From 02e42de819e5d6beeeaad12b93c7075efe69d1e0 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 29 Oct 2008 01:17:37 +0000 Subject: [PATCH] Added testsuite, as one project for now. Will move individual tests to respective modules later git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@173 50f2f4bb-b051-0410-bef5-90022cba6387 --- org.springframework.testsuite/build.xml | 6 + org.springframework.testsuite/ivy.xml | 81 + org.springframework.testsuite/pom.xml | 59 + .../aop/SimpleBeforeAdvice.java | 28 + .../aop/SimpleBeforeAdviceAdapter.java | 40 + .../aop/SimpleBeforeAdviceImpl.java | 34 + .../aop/SimpleBeforeAdviceInterceptor.java | 38 + .../aspectj/AbstractAdviceBindingTests.java | 47 + .../aop/aspectj/AdviceBindingTestAspect.java | 69 + .../aop/aspectj/AfterAdviceBindingTests.java | 96 + ...AfterReturningAdviceBindingTestAspect.java | 67 + .../AfterReturningAdviceBindingTests.java | 169 ++ .../AfterThrowingAdviceBindingTestAspect.java | 60 + .../AfterThrowingAdviceBindingTests.java | 147 + .../AroundAdviceBindingTestAspect.java | 71 + .../aop/aspectj/AroundAdviceBindingTests.java | 81 + .../aspectj/AroundAdviceCircularTests.java | 37 + .../AspectAndAdvicePrecedenceTests.java | 140 + ...ctJAdviceParameterNameDiscovererTests.java | 298 ++ ...AspectJExpressionPointcutAdvisorTests.java | 58 + .../AspectJExpressionPointcutTests.java | 332 +++ .../aop/aspectj/AuthenticationLogger.java | 37 + .../aop/aspectj/BeanNameAwareMixin.java | 37 + .../BeanNamePointcutMatchingTests.java | 94 + .../aop/aspectj/BeanNamePointcutTests.java | 119 + .../aop/aspectj/BeforeAdviceBindingTests.java | 90 + .../aop/aspectj/CallCountingInterceptor.java | 26 + .../springframework/aop/aspectj/Counter.java | 50 + .../DeclarationOrderIndependenceTests.java | 110 + .../DeclareParentsDelegateRefTests.java | 77 + .../aop/aspectj/DeclareParentsTests.java | 60 + .../springframework/aop/aspectj/ICounter.java | 34 + .../ImplicitJPArgumentMatchingTests.java | 50 + ...hodInvocationProceedingJoinPointTests.java | 180 ++ .../aop/aspectj/NonAnnotatedMakeLockable.java | 32 + .../aspectj/OverloadedAdviceTestAspect.java | 32 + .../aop/aspectj/OverloadedAdviceTests.java | 55 + .../aop/aspectj/PrecedenceTestAspect.java | 103 + .../aop/aspectj/ProceedTests.java | 214 ++ .../aop/aspectj/SerializableMixin.java | 28 + .../SharedPointcutWithArgsMismatch.java | 64 + .../aop/aspectj/SimpleSpringBeforeAdvice.java | 55 + .../aspectj/SubtypeMatchingTestClasses.java | 45 + .../SubtypeSensitiveMatchingTests.java | 66 + .../aspectj/TargetPointcutSelectionTests.java | 111 + ...sAndTargetSelectionOnlyPointcutsTests.java | 99 + .../aop/aspectj/TopsyTurvyAspect.java | 53 + .../aop/aspectj/TopsyTurvyTarget.java | 30 + .../aop/aspectj/TopsyTurvyTargetImpl.java | 42 + .../aspectj/TypePatternClassFilterTests.java | 93 + .../aop/aspectj/advice-precedence-tests.xml | 90 + .../aop/aspectj/after-advice-tests.xml | 24 + .../aspectj/afterReturning-advice-tests.xml | 35 + .../aspectj/afterThrowing-advice-tests.xml | 42 + .../aop/aspectj/ambiguous-advice-tests.xml | 20 + .../aop/aspectj/args-mismatch.xml | 20 + .../aspectj/around-advice-circular-tests.xml | 28 + .../aop/aspectj/around-advice-tests.xml | 22 + .../springframework/aop/aspectj/aspectj.xml | 18 + .../AspectImplementingInterfaceTests.java | 62 + .../AspectJPrecedenceComparatorTests.java | 223 ++ .../aspect-implementing-interface-tests.xml | 20 + .../aop/aspectj/bean-name-pointcut-tests.xml | 62 + .../aop/aspectj/before-advice-tests.xml | 33 + .../declare-parents-delegate-ref-tests.xml | 22 + .../aop/aspectj/declare-parents-tests.xml | 27 + .../implicit-jp-argument-matching-tests.xml | 22 + .../aop/aspectj/overloaded-advice-tests.xml | 21 + .../aop/aspectj/proceedTests.xml | 32 + .../aspectj/subtype-sensitive-matching.xml | 31 + .../aspectj/targetPointcutSelectionTests.xml | 35 + ...d-target-selectionOnly-pointcuts-tests.xml | 64 + .../aop/aspectj/topsy-turvy-aspect.xml | 32 + .../config/AopNamespaceAdviceTypeTests.java | 61 + .../AopNamespaceHandlerArgNamesTests.java | 59 + .../config/AopNamespaceHandlerEventTests.java | 181 ++ ...AopNamespaceHandlerPointcutErrorTests.java | 53 + ...NamespaceHandlerProxyTargetClassTests.java | 36 + .../AopNamespaceHandlerReturningTests.java | 60 + .../config/AopNamespaceHandlerScopeTests.java | 106 + .../aop/config/AopNamespaceHandlerTests.java | 98 + .../AopNamespaceHandlerThrowingTests.java | 60 + .../aop/config/CountingAspectJAdvice.java | 69 + .../MethodLocatingFactoryBeanTests.java | 183 ++ .../aop/config/PrototypeProxyTests.java | 32 + .../aop/config/TopLevelAopTagTests.java | 39 + ...opNamespaceHandlerAdviceTypeErrorTests.xml | 26 + .../aopNamespaceHandlerAdviceTypeOKTests.xml | 27 + ...lerAdvisorWithDirectPointcutEventTests.xml | 14 + ...andlerAdvisorWithPointcutRefEventTests.xml | 15 + .../aopNamespaceHandlerArgNamesErrorTests.xml | 23 + .../aopNamespaceHandlerArgNamesOKTests.xml | 23 + .../aopNamespaceHandlerAspectEventTests.xml | 27 + ...mespaceHandlerPointcutDuplicationTests.xml | 21 + .../aopNamespaceHandlerPointcutEventTests.xml | 12 + ...opNamespaceHandlerPointcutMissingTests.xml | 21 + ...pNamespaceHandlerProxyTargetClassTests.xml | 30 + ...aopNamespaceHandlerReturningErrorTests.xml | 22 + .../aopNamespaceHandlerReturningOKTests.xml | 22 + .../config/aopNamespaceHandlerScopeTests.xml | 26 + .../aop/config/aopNamespaceHandlerTests.xml | 30 + .../aopNamespaceHandlerThrowingErrorTests.xml | 22 + .../aopNamespaceHandlerThrowingOKTests.xml | 22 + .../aop/config/prototypeProxy.xml | 27 + .../aop/config/topLevelAop.xml | 12 + .../aop/framework/AbstractAopProxyTests.java | 1838 ++++++++++++ .../aop/framework/AopProxyUtilsTests.java | 134 + .../aop/framework/CglibProxyTests.java | 411 +++ .../aop/framework/CglibTestBean.java | 37 + .../CountingAfterReturningAdvice.java | 34 + .../aop/framework/CountingBeforeAdvice.java | 34 + .../aop/framework/CountingMultiAdvice.java | 53 + .../aop/framework/CountingThrowsAdvice.java | 37 + .../aop/framework/DefaultLockable.java | 40 + .../framework/ExposedInvocationTestBean.java | 43 + .../framework/IntroductionBenchmarkTests.java | 87 + ...ocationCheckExposedInvocationTestBean.java | 34 + .../aop/framework/JdkDynamicProxyTests.java | 212 ++ .../aop/framework/LockMixin.java | 64 + .../aop/framework/LockMixinAdvisor.java | 32 + .../aop/framework/Lockable.java | 33 + .../aop/framework/LockedException.java | 24 + .../aop/framework/MethodCounter.java | 68 + .../aop/framework/MethodInvocationTests.java | 110 + .../aop/framework/MethodVisibilities.java | 38 + .../aop/framework/MockTargetSource.java | 82 + .../aop/framework/NoArgCtorTestBean.java | 38 + .../aop/framework/NoInterfaces.java | 34 + .../framework/NoInterfacesConstructor.java | 29 + .../framework/ProtectedMethodTestBean.java | 28 + .../aop/framework/PrototypeTargetTests.java | 86 + .../aop/framework/ProxyFactoryBeanTests.java | 722 +++++ .../aop/framework/ProxyFactoryTests.java | 292 ++ .../aop/framework/TimeStamped.java | 34 + .../TimestampIntroductionAdvisor.java | 35 + .../TimestampIntroductionInterceptor.java | 41 + .../aop/framework/UnsupportedInterceptor.java | 35 + .../AdvisorAdapterRegistrationTests.java | 81 + .../adapter/ThrowsAdviceInterceptorTests.java | 197 ++ .../aop/framework/adapter/withBPPContext.xml | 23 + .../framework/adapter/withoutBPPContext.xml | 21 + .../AdvisorAutoProxyCreatorTests.java | 343 +++ .../autoproxy/AutoProxyCreatorTests.java | 308 ++ .../BeanNameAutoProxyCreatorInitTests.java | 45 + .../BeanNameAutoProxyCreatorTests.java | 185 ++ .../framework/autoproxy/CountingTestBean.java | 37 + .../framework/autoproxy/CreatesTestBean.java | 49 + .../autoproxy/NeverMatchAdvisor.java | 52 + .../aop/framework/autoproxy/NoSetters.java | 33 + .../aop/framework/autoproxy/NullChecker.java | 40 + .../autoproxy/OrderedTxCheckAdvisor.java | 87 + .../aop/framework/autoproxy/Rollback.java | 57 + ...SelectivePrototypeTargetSourceCreator.java | 39 + .../autoproxy/advisorAutoProxyCreator.xml | 107 + ...AutoProxyCreatorWithCommonInterceptors.xml | 47 + .../beanNameAutoProxyCreatorInitTests.xml | 29 + .../beanNameAutoProxyCreatorTests.xml | 115 + .../autoproxy/customTargetSource.xml | 34 + .../autoproxy/optimizedAutoProxyCreator.xml | 24 + .../framework/autoproxy/quickTargetSource.xml | 44 + .../aop/framework/frozenProxyFactoryBean.xml | 28 + .../aop/framework/innerBeanTarget.xml | 39 + .../aop/framework/invalidProxyFactory.xml | 21 + .../aop/framework/prototypeTarget.xml | 42 + .../aop/framework/prototypeTests.xml | 37 + .../proxyFactoryBeanAutowiringTests.xml | 16 + .../proxyFactoryDoubleTargetSourceTests.xml | 54 + .../proxyFactoryTargetSourceNotLastTests.xml | 34 + .../proxyFactoryTargetSourceTests.xml | 58 + .../aop/framework/proxyFactoryTests.xml | 171 ++ .../aop/framework/serializationTests.xml | 40 + .../aop/framework/throwsAdvice.xml | 37 + .../aop/framework/withDependencyChecking.xml | 13 + .../ConcurrencyThrottleInterceptorTests.java | 153 + .../CustomizableTraceInterceptorTests.java | 224 ++ .../interceptor/DebugInterceptorTests.java | 114 + .../ExposeBeanNameAdvisorsTests.java | 75 + .../ExposeInvocationInterceptorTests.java | 39 + .../aop/interceptor/NopInterceptor.java | 58 + .../PerformanceMonitorInterceptorTests.java | 104 + .../SerializableNopInterceptor.java | 45 + .../aop/interceptor/SideEffectBean.java | 40 + .../SimpleTraceInterceptorTests.java | 101 + .../aop/interceptor/exposeInvocation.xml | 29 + .../aop/scope/DefaultScopedObjectTests.java | 69 + .../aop/scope/ScopedProxyAutowireTests.java | 57 + .../aop/scope/ScopedProxyTests.java | 100 + .../aop/scope/scopedAutowireFalse.xml | 16 + .../aop/scope/scopedAutowireTrue.xml | 16 + .../springframework/aop/scope/scopedList.xml | 16 + .../springframework/aop/scope/scopedMap.xml | 22 + .../aop/scope/scopedOverride.xml | 21 + .../aop/scope/scopedTestBean.xml | 13 + .../AbstractRegexpMethodPointcutTests.java | 101 + .../aop/support/AopUtilsTests.java | 82 + .../aop/support/ClassFiltersTests.java | 57 + .../aop/support/ComposablePointcutTests.java | 145 + .../aop/support/ControlFlowPointcutTests.java | 114 + ...elegatingIntroductionInterceptorTests.java | 318 ++ .../support/JdkRegexpMethodPointcutTests.java | 28 + .../aop/support/MethodMatchersTests.java | 120 + .../support/NameMatchMethodPointcutTests.java | 132 + .../aop/support/PointcutsTests.java | 239 ++ ...MethodPointcutAdvisorIntegrationTests.java | 108 + .../aop/support/regexpSetterTests.xml | 58 + .../CommonsPoolTargetSourceProxyTests.java | 41 + .../target/CommonsPoolTargetSourceTests.java | 201 ++ .../target/HotSwappableTargetSourceTests.java | 154 + .../target/LazyCreationTargetSourceTests.java | 69 + .../aop/target/LazyInitTargetSourceTests.java | 77 + .../PrototypeBasedTargetSourceTests.java | 76 + .../target/PrototypeTargetSourceTests.java | 58 + .../target/ThreadLocalTargetSourceTests.java | 146 + .../aop/target/commonsPoolProxyTests.xml | 16 + .../aop/target/commonsPoolTests.xml | 69 + .../aop/target/customLazyInitTarget.xml | 21 + .../dynamic/RefreshableTargetSourceTests.java | 126 + .../aop/target/hotSwapTests.xml | 27 + .../aop/target/lazyInitFactoryBean.xml | 47 + .../aop/target/lazyInitSingletonTests.xml | 21 + .../aop/target/prototypeTests.xml | 33 + .../aop/target/threadLocalTests.xml | 55 + .../beans/AbstractPropertyValuesTests.java | 54 + .../springframework/beans/BeanUtilsTests.java | 309 ++ .../beans/BeanWithObjectProperty.java | 35 + .../beans/BeanWrapperTests.java | 1711 +++++++++++ .../beans/BooleanTestBean.java | 45 + .../CachedIntrospectionResultsTests.java | 48 + .../org/springframework/beans/Colour.java | 35 + .../beans/ConcurrentBeanWrapperTests.java | 145 + .../beans/DerivedTestBean.java | 85 + .../org/springframework/beans/Employee.java | 39 + .../beans/FieldAccessBean.java | 44 + .../beans/INestedTestBean.java | 23 + .../org/springframework/beans/IOther.java | 24 + .../org/springframework/beans/ITestBean.java | 71 + .../beans/IndexedTestBean.java | 145 + .../beans/MutablePropertyValuesTests.java | 97 + .../springframework/beans/NestedTestBean.java | 60 + .../springframework/beans/NumberTestBean.java | 143 + .../org/springframework/beans/Person.java | 36 + .../java/org/springframework/beans/Pet.java | 54 + .../beans/PropertyAccessorUtilsTests.java | 51 + .../beans/ResourceTestBean.java | 41 + .../beans/SerializablePerson.java | 64 + .../org/springframework/beans/TestBean.java | 437 +++ .../factory/AbstractBeanFactoryTests.java | 328 +++ .../AbstractListableBeanFactoryTests.java | 84 + .../beans/factory/BeanFactoryUtilsTests.java | 273 ++ .../factory/ConcurrentBeanFactoryTests.java | 149 + .../beans/factory/CountingFactory.java | 64 + .../DefaultListableBeanFactoryTests.java | 2239 ++++++++++++++ .../beans/factory/DummyFactory.java | 172 ++ .../beans/factory/FactoryBeanTests.java | 149 + .../springframework/beans/factory/HasMap.java | 94 + .../beans/factory/KnowsIfInstantiated.java | 35 + .../beans/factory/LifecycleBean.java | 158 + .../beans/factory/MustBeInitialized.java | 44 + .../factory/PackageLevelVisibleBean.java | 28 + .../factory/SharedBeanRegistryTests.java | 80 + .../SingletonBeanFactoryLocatorTests.java | 186 ++ .../beans/factory/access/TestBean.java | 75 + .../beans/factory/access/beans1.xml | 16 + .../beans/factory/access/beans2.xml | 16 + .../beans/factory/access/ref1.xml | 28 + .../beans/factory/concurrent.xml | 16 + .../config/BeanFactoryPostProcessorTests.java | 96 + .../config/CommonsLogFactoryBeanTests.java | 59 + .../config/CustomEditorConfigurerTests.java | 171 ++ .../config/CustomScopeConfigurerTests.java | 155 + .../FieldRetrievingFactoryBeanTests.java | 123 + .../MethodInvokingFactoryBeanTests.java | 339 +++ .../beans/factory/config/NoOpScope.java | 41 + ...ObjectFactoryCreatingFactoryBeanTests.java | 127 + .../ObjectFactoryCreatingFactoryBeanTests.xml | 19 + .../config/PropertiesFactoryBeanTests.java | 135 + .../config/PropertyPathFactoryBeanTests.java | 78 + .../PropertyResourceConfigurerTests.java | 715 +++++ .../ServiceLocatorFactoryBeanTests.java | 346 +++ .../beans/factory/config/SimpleMapScope.java | 78 + .../factory/config/SimpleScopeTests.java | 76 + .../beans/factory/config/fieldRetrieving.xml | 15 + .../beans/factory/config/propertyPath.xml | 62 + .../beans/factory/config/simpleScope.xml | 10 + .../beans/factory/config/test-properties.xml | 9 + .../beans/factory/config/test.properties | 2 + .../beans/factory/config/util.properties | 1 + .../beans/factory/dependentBeans.xml | 40 + .../beans/factory/factoryBeanReturnsNull.xml | 8 + .../factory/factoryBeansWithAutowiring.xml | 41 + .../springframework/beans/factory/leaf.xml | 13 + .../springframework/beans/factory/middle.xml | 20 + .../CollectingReaderEventListener.java | 86 + .../ConstructorArgumentEntryTests.java | 37 + .../parsing/CustomProblemReporterTests.java | 88 + .../parsing/FailFastProblemReporterTests.java | 68 + .../parsing/NullSourceExtractorTests.java | 37 + .../factory/parsing/ParseStateTests.java | 74 + .../PassThroughSourceExtractorTests.java | 37 + .../factory/parsing/PropertyEntryTests.java | 37 + .../beans/factory/parsing/withErrors.xml | 30 + .../springframework/beans/factory/root.xml | 25 + .../support/BeanDefinitionBuilderTests.java | 69 + .../factory/support/BeanDefinitionTests.java | 134 + ...DefinitionMetadataEqualsHashCodeTests.java | 95 + .../factory/support/ManagedListTests.java | 91 + .../factory/support/ManagedMapTests.java | 90 + .../support/ManagedPropertiesTests.java | 90 + .../factory/support/ManagedSetTests.java | 91 + .../PropertiesBeanDefinitionReaderTests.java | 56 + .../support/multiConstructorArgs.properties | 3 + .../support/refConstructorArg.properties | 5 + .../support/simpleConstructorArg.properties | 2 + .../wiring/BeanConfigurerSupportTests.java | 136 + .../factory/wiring/BeanWiringInfoTests.java | 93 + .../ClassNameBeanWiringInfoResolverTests.java | 46 + .../xml/AutowireWithExclusionTests.java | 142 + .../factory/xml/BeanNameGenerationTests.java | 62 + .../factory/xml/CollectionMergingTests.java | 183 ++ .../xml/CollectionsWithDefaultTypesTests.java | 59 + .../xml/ConstructorDependenciesBean.java | 99 + .../xml/ConstructorInjectedOverrides.java | 58 + .../xml/DefaultLifecycleMethodsTests.java | 114 + .../xml/DelegatingEntityResolverTests.java | 64 + .../beans/factory/xml/DependenciesBean.java | 72 + .../DerivedConstructorDependenciesBean.java | 59 + .../beans/factory/xml/DummyBo.java | 27 + .../beans/factory/xml/DummyBoImpl.java | 35 + .../beans/factory/xml/DummyDao.java | 33 + .../beans/factory/xml/DummyReferencer.java | 66 + .../factory/xml/EventPublicationTests.java | 115 + .../beans/factory/xml/FactoryMethodTests.java | 325 +++ .../beans/factory/xml/FactoryMethods.java | 120 + .../factory/xml/FixedMethodReplacer.java | 35 + .../beans/factory/xml/GeneratedNameBean.java | 46 + .../beans/factory/xml/InstanceFactory.java | 62 + .../LookupMethodWrappedByCglibProxyTests.java | 81 + .../factory/xml/MetadataAttachmentTests.java | 53 + .../factory/xml/MethodReplaceCandidate.java | 29 + .../factory/xml/MixedCollectionBean.java | 41 + .../beans/factory/xml/OverrideInterface.java | 30 + .../beans/factory/xml/OverrideOneMethod.java | 56 + .../xml/OverrideOneMethodSubclass.java | 32 + .../factory/xml/ProtectedLifecycleBean.java | 162 ++ .../factory/xml/ReverseMethodReplacer.java | 23 + .../factory/xml/SchemaValidationTests.java | 68 + .../SerializableMethodReplacerCandidate.java | 28 + .../beans/factory/xml/ShortcutTests.java | 66 + .../xml/SingleSimpleTypeConstructorBean.java | 52 + .../beans/factory/xml/TestBeanCreator.java | 43 + .../xml/UtilNamespaceHandlerTests.java | 310 ++ .../factory/xml/XmlBeanCollectionTests.java | 413 +++ .../xml/XmlBeanDefinitionReaderTests.java | 142 + .../factory/xml/XmlBeanFactoryTests.java | 1549 ++++++++++ .../xml/XmlListableBeanFactoryTests.java | 226 ++ .../autowire-constructor-with-exclusion.xml | 22 + .../factory/xml/autowire-with-exclusion.xml | 26 + .../factory/xml/autowire-with-inclusion.xml | 27 + .../xml/autowire-with-selective-inclusion.xml | 33 + .../beans/factory/xml/autowire.xml | 64 + .../beans/factory/xml/beanEvents.xml | 34 + .../beans/factory/xml/beanEventsImported.xml | 6 + .../beans/factory/xml/beanNameGeneration.xml | 18 + .../beans/factory/xml/child.xml | 51 + .../beans/factory/xml/classNotFound.xml | 8 + .../beans/factory/xml/collectionMerging.xml | 205 ++ .../beans/factory/xml/collections.xml | 376 +++ .../xml/collectionsWithDefaultTypes.xml | 61 + .../factory/xml/complexFactoryCircle.xml | 49 + .../beans/factory/xml/constructor-arg.xml | 166 ++ .../factory/xml/constructorOverrides.xml | 34 + .../beans/factory/xml/default-autowire.xml | 24 + .../beans/factory/xml/default-lazy-init.xml | 20 + .../factory/xml/defaultLifecycleMethods.xml | 14 + .../beans/factory/xml/delegationOverrides.xml | 83 + .../xml/dependencies-carg-autowire.xml | 16 + .../factory/xml/dependencies-carg-inner.xml | 19 + .../beans/factory/xml/dependencies-carg.xml | 21 + .../xml/dependencies-dependsOn-inner.xml | 38 + .../factory/xml/dependencies-dependsOn.xml | 13 + .../xml/dependencies-prop-autowireByName.xml | 19 + .../xml/dependencies-prop-autowireByType.xml | 16 + .../xml/dependencies-prop-inTheMiddle.xml | 19 + .../factory/xml/dependencies-prop-inner.xml | 19 + .../beans/factory/xml/dependencies-prop.xml | 15 + .../xml/dependenciesMaterializeThis.xml | 34 + .../beans/factory/xml/factory-methods.xml | 145 + .../beans/factory/xml/factoryCircle.xml | 10 + .../xml/ignoreDefaultLifecycleMethods.xml | 8 + .../beans/factory/xml/initializers.xml | 23 + .../beans/factory/xml/invalid-factory.xml | 10 + .../beans/factory/xml/invalid.xml | 20 + .../xml/invalidOverridesNoSuchMethod.xml | 24 + .../beans/factory/xml/invalidPerSchema.xml | 8 + .../xml/local-collections-using-XSD.xml | 36 + .../factory/xml/no-such-factory-method.xml | 17 + .../beans/factory/xml/overloadOverrides.xml | 39 + .../beans/factory/xml/overrides.xml | 84 + .../beans/factory/xml/parent.xml | 23 + .../beans/factory/xml/recursiveImport.xml | 8 + .../beans/factory/xml/reftypes.xml | 186 ++ .../beans/factory/xml/resource.xml | 17 + .../beans/factory/xml/resourceImport.xml | 15 + .../xml/satisfiedAllDependencyCheck.xml | 17 + .../xml/satisfiedObjectDependencyCheck.xml | 13 + .../xml/satisfiedSimpleDependencyCheck.xml | 13 + .../beans/factory/xml/schemaValidated.xml | 20 + .../beans/factory/xml/shortcutTests.xml | 27 + .../factory/xml/shortcutWithErrorsTests.xml | 17 + .../support/CustomNamespaceHandlerTests.java | 155 + .../DefaultNamespaceHandlerResolverTests.java | 87 + .../xml/support/TestNamespaceHandler.java | 119 + .../xml/support/customNamespace.properties | 2 + .../factory/xml/support/customNamespace.xml | 50 + .../factory/xml/support/invalid.properties | 1 + .../xml/support/nonExistent.properties | 1 + .../beans/factory/xml/support/spring-test.xsd | 36 + .../beans/factory/xml/test.properties | 1 + .../beans/factory/xml/test.xml | 127 + .../beans/factory/xml/testUtilNamespace.xml | 184 ++ .../xml/testWithDuplicateNameInAlias.xml | 10 + .../factory/xml/testWithDuplicateNames.xml | 10 + ...isfiedAllDependencyCheckMissingObjects.xml | 14 + ...tisfiedAllDependencyCheckMissingSimple.xml | 16 + .../xml/unsatisfiedObjectDependencyCheck.xml | 11 + .../xml/unsatisfiedSimpleDependencyCheck.xml | 11 + .../beans/factory/xml/validateWithDtd.xml | 13 + .../beans/factory/xml/validateWithXsd.xml | 11 + .../beans/factory/xml/withMeta.xml | 21 + .../beans/propertyeditors/BeanInfoTests.java | 108 + .../ByteArrayPropertyEditorTests.java | 54 + .../CharArrayPropertyEditorTests.java | 54 + .../CustomCollectionEditorTests.java | 98 + .../propertyeditors/CustomEditorTests.java | 1492 ++++++++++ .../propertyeditors/FileEditorTests.java | 86 + .../InputStreamEditorTests.java | 76 + .../PropertiesEditorTests.java | 159 + .../ResourceBundleEditorTests.java | 126 + .../ResourceBundleEditorTests.properties | 1 + ...angCountryDialect_en_GB_GLASGOW.properties | 1 + ...dleEditorTestsLangCountry_en_GB.properties | 1 + ...esourceBundleEditorTestsLang_en.properties | 1 + .../StringArrayPropertyEditorTests.java | 78 + .../beans/propertyeditors/URIEditorTests.java | 111 + .../beans/propertyeditors/URLEditorTests.java | 90 + .../support/DerivedFromProtectedBaseBean.java | 25 + .../beans/support/PagedListHolderTests.java | 219 ++ .../beans/support/ProtectedBaseBean.java | 35 + .../cache/ehcache/EhCacheSupportTests.java | 222 ++ .../cache/ehcache/testEhcache.xml | 50 + .../springframework/context/ACATester.java | 48 + .../AbstractApplicationContextTests.java | 157 + .../context/BeanThatBroadcasts.java | 36 + .../context/BeanThatListens.java | 61 + .../context/LifecycleContextBean.java | 52 + .../springframework/context/TestListener.java | 41 + .../ContextBeanFactoryReferenceTests.java | 52 + .../ContextJndiBeanFactoryLocatorTests.java | 115 + ...ntextSingletonBeanFactoryLocatorTests.java | 86 + .../access/DefaultLocatorFactoryTests.java | 45 + .../config/ContextNamespaceHandlerTests.java | 53 + .../config/contextNamespaceHandlerTests.xml | 27 + .../event/ApplicationContextEventTests.java | 208 ++ .../EventPublicationInterceptorTests.java | 153 + .../context/event/LifecycleEventTests.java | 116 + .../ApplicationContextLifecycleTests.java | 97 + .../context/support/Assembler.java | 48 + .../context/support/AutowiredService.java | 39 + .../ClassPathXmlApplicationContextTests.java | 371 +++ .../FactoryBeanAndApplicationListener.java | 28 + .../context/support/LifecycleTestBean.java | 60 + .../context/support/Logic.java | 45 + .../ResourceBundleMessageSourceTests.java | 270 ++ .../support/ResourceMapFactoryBeanTests.java | 75 + .../context/support/Service.java | 95 + ...ticApplicationContextMulticasterTests.java | 97 + .../StaticApplicationContextTests.java | 73 + .../support/StaticMessageSourceTests.java | 262 ++ .../context/support/TestIF.java | 21 + .../context/support/aliasForParent.xml | 8 + .../support/aliasThatOverridesParent.xml | 10 + .../context/support/childWithProxy.xml | 28 + .../context/support/classWithPlaceholder.xml | 17 + .../context/support/invalidClass.xml | 8 + .../context/support/invalidValueType.xml | 11 + .../context/support/lifecycleTests.xml | 19 + .../context/support/messages.properties | 5 + .../context/support/messages_de.properties | 1 + .../context/support/messages_de_AT.properties | 1 + .../support/messages_de_AT_oo.properties | 1 + .../context/support/messages_de_DE.xml | 8 + .../context/support/more-messages.properties | 1 + .../context/support/override.properties | 2 + .../context/support/placeholder.properties | 3 + .../context/support/simpleContext.xml | 13 + .../context/support/test.properties | 1 + .../context/support/test/aliased-contextC.xml | 19 + .../context/support/test/contextA.xml | 54 + .../context/support/test/contextB.xml | 11 + .../context/support/test/contextC.xml | 17 + .../context/support/test/import1.xml | 15 + .../context/support/test/subtest/import2.xml | 15 + .../context/support/testBeans.properties | 42 + .../core/AbstractControlFlowTests.java | 90 + .../core/AttributeAccessorSupportTests.java | 69 + .../core/CollectionFactoryTests.java | 61 + .../springframework/core/ConstantsTests.java | 253 ++ .../core/ConventionsTests.java | 74 + .../core/DefaultControlFlowTests.java | 37 + .../core/Jdk14ControlFlowTests.java | 37 + ...ableTableParameterNameDiscovererTests.java | 201 ++ .../core/NestedExceptionTests.java | 104 + .../core/OrderComparatorTests.java | 72 + ...ioritizedParameterNameDiscovererTests.java | 84 + .../core/enums/LabeledEnumTests.java | 183 ++ .../enums/StandAloneStaticLabeledEnum.java | 36 + .../core/io/ResourceEditorTests.java | 59 + .../core/io/ResourceTests.java | 224 ++ ...hMatchingResourcePatternResolverTests.java | 153 + .../core/style/ToStringCreatorTests.java | 125 + .../core/task/MockRunnable.java | 34 + .../core/task/NoOpRunnable.java | 30 + .../task/SimpleAsyncTaskExecutorTests.java | 132 + .../core/task/StubTaskExecutor.java | 27 + ...edPersistenceExceptionTranslatorTests.java | 72 + .../dao/support/DataAccessUtilsTests.java | 278 ++ .../jca/StubActivationSpec.java | 39 + .../jca/StubResourceAdapter.java | 48 + .../jca/cci/CciLocalTransactionTests.java | 187 ++ .../jca/cci/CciTemplateTests.java | 987 +++++++ .../jca/cci/EisOperationTests.java | 338 +++ .../LocalConnectionFactoryBeanTests.java | 92 + .../jdbc/AbstractJdbcTests.java | 85 + .../org/springframework/jdbc/Customer.java | 50 + .../jdbc/core/AbstractRowMapperTests.java | 145 + .../jdbc/core/BeanPropertyRowMapperTests.java | 92 + .../jdbc/core/JdbcTemplateQueryTests.java | 983 +++++++ .../jdbc/core/JdbcTemplateTests.java | 2057 +++++++++++++ .../jdbc/core/RowMapperTests.java | 248 ++ .../core/SimpleRowCountCallbackHandler.java | 42 + .../jdbc/core/StatementCreatorUtilsTests.java | 223 ++ .../BeanPropertySqlParameterSourceTests.java | 95 + .../MapSqlParameterSourceTests.java | 50 + .../NamedParameterJdbcTemplateTests.java | 415 +++ .../namedparam/NamedParameterQueryTests.java | 608 ++++ .../namedparam/NamedParameterUtilsTests.java | 189 ++ .../JdbcBeanDefinitionReaderTests.java | 87 + .../core/support/JdbcDaoSupportTests.java | 65 + .../jdbc/core/support/LobSupportTests.java | 169 ++ .../jdbc/core/support/SqlLobValueTests.java | 274 ++ .../jdbc/core/test/AbstractPerson.java | 57 + .../jdbc/core/test/ConcretePerson.java | 37 + .../jdbc/core/test/ExtendedPerson.java | 35 + .../jdbc/core/test/Person.java | 67 + .../DataSourceJtaTransactionTests.java | 901 ++++++ .../DataSourceTransactionManagerTests.java | 1990 +++++++++++++ .../DriverManagerDataSourceTests.java | 160 + ...UserCredentialsDataSourceAdapterTests.java | 87 + .../BeanFactoryDataSourceLookupTests.java | 84 + .../lookup/JndiDataSourceLookupTests.java | 61 + .../lookup/MapDataSourceLookupTests.java | 103 + .../datasource/lookup/StubDataSource.java | 41 + .../jdbc/object/BatchSqlUpdateTests.java | 129 + .../jdbc/object/RdbmsOperationTests.java | 220 ++ .../jdbc/object/SqlFunctionTests.java | 339 +++ .../jdbc/object/SqlQueryTests.java | 1160 ++++++++ .../jdbc/object/SqlUpdateTests.java | 585 ++++ .../jdbc/object/StoredProcedureTests.java | 1005 +++++++ .../support/CustomErrorCodeException.java | 34 + .../DataFieldMaxValueIncrementerTests.java | 253 ++ .../jdbc/support/DefaultLobHandlerTests.java | 161 + .../jdbc/support/JdbcUtilsTests.java | 43 + .../jdbc/support/KeyHolderTests.java | 112 + .../support/NativeJdbcExtractorTests.java | 144 + ...LErrorCodeSQLExceptionTranslatorTests.java | 153 + .../support/SQLErrorCodesFactoryTests.java | 324 +++ .../support/SQLExceptionSubclassFactory.java | 78 + .../SQLExceptionSubclassTranslatorTests.java | 112 + .../SQLStateExceptionTranslatorTests.java | 95 + .../SQLStateSQLExceptionTranslatorTests.java | 88 + .../jdbc/support/custom-error-codes.xml | 24 + .../rowset/ResultSetWrappingRowSetTests.java | 223 ++ .../jdbc/support/test-error-codes.xml | 14 + .../jdbc/support/wildcard-error-codes.xml | 38 + .../jms/StubConnectionFactory.java | 38 + .../org/springframework/jms/StubQueue.java | 46 + .../org/springframework/jms/StubTopic.java | 46 + .../jms/config/JmsNamespaceHandlerTests.java | 247 ++ .../jms/config/jmsNamespaceHandlerTests.xml | 55 + .../JmsTransactionManagerTests.java | 505 ++++ .../SingleConnectionFactoryTests.java | 651 +++++ .../jms/connection/TestConnection.java | 92 + .../jms/connection/TestExceptionListener.java | 37 + .../jms/core/JmsTemplate102JtaTests.java | 33 + .../jms/core/JmsTemplate102Tests.java | 1166 ++++++++ .../core/JmsTemplate102TransactedTests.java | 33 + .../jms/core/JmsTemplateJtaTests.java | 33 + .../jms/core/JmsTemplateTests.java | 847 ++++++ .../jms/core/JmsTemplateTransactedTests.java | 33 + .../core/support/JmsGatewaySupportTests.java | 66 + ...AbstractMessageListenerContainerTests.java | 49 + .../SimpleMessageListenerContainerTests.java | 607 ++++ .../adapter/MessageContentsDelegate.java | 39 + .../jms/listener/adapter/MessageDelegate.java | 39 + .../MessageListenerAdapter102Tests.java | 432 +++ .../adapter/MessageListenerAdapterTests.java | 657 +++++ ...msTextMessageReturningMessageDelegate.java | 36 + .../adapter/ResponsiveMessageDelegate.java | 42 + .../adapter/StubMessageListenerAdapter.java | 42 + .../StubMessageListenerAdapter102.java | 42 + .../DefaultJmsActivationSpecFactoryTests.java | 168 ++ .../endpoint/StubJmsActivationSpec.java | 94 + .../StubJmsActivationSpecFactory.java | 33 + .../jms/remoting/JmsInvokerTests.java | 414 +++ .../jms/support/JmsAccessorTests.java | 72 + .../SimpleMessageConverter102Tests.java | 76 + .../support/SimpleMessageConverterTests.java | 259 ++ .../DynamicDestinationResolverTests.java | 108 + .../JmsDestinationAccessorTests.java | 61 + .../JndiDestinationResolverTests.java | 156 + .../springframework/jmx/AbstractJmxTests.java | 51 + .../jmx/AbstractMBeanServerTests.java | 83 + .../org/springframework/jmx/IJmxTestBean.java | 40 + .../org/springframework/jmx/JmxTestBean.java | 143 + ...sAttributesMBeanProxyFactoryBeanTests.java | 94 + .../access/MBeanClientInterceptorTests.java | 313 ++ .../RemoteMBeanClientInterceptorTests.java | 69 + .../jmx/access/proxyFactoryBean.xml | 45 + .../jmx/applicationContext.xml | 25 + .../export/CustomEditorConfigurerTests.java | 66 + .../springframework/jmx/export/DateRange.java | 46 + .../jmx/export/ExceptionOnInitBean.java | 46 + .../jmx/export/LazyInitMBeanTests.java | 57 + .../export/MBeanExporterOperationsTests.java | 119 + .../jmx/export/MBeanExporterTests.java | 760 +++++ .../jmx/export/NotificationListenerTests.java | 482 +++ .../export/NotificationPublisherTests.java | 206 ++ .../PropertyPlaceholderConfigurerTests.java | 50 + .../jmx/export/TestDynamicMBean.java | 80 + .../assembler/AbstractAutodetectTests.java | 37 + .../assembler/AbstractJmxAssemblerTests.java | 198 ++ ...tractMetadataAssemblerAutodetectTests.java | 34 + .../AbstractMetadataAssemblerTests.java | 189 ++ .../assembler/IAdditionalTestMethods.java | 13 + .../jmx/export/assembler/ICustomBase.java | 28 + .../jmx/export/assembler/ICustomJmxBean.java | 30 + ...aceBasedMBeanInfoAssemblerCustomTests.java | 59 + ...aceBasedMBeanInfoAssemblerMappedTests.java | 119 + ...InterfaceBasedMBeanInfoAssemblerTests.java | 44 + ...ExclusionMBeanInfoAssemblerComboTests.java | 73 + ...xclusionMBeanInfoAssemblerMappedTests.java | 71 + ...usionMBeanInfoAssemblerNotMappedTests.java | 72 + ...ethodExclusionMBeanInfoAssemblerTests.java | 81 + ...ameBasedMBeanInfoAssemblerMappedTests.java | 95 + ...ethodNameBasedMBeanInfoAssemblerTests.java | 59 + .../assembler/ReflectiveAssemblerTests.java | 49 + .../export/assembler/interfaceAssembler.xml | 42 + .../assembler/interfaceAssemblerCustom.xml | 39 + .../assembler/interfaceAssemblerMapped.xml | 45 + .../export/assembler/metadata-autodetect.xml | 42 + .../export/assembler/metadataAssembler.xml | 38 + .../assembler/methodExclusionAssembler.xml | 31 + .../methodExclusionAssemblerCombo.xml | 37 + .../methodExclusionAssemblerMapped.xml | 36 + .../methodExclusionAssemblerNotMapped.xml | 36 + .../export/assembler/methodNameAssembler.xml | 39 + .../assembler/methodNameAssemblerMapped.xml | 47 + .../export/assembler/reflectiveAssembler.xml | 36 + .../jmx/export/autodetectLazyMBeans.xml | 26 + .../jmx/export/autodetectMBeans.xml | 26 + .../jmx/export/autodetectNoMBeans.xml | 13 + .../jmx/export/customConfigurer.xml | 47 + .../jmx/export/excludedBeans.xml | 27 + .../springframework/jmx/export/lazyInit.xml | 31 + .../naming/AbstractNamingStrategyTests.java | 42 + .../naming/IdentityNamingStrategyTests.java | 45 + .../export/naming/KeyNamingStrategyTests.java | 42 + .../PropertiesFileNamingStrategyTests.java | 33 + .../naming/PropertiesNamingStrategyTests.java | 50 + .../jmx/export/naming/jmx-names.properties | 1 + .../ModelMBeanNotificationPublisherTests.java | 136 + .../export/notificationPublisherLazyTests.xml | 17 + .../jmx/export/notificationPublisherTests.xml | 23 + .../export/propertyPlaceholderConfigurer.xml | 49 + .../ConnectorServerFactoryBeanTests.java | 120 + .../jmx/support/JmxUtilsTests.java | 243 ++ ...MBeanServerConnectionFactoryBeanTests.java | 115 + .../support/MBeanServerFactoryBeanTests.java | 121 + .../jndi/JndiObjectFactoryBeanTests.java | 385 +++ .../jndi/JndiTemplateEditorTests.java | 56 + .../jndi/JndiTemplateTests.java | 196 ++ .../jndi/SimpleNamingContextTests.java | 210 ++ .../mail/SimpleMailMessageTests.java | 170 ++ .../ConfigurableMimeFileTypeMapTests.java | 72 + .../javamail/InternetAddressEditorTests.java | 76 + .../mail/javamail/JavaMailSenderTests.java | 536 ++++ .../mail/javamail/test.mime.types | 4 + .../easymock/AbstractScalarMockTemplate.java | 128 + .../mock/web/MockHttpServletRequestTests.java | 89 + .../web/MockHttpServletResponseTests.java | 130 + .../mock/web/MockPageContextTests.java | 56 + .../mock/web/MockServletContextTests.java | 70 + .../hibernate3/HibernateInterceptorTests.java | 603 ++++ .../HibernateJtaTransactionTests.java | 1824 ++++++++++++ .../hibernate3/HibernateTemplateTests.java | 2587 +++++++++++++++++ .../HibernateTransactionManagerTests.java | 1789 ++++++++++++ .../LocalSessionFactoryBeanTests.java | 588 ++++ .../orm/hibernate3/filterDefinitions.xml | 30 + .../support/HibernateDaoSupportTests.java | 66 + .../orm/hibernate3/support/LobTypeTests.java | 630 ++++ .../support/OpenSessionInViewTests.java | 661 +++++ .../support/ScopedBeanInterceptorTests.java | 67 + .../orm/hibernate3/typeDefinitions.xml | 32 + .../orm/jdo/JdoInterceptorTests.java | 155 + .../orm/jdo/JdoTemplateTests.java | 787 +++++ .../orm/jdo/JdoTransactionManagerTests.java | 1209 ++++++++ .../LocalPersistenceManagerFactoryTests.java | 146 + .../orm/jdo/support/JdoDaoSupportTests.java | 69 + .../OpenPersistenceManagerInViewTests.java | 183 ++ .../springframework/orm/jdo/test.properties | 1 + .../orm/toplink/MockSessionFactory.java | 37 + .../toplink/SessionBrokerFactoryTests.java | 102 + .../orm/toplink/SessionFactoryUtilsTests.java | 106 + .../orm/toplink/TopLinkInterceptorTests.java | 98 + .../toplink/TopLinkJtaTransactionTests.java | 321 ++ .../orm/toplink/TopLinkTemplateTests.java | 117 + .../TopLinkTransactionManagerTests.java | 496 ++++ .../httpinvoker/HttpInvokerTests.java | 469 +++ .../remoting/jaxrpc/JaxRpcSupportTests.java | 705 +++++ .../remoting/rmi/RmiSupportTests.java | 452 +++ .../support/RemoteInvocationUtilsTests.java | 43 + .../scheduling/TestMethodInvokingTask.java | 52 + .../ConcurrentTaskExecutorTests.java | 48 + .../ScheduledExecutorFactoryBeanTests.java | 263 ++ .../scheduling/quartz/QuartzSupportTests.java | 1082 +++++++ .../scheduling/quartz/QuartzTestBean.java | 45 + .../scheduling/quartz/job-scheduling-data.xml | 29 + ...ipleAnonymousMethodInvokingJobDetailFB.xml | 41 + .../scheduling/quartz/multipleSchedulers.xml | 14 + .../quartz/schedulerAccessorBean.xml | 44 + .../quartz/schedulerRepositoryExposure.xml | 47 + .../scheduling/timer/TimerSupportTests.java | 122 + .../timer/TimerTaskExecutorTests.java | 189 ++ .../springframework/scripting/Calculator.java | 26 + .../scripting/CallCounter.java | 28 + .../scripting/ConfigurableMessenger.java | 26 + .../scripting/ContextScriptBean.java | 32 + .../springframework/scripting/Messenger.java | 26 + .../scripting/MessengerScrambler.java | 34 + .../springframework/scripting/ScriptBean.java | 34 + .../scripting/TestBeanAwareMessenger.java | 30 + .../springframework/scripting/bsh/Broken.bsh | 1 + .../scripting/bsh/BshScriptFactoryTests.java | 306 ++ .../scripting/bsh/Calculator.bsh | 3 + .../scripting/bsh/Messenger.bsh | 21 + .../scripting/bsh/MessengerImpl.bsh | 38 + .../scripting/bsh/MessengerInstance.bsh | 28 + .../scripting/bsh/bsh-with-xsd.xml | 55 + .../scripting/bsh/bshBrokenContext.xml | 12 + .../scripting/bsh/bshContext.xml | 71 + .../scripting/bsh/bshRefreshableContext.xml | 26 + .../scripting/config/ITestBean.java | 30 + .../scripting/config/OtherTestBean.java | 36 + .../config/ScriptingDefaultsTests.java | 69 + .../scripting/config/TestBean.groovy | 19 + .../config/scriptingDefaultsTests.xml | 22 + .../scripting/groovy/Broken.groovyb | 14 + .../scripting/groovy/Calculator.groovy | 10 + .../scripting/groovy/CallCounter.groovy | 24 + .../groovy/DelegatingCalculator.groovy | 19 + .../groovy/GroovyClassLoadingTests.java | 56 + .../groovy/GroovyScriptFactoryTests.java | 447 +++ .../scripting/groovy/Messenger.groovy | 8 + .../scripting/groovy/MessengerInstance.groovy | 14 + .../scripting/groovy/ScriptBean.groovy | 23 + .../scripting/groovy/TestFactoryBean.groovy | 17 + .../scripting/groovy/calculators-with-xsd.xml | 18 + .../scripting/groovy/calculators.xml | 25 + .../groovy/groovy-multiple-properties.xml | 24 + .../scripting/groovy/groovy-with-xsd.xml | 60 + .../scripting/groovy/groovyBrokenContext.xml | 11 + .../scripting/groovy/groovyContext.xml | 71 + .../groovy/groovyRefreshableContext.xml | 24 + .../scripting/groovy/lwspBadGroovyContext.xml | 22 + .../groovy/twoClassesCorrectOneFirst.xml | 28 + .../groovy/twoClassesWrongOneFirst.xml | 28 + .../jruby/AdvisedJRubyScriptFactoryTests.java | 61 + .../springframework/scripting/jruby/Broken.rb | 4 + .../scripting/jruby/Calculator.rb | 9 + .../jruby/JRubyScriptFactoryTests.java | 286 ++ .../scripting/jruby/Messenger.rb | 21 + .../scripting/jruby/PrimitiveAdder.java | 25 + .../scripting/jruby/Printable.java | 26 + .../scripting/jruby/Printer.java | 26 + .../scripting/jruby/Printer.rb | 9 + .../scripting/jruby/WrapperAdder.java | 52 + .../advisedByBeanNameAutoProxyCreator.xml | 21 + .../jruby/advisedByProxyFactoryBean.xml | 21 + .../scripting/jruby/jruby-aop.xml | 28 + .../scripting/jruby/jruby-with-xsd.xml | 79 + .../scripting/jruby/jrubyBrokenContext.xml | 12 + .../scripting/jruby/jrubyContext.xml | 36 + .../jruby/jrubyContextForPrimitives.xml | 53 + .../jruby/jrubyContextForWrappers.xml | 73 + .../jruby/jrubyRefreshableContext.xml | 21 + .../RefreshableScriptTargetSourceTests.java | 41 + .../support/ResourceScriptSourceTests.java | 102 + .../ScriptFactoryPostProcessorTests.java | 277 ++ .../support/StaticScriptSourceTests.java | 88 + .../scripting/support/StubMessenger.java | 36 + .../scripting/support/groovyReferences.xml | 32 + ...stractSpr3350SingleSpringContextTests.java | 77 + ...ingleSpringContextTests-context.properties | 2 + ...sBasedSpr3350SingleSpringContextTests.java | 58 + ...DependencyInjectionSpringContextTests.java | 65 + .../test/Spr3264SingleSpringContextTests.java | 54 + ...pr3350SingleSpringContextTests-context.xml | 9 + ...lBasedSpr3350SingleSpringContextTests.java | 44 + .../test/jdbc/JdbcTestUtilsTests.java | 74 + .../transaction/TransactionTestUtils.java | 82 + .../test/util/ReflectionTestUtilsTests.java | 194 ++ .../util/subpackage/PersistentEntity.java | 38 + .../test/util/subpackage/Person.java | 98 + .../CallCountingTransactionManager.java | 58 + .../JndiJtaTransactionManagerTests.java | 243 ++ .../JtaTransactionManagerTests.java | 1574 ++++++++++ ...kCallbackPreferringTransactionManager.java | 60 + .../transaction/MockJtaTransaction.java | 60 + .../transaction/TestTransactionManager.java | 87 + .../transaction/TransactionSupportTests.java | 284 ++ .../TxNamespaceHandlerEventTests.java | 50 + .../transaction/TxNamespaceHandlerTests.java | 94 + .../AbstractTransactionAspectTests.java | 599 ++++ .../BeanFactoryTransactionTests.java | 225 ++ .../interceptor/ImplementsNoInterfaces.java | 43 + .../MapTransactionAttributeSource.java | 51 + .../PlatformTransactionManagerFacade.java | 52 + .../interceptor/RollbackRuleTests.java | 91 + .../RuleBasedTransactionAttributeTests.java | 162 ++ .../TransactionAttributeEditorTests.java | 173 ++ ...ransactionAttributeSourceAdvisorTests.java | 42 + ...TransactionAttributeSourceEditorTests.java | 117 + .../TransactionAttributeSourceTests.java | 146 + .../TransactionInterceptorTests.java | 126 + .../noTransactionAttributeSource.xml | 23 + .../interceptor/transactionalBeanFactory.xml | 137 + .../transaction/jta/MockUOWManager.java | 125 + .../WebSphereUowTransactionManagerTests.java | 629 ++++ ...aTransactionManagerSerializationTests.java | 60 + .../transaction/txNamespaceHandlerTests.xml | 33 + .../org/springframework/ui/ModelMapTests.java | 280 ++ .../ui/jasperreports/DataSourceReport.jasper | Bin 0 -> 18664 bytes .../ui/jasperreports/DataSourceReport.jrxml | 185 ++ .../JasperReportsUtilsTests.java | 247 ++ .../ui/jasperreports/PersonBean.java | 64 + .../ui/jasperreports/ProductBean.java | 64 + .../ui/jasperreports/messages_de.properties | 1 + .../ui/jasperreports/subReportChild.jasper | Bin 0 -> 18449 bytes .../ui/jasperreports/subReportChild.jrxml | 227 ++ .../ui/jasperreports/subReportParent.jasper | Bin 0 -> 14261 bytes .../ui/jasperreports/subReportParent.jrxml | 103 + .../org/springframework/util/AssertTests.java | 184 ++ .../util/AutoPopulatingListTests.java | 94 + .../util/CachingMapDecoratorTests.java | 63 + .../springframework/util/ClassUtilsTests.java | 320 ++ .../util/CollectionUtilsTests.java | 226 ++ .../util/FileCopyUtilsTests.java | 82 + .../util/FileSystemUtilsTests.java | 88 + .../util/Log4jConfigurerTests.java | 100 + .../util/MethodInvokerTests.java | 285 ++ .../util/MockLog4jAppender.java | 59 + .../util/NumberUtilsTests.java | 348 +++ .../util/ObjectUtilsTests.java | 627 ++++ .../util/PathMatcherTests.java | 285 ++ .../util/PatternMatchUtilsTests.java | 81 + .../util/PropertiesPersisterTests.java | 125 + .../util/ReflectionUtilsTests.java | 285 ++ .../util/ResourceUtilsTests.java | 71 + .../util/SerializationTestUtils.java | 97 + .../springframework/util/StopWatchTests.java | 144 + .../util/StringUtilsTests.java | 614 ++++ .../util/comparator/ComparatorTests.java | 179 ++ .../springframework/util/testlog4j.properties | 2 + .../util/xml/TransformerUtilsTests.java | 151 + .../DataBinderFieldAccessTests.java | 160 + .../validation/DataBinderTests.java | 1348 +++++++++ .../validation/ValidationUtilsTests.java | 181 ++ .../validation/messages1.properties | 1 + .../validation/messages2.properties | 2 + .../validation/messages3.properties | 2 + .../web/bind/EscapedErrorsTests.java | 90 + .../web/bind/RequestUtilsTests.java | 413 +++ .../bind/ServletRequestDataBinderTests.java | 161 + .../web/bind/ServletRequestUtilsTests.java | 446 +++ .../web/context/ContextLoaderTests.java | 272 ++ .../ResourceBundleMessageSourceTests.java | 279 ++ .../web/context/ServletConfigAwareBean.java | 35 + .../web/context/ServletContextAwareBean.java | 35 + .../ServletContextAwareProcessorTests.java | 156 + .../context/WEB-INF/applicationContext.xml | 81 + .../web/context/WEB-INF/context-addition.xml | 50 + .../WEB-INF/context-messages.properties | 6 + .../WEB-INF/context-messages_en_GB.properties | 2 + .../WEB-INF/context-messages_en_US.properties | 5 + .../web/context/WEB-INF/contextInclude.xml | 6 + .../web/context/WEB-INF/empty-servlet.xml | 12 + .../web/context/WEB-INF/fail.xml | 8 + .../WEB-INF/more-context-messages.properties | 2 + .../web/context/WEB-INF/myoverride.properties | 3 + .../context/WEB-INF/myplaceholder.properties | 4 + .../WEB-INF/resources/messageSource.xml | 24 + .../context/WEB-INF/resources/themeSource.xml | 12 + .../web/context/WEB-INF/sessionContext.xml | 16 + .../context/WEB-INF/test-messages.properties | 1 + .../web/context/WEB-INF/test-servlet.xml | 59 + .../web/context/WEB-INF/test-theme.properties | 1 + .../web/context/WEB-INF/testNamespace.xml | 17 + .../web/context/WEB-INF/theme.properties | 2 + .../context/WEB-INF/theme_en_GB.properties | 0 .../context/WEB-INF/theme_en_US.properties | 1 + .../web/context/WEB-INF/web.xml | 151 + .../XmlWebApplicationContextTests.java | 191 ++ .../RequestAndSessionScopedProxyTests.java | 102 + .../request/RequestContextListenerTests.java | 110 + .../context/request/RequestScopeTests.java | 172 ++ .../request/RequestScopedProxyTests.java | 187 ++ .../ServletRequestAttributesTests.java | 169 ++ .../request/ServletWebRequestTests.java | 64 + .../context/request/SessionScopeTests.java | 196 ++ .../web/context/request/requestScopeTests.xml | 39 + .../request/requestScopedProxyTests.xml | 55 + .../web/context/request/sessionScopeTests.xml | 10 + .../support/HttpRequestHandlerTests.java | 90 + .../support/ServletContextSupportTests.java | 474 +++ .../WebApplicationObjectSupportTests.java | 63 + .../filter/CharacterEncodingFilterTests.java | 199 ++ .../filter/DelegatingFilterProxyTests.java | 170 ++ .../web/filter/RequestContextFilterTests.java | 99 + .../jsf/DelegatingNavigationHandlerTests.java | 100 + .../web/jsf/DelegatingPhaseListenerTests.java | 101 + .../jsf/DelegatingVariableResolverTests.java | 83 + .../web/jsf/MockFacesContext.java | 125 + .../web/jsf/MockLifecycle.java | 46 + .../MockMultipartHttpServletRequestTests.java | 88 + .../CommonsMultipartResolverTests.java | 485 +++ .../ByteArrayMultipartFileEditorTests.java | 92 + .../ComplexPortletApplicationContext.java | 504 ++++ .../web/portlet/DispatcherPortletTests.java | 989 +++++++ .../web/portlet/GenericPortletBeanTests.java | 177 ++ .../SimplePortletApplicationContext.java | 129 + .../bind/PortletRequestDataBinderTests.java | 237 ++ ...etRequestParameterPropertyValuesTests.java | 64 + .../bind/PortletRequestUtilsTests.java | 437 +++ .../context/PortletConfigAwareBean.java | 35 + .../context/PortletContextAwareBean.java | 35 + .../PortletContextAwareProcessorTests.java | 154 + .../PortletRequestAttributesTests.java | 170 ++ .../context/PortletWebRequestTests.java | 64 + .../portlet/context/WEB-INF/empty-portlet.xml | 12 + .../portlet/context/WEB-INF/test-portlet.xml | 12 + .../XmlPortletApplicationContextTests.java | 134 + .../handler/ParameterHandlerMappingTests.java | 103 + .../ParameterMappingInterceptorTests.java | 131 + .../PortletModeHandlerMappingTests.java | 87 + ...rtletModeParameterHandlerMappingTests.java | 112 + .../SimpleMappingExceptionResolverTests.java | 277 ++ ...UserRoleAuthorizationInterceptorTests.java | 110 + .../web/portlet/handler/parameterMapping.xml | 19 + .../portlet/handler/portletModeMapping.xml | 22 + .../handler/portletModeParameterMapping.xml | 30 + .../portlet/mvc/CommandControllerTests.java | 461 +++ .../ParameterizableViewControllerTests.java | 73 + .../PortletModeNameViewControllerTests.java | 76 + .../mvc/PortletWrappingControllerTests.java | 188 ++ .../web/portlet/util/PortletUtilsTests.java | 605 ++++ .../servlet/ComplexWebApplicationContext.java | 461 +++ .../web/servlet/DispatcherServletTests.java | 866 ++++++ .../servlet/SimpleWebApplicationContext.java | 141 + .../web/servlet/complexviews.properties | 3 + .../BeanNameUrlHandlerMappingTests.java | 192 ++ .../PathMatchingUrlHandlerMappingTests.java | 251 ++ .../SimpleMappingExceptionResolverTests.java | 243 ++ .../handler/SimpleUrlHandlerMappingTests.java | 142 + .../web/servlet/handler/map1.xml | 11 + .../web/servlet/handler/map2.properties | 7 + .../web/servlet/handler/map2.xml | 38 + .../web/servlet/handler/map2err.xml | 33 + .../web/servlet/handler/map3.xml | 45 + .../metadata/BeanPropertyController.java | 43 + .../metadata/ConstructorController.java | 43 + .../metadata/PathMapHandlerMappingTests.java | 221 ++ .../i18n/CookieLocaleResolverTests.java | 171 ++ .../web/servlet/i18n/LocaleResolverTests.java | 70 + .../i18n/SessionLocaleResolverTests.java | 95 + .../mvc/CancellableFormControllerTests.java | 236 ++ .../servlet/mvc/CommandControllerTests.java | 510 ++++ .../web/servlet/mvc/ControllerTests.java | 216 ++ .../web/servlet/mvc/FormControllerTests.java | 646 ++++ .../mvc/UrlFilenameViewControllerTests.java | 158 + .../mvc/WebContentInterceptorTests.java | 122 + .../mvc/WizardFormControllerTests.java | 428 +++ .../servlet/mvc/mapping/AdminController.java | 26 + .../web/servlet/mvc/mapping/BuyForm.java | 26 + .../web/servlet/mvc/mapping/Controller.java | 33 + ...ControllerBeanNameHandlerMappingTests.java | 78 + ...ontrollerClassNameHandlerMappingTests.java | 116 + .../mvc/mapping/WelcomeController.java | 34 + .../web/servlet/mvc/mapping/class-mapping.xml | 59 + .../web/servlet/mvc/mapping/name-mapping.xml | 24 + .../MultiActionControllerTests.java | 720 +++++ .../web/servlet/tags/AbstractTagTests.java | 74 + .../BindTagOutsideDispatcherServletTests.java | 29 + .../web/servlet/tags/BindTagTests.java | 1040 +++++++ ...scapeTagOutsideDispatcherServletTests.java | 29 + .../web/servlet/tags/HtmlEscapeTagTests.java | 182 ++ ...ssageTagOutsideDispatcherServletTests.java | 29 + .../web/servlet/tags/MessageTagTests.java | 422 +++ .../web/servlet/tags/ThemeTagTests.java | 69 + .../tags/form/AbstractFormTagTests.java | 51 + .../form/AbstractHtmlElementTagTests.java | 125 + .../servlet/tags/form/CheckboxTagTests.java | 624 ++++ .../servlet/tags/form/CheckboxesTagTests.java | 671 +++++ .../web/servlet/tags/form/Country.java | 86 + .../web/servlet/tags/form/ErrorsTagTests.java | 408 +++ .../web/servlet/tags/form/FormTagTests.java | 182 ++ .../tags/form/HiddenInputTagTests.java | 89 + .../web/servlet/tags/form/InputTagTests.java | 359 +++ .../web/servlet/tags/form/ItemPet.java | 71 + .../web/servlet/tags/form/LabelTagTests.java | 119 + .../web/servlet/tags/form/OptionTagTests.java | 563 ++++ .../servlet/tags/form/OptionsTagTests.java | 199 ++ .../tags/form/PasswordInputTagTests.java | 103 + .../tags/form/RadioButtonTagTests.java | 238 ++ .../tags/form/RadioButtonsTagTests.java | 515 ++++ .../web/servlet/tags/form/SelectTagTests.java | 622 ++++ .../servlet/tags/form/SimpleFloatEditor.java | 34 + .../tags/form/TagIdGeneratorTests.java | 47 + .../web/servlet/tags/form/TagWriterTests.java | 121 + .../tags/form/TestBeanWithRealCountry.java | 37 + .../servlet/tags/form/TextareaTagTests.java | 106 + .../web/servlet/theme/ThemeResolverTests.java | 80 + .../web/servlet/view/BaseViewTests.java | 284 ++ ...faultRequestToViewNameTranslatorTests.java | 114 + .../view/DummyMacroRequestContext.java | 146 + .../view/InternalResourceViewTests.java | 237 ++ .../web/servlet/view/RedirectViewTests.java | 235 ++ ...esourceBundleViewResolverNoCacheTests.java | 28 + .../view/ResourceBundleViewResolverTests.java | 181 ++ .../web/servlet/view/ViewResolverTests.java | 493 ++++ .../servlet/view/document/ExcelViewTests.java | 331 +++ .../servlet/view/document/PdfViewTests.java | 78 + .../web/servlet/view/document/template.xls | Bin 0 -> 13824 bytes .../web/servlet/view/document/template_de.xls | Bin 0 -> 13824 bytes .../servlet/view/document/template_en_US.xls | Bin 0 -> 13824 bytes .../freemarker/FreeMarkerConfigurerTests.java | 105 + .../view/freemarker/FreeMarkerMacroTests.java | 191 ++ .../view/freemarker/FreeMarkerViewTests.java | 174 ++ .../web/servlet/view/freemarker/test.ftl | 79 + ...actConfigurableJasperReportsViewTests.java | 47 + .../AbstractJasperReportsTests.java | 117 + .../AbstractJasperReportsViewTests.java | 421 +++ ...rableJasperReportsViewWithStreamTests.java | 38 + ...rableJasperReportsViewWithWriterTests.java | 37 + .../jasperreports/ExporterParameterTests.java | 161 + .../JasperReportViewResolverTests.java | 92 + .../JasperReportsCsvViewTests.java | 32 + .../JasperReportsHtmlViewTests.java | 57 + .../JasperReportsMultiFormatViewTests.java | 131 + ...ultiFormatViewWithCustomMappingsTests.java | 48 + .../JasperReportsPdfViewTests.java | 32 + .../JasperReportsXlsViewTests.java | 32 + .../view/jasperreports/view.properties | 4 + .../web/servlet/view/testviews.properties | 13 + .../web/servlet/view/testviews_en.properties | 1 + .../web/servlet/view/testviews_fr.properties | 3 + .../view/velocity/TestVelocityEngine.java | 54 + .../velocity/VelocityConfigurerTests.java | 153 + .../view/velocity/VelocityMacroTests.java | 184 ++ .../view/velocity/VelocityViewTests.java | 503 ++++ .../web/servlet/view/velocity/test.vm | 57 + .../web/servlet/view/velocity/toolbox.xml | 23 + .../web/servlet/view/views.xml | 27 + .../servlet/view/xslt/TestXsltViewTests.java | 392 +++ .../view/xslt/XsltViewResolverTests.java | 47 + .../web/servlet/view/xslt/XsltViewTests.java | 221 ++ .../web/servlet/view/xslt/dummyData.xsl | 1 + .../web/servlet/view/xslt/errors.xsl | 9 + .../web/servlet/view/xslt/firstWords.xsl | 20 + .../web/servlet/view/xslt/productData.xml | 6 + .../web/servlet/view/xslt/products.xsl | 23 + .../web/servlet/view/xslt/productsImport.xsl | 20 + .../web/servlet/view/xslt/sunnyDay.xsl | 25 + .../view/xslt/sunnyDayExplicitRoot.xsl | 12 + .../web/servlet/view/xslt/valid.xsl | 8 + .../util/ExpressionEvaluationUtilsTests.java | 287 ++ .../util/HtmlCharacterEntityReferences.dtd | 523 ++++ .../HtmlCharacterEntityReferencesTests.java | 165 ++ .../web/util/HtmlUtilsTests.java | 116 + .../web/util/Log4jWebConfigurerTests.java | 140 + .../web/util/TagUtilsTests.java | 162 ++ .../web/util/UrlPathHelperTests.java | 59 + .../web/util/WebUtilsTests.java | 52 + .../src/test/resources/log4j.xml | 28 + org.springframework.testsuite/template.mf | 4 + 1104 files changed, 144705 insertions(+) create mode 100644 org.springframework.testsuite/build.xml create mode 100644 org.springframework.testsuite/ivy.xml create mode 100644 org.springframework.testsuite/pom.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceAdapter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceImpl.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AbstractAdviceBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AdviceBindingTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterAdviceBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceCircularTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutAdvisorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AuthenticationLogger.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNameAwareMixin.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeforeAdviceBindingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/CallCountingInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/Counter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclarationOrderIndependenceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsDelegateRefTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ICounter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/NonAnnotatedMakeLockable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PrecedenceTestAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ProceedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SerializableMixin.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SharedPointcutWithArgsMismatch.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SimpleSpringBeforeAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeMatchingTestClasses.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeSensitiveMatchingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TargetPointcutSelectionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyAspect.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTarget.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTargetImpl.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/advice-precedence-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/after-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterReturning-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterThrowing-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ambiguous-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/args-mismatch.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-circular-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/aspectj.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectImplementingInterfaceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspect-implementing-interface-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/before-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-delegate-ref-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/overloaded-advice-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/proceedTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/subtype-sensitive-matching.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/targetPointcutSelectionTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-tests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/topsy-turvy-aspect.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceAdviceTypeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerArgNamesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerProxyTargetClassTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerReturningTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerThrowingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/CountingAspectJAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/MethodLocatingFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/PrototypeProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeErrorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeOKTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithDirectPointcutEventTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithPointcutRefEventTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesErrorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesOKTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAspectEventTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutDuplicationTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutEventTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutMissingTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerProxyTargetClassTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningErrorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningOKTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerScopeTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingErrorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingOKTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/prototypeProxy.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/config/topLevelAop.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingAfterReturningAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingBeforeAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingMultiAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingThrowsAdvice.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/DefaultLockable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ExposedInvocationTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/InvocationCheckExposedInvocationTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixin.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixinAdvisor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/Lockable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockedException.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodCounter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodVisibilities.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MockTargetSource.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoArgCtorTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfaces.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfacesConstructor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProtectedMethodTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimeStamped.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionAdvisor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/UnsupportedInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withBPPContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withoutBPPContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorInitTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CountingTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CreatesTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NeverMatchAdvisor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NoSetters.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NullChecker.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/OrderedTxCheckAdvisor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/Rollback.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/SelectivePrototypeTargetSourceCreator.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreator.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreatorWithCommonInterceptors.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorInitTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/customTargetSource.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/optimizedAutoProxyCreator.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/quickTargetSource.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/frozenProxyFactoryBean.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/innerBeanTarget.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/invalidProxyFactory.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTarget.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryBeanAutowiringTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryDoubleTargetSourceTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceNotLastTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/serializationTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/throwsAdvice.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/framework/withDependencyChecking.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/CustomizableTraceInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/NopInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/PerformanceMonitorInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SerializableNopInterceptor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SideEffectBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/exposeInvocation.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/DefaultScopedObjectTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireFalse.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireTrue.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedList.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedMap.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedOverride.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedTestBean.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/AopUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/ClassFiltersTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/JdkRegexpMethodPointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/MethodMatchersTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/PointcutsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/support/regexpSetterTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyCreationTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolProxyTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/customLazyInitTarget.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/hotSwapTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitFactoryBean.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitSingletonTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/prototypeTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/aop/target/threadLocalTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/BeanUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWithObjectProperty.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWrapperTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/BooleanTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/Colour.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/ConcurrentBeanWrapperTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/DerivedTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/Employee.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/FieldAccessBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/INestedTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/IOther.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/ITestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/IndexedTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/NestedTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/NumberTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/Person.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/Pet.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/PropertyAccessorUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/ResourceTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/SerializablePerson.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/TestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractBeanFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractListableBeanFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/CountingFactory.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DummyFactory.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/HasMap.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/KnowsIfInstantiated.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/LifecycleBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/MustBeInitialized.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/PackageLevelVisibleBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/SharedBeanRegistryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/TestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans1.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans2.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/ref1.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/concurrent.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/BeanFactoryPostProcessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CommonsLogFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomScopeConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/NoOpScope.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleMapScope.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/fieldRetrieving.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/propertyPath.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/simpleScope.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test-properties.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/util.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/dependentBeans.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeanReturnsNull.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeansWithAutowiring.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/leaf.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/middle.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CollectingReaderEventListener.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ConstructorArgumentEntryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/FailFastProblemReporterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/NullSourceExtractorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ParseStateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PassThroughSourceExtractorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PropertyEntryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/withErrors.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/root.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedListTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedMapTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedPropertiesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedSetTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/multiConstructorArgs.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/refConstructorArg.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/simpleConstructorArg.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanWiringInfoTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/ClassNameBeanWiringInfoResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/BeanNameGenerationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorInjectedOverrides.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DefaultLifecycleMethodsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DelegatingEntityResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DependenciesBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DerivedConstructorDependenciesBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBo.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBoImpl.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyDao.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethods.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FixedMethodReplacer.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/GeneratedNameBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/LookupMethodWrappedByCglibProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MetadataAttachmentTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MethodReplaceCandidate.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MixedCollectionBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideInterface.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethod.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethodSubclass.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ProtectedLifecycleBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ReverseMethodReplacer.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SerializableMethodReplacerCandidate.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ShortcutTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SingleSimpleTypeConstructorBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-exclusion.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-inclusion.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEvents.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEventsImported.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanNameGeneration.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/child.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/classNotFound.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionMerging.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collections.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/complexFactoryCircle.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructor-arg.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructorOverrides.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-autowire.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-lazy-init.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/defaultLifecycleMethods.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/delegationOverrides.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-autowire.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-inner.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn-inner.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByName.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByType.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inTheMiddle.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inner.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependenciesMaterializeThis.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factory-methods.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factoryCircle.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ignoreDefaultLifecycleMethods.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/initializers.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid-factory.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidOverridesNoSuchMethod.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidPerSchema.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/local-collections-using-XSD.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/no-such-factory-method.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overloadOverrides.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overrides.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/parent.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/recursiveImport.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/reftypes.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resource.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resourceImport.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedAllDependencyCheck.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedObjectDependencyCheck.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedSimpleDependencyCheck.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/schemaValidated.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutWithErrorsTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/DefaultNamespaceHandlerResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/TestNamespaceHandler.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/invalid.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/nonExistent.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/spring-test.xsd create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testUtilNamespace.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNameInAlias.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNames.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingObjects.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingSimple.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedObjectDependencyCheck.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedSimpleDependencyCheck.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithDtd.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithXsd.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/withMeta.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ByteArrayPropertyEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CharArrayPropertyEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/FileEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/InputStreamEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/PropertiesEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountryDialect_en_GB_GLASGOW.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountry_en_GB.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLang_en.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URIEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URLEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/support/DerivedFromProtectedBaseBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/support/PagedListHolderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/beans/support/ProtectedBaseBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/testEhcache.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/ACATester.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/AbstractApplicationContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatBroadcasts.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatListens.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/LifecycleContextBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/TestListener.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextBeanFactoryReferenceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextJndiBeanFactoryLocatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextSingletonBeanFactoryLocatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/access/DefaultLocatorFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/config/contextNamespaceHandlerTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/event/LifecycleEventTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/ApplicationContextLifecycleTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/Assembler.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/AutowiredService.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/ClassPathXmlApplicationContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/FactoryBeanAndApplicationListener.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/LifecycleTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/Logic.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceMapFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/Service.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextMulticasterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticMessageSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/TestIF.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasForParent.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasThatOverridesParent.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/childWithProxy.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/classWithPlaceholder.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidClass.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidValueType.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/lifecycleTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/messages.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT_oo.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_DE.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/more-messages.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/override.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/placeholder.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/simpleContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/test.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/test/aliased-contextC.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextA.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextB.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextC.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/test/import1.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/test/subtest/import2.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/context/support/testBeans.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/AbstractControlFlowTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/AttributeAccessorSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/CollectionFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/ConstantsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/ConventionsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/DefaultControlFlowTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/Jdk14ControlFlowTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/NestedExceptionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/OrderComparatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/enums/LabeledEnumTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/enums/StandAloneStaticLabeledEnum.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/style/ToStringCreatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/task/MockRunnable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/task/NoOpRunnable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/core/task/StubTaskExecutor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/dao/support/ChainedPersistenceExceptionTranslatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jca/StubActivationSpec.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jca/StubResourceAdapter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciLocalTransactionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jca/cci/EisOperationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jca/support/LocalConnectionFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/AbstractJdbcTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/Customer.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/RowMapperTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/SimpleRowCountCallbackHandler.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/StatementCreatorUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/MapSqlParameterSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterQueryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcBeanDefinitionReaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcDaoSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/LobSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/SqlLobValueTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ConcretePerson.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ExtendedPerson.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/Person.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceJtaTransactionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DriverManagerDataSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookupTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/JndiDataSourceLookupTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/MapDataSourceLookupTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/StubDataSource.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/BatchSqlUpdateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/RdbmsOperationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlFunctionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlQueryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlUpdateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/StoredProcedureTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/CustomErrorCodeException.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DefaultLobHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/JdbcUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/KeyHolderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/NativeJdbcExtractorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodesFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassFactory.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassTranslatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateExceptionTranslatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/custom-error-codes.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/rowset/ResultSetWrappingRowSetTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/test-error-codes.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/wildcard-error-codes.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/StubConnectionFactory.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/StubQueue.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/StubTopic.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/config/JmsNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/config/jmsNamespaceHandlerTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/connection/JmsTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/connection/SingleConnectionFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestConnection.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestExceptionListener.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102JtaTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102Tests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102TransactedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateJtaTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTransactedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/core/support/JmsGatewaySupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/AbstractMessageListenerContainerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/SimpleMessageListenerContainerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageContentsDelegate.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageDelegate.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapter102Tests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveJmsTextMessageReturningMessageDelegate.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveMessageDelegate.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter102.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/DefaultJmsActivationSpecFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpec.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpecFactory.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/remoting/JmsInvokerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/support/JmsAccessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverter102Tests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/DynamicDestinationResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JmsDestinationAccessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JndiDestinationResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractJmxTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/IJmxTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/JmxTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/access/CommonsAttributesMBeanProxyFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/access/proxyFactoryBean.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/applicationContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/DateRange.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/ExceptionOnInitBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/LazyInitMBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/TestDynamicMBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractAutodetectTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerAutodetectTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/IAdditionalTestMethods.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomBase.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomJmxBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ReflectiveAssemblerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssembler.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerCustom.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerMapped.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadata-autodetect.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadataAssembler.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssembler.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerCombo.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerMapped.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerNotMapped.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssembler.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssemblerMapped.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/reflectiveAssembler.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectLazyMBeans.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectMBeans.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectNoMBeans.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/customConfigurer.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/excludedBeans.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/lazyInit.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/AbstractNamingStrategyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/IdentityNamingStrategyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/KeyNamingStrategyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesFileNamingStrategyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesNamingStrategyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/jmx-names.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notification/ModelMBeanNotificationPublisherTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherLazyTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/export/propertyPlaceholderConfigurer.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/support/JmxUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiObjectFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/jndi/SimpleNamingContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mail/SimpleMailMessageTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMapTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/InternetAddressEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/JavaMailSenderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/test.mime.types create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mock/easymock/AbstractScalarMockTemplate.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequestTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockPageContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockServletContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateJtaTransactionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/filterDefinitions.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/HibernateDaoSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/LobTypeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/typeDefinitions.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/LocalPersistenceManagerFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/JdoDaoSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/test.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/MockSessionFactory.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionBrokerFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionFactoryUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkJtaTransactionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTemplateTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxrpc/JaxRpcSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/remoting/support/RemoteInvocationUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/TestMethodInvokingTask.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ConcurrentTaskExecutorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/job-scheduling-data.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleAnonymousMethodInvokingJobDetailFB.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleSchedulers.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerAccessorBean.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerRepositoryExposure.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerTaskExecutorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/Calculator.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/CallCounter.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/ConfigurableMessenger.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/ContextScriptBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/Messenger.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/MessengerScrambler.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/ScriptBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/TestBeanAwareMessenger.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Broken.bsh create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/BshScriptFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Calculator.bsh create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Messenger.bsh create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerImpl.bsh create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerInstance.bsh create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bsh-with-xsd.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshBrokenContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshRefreshableContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ITestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/config/OtherTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ScriptingDefaultsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/config/TestBean.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/config/scriptingDefaultsTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Broken.groovyb create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Calculator.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/CallCounter.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/DelegatingCalculator.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyClassLoadingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Messenger.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/MessengerInstance.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/ScriptBean.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/TestFactoryBean.groovy create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators-with-xsd.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-multiple-properties.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-with-xsd.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyBrokenContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyRefreshableContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/lwspBadGroovyContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesCorrectOneFirst.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesWrongOneFirst.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Broken.rb create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Calculator.rb create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Messenger.rb create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/PrimitiveAdder.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printable.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.rb create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/WrapperAdder.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByBeanNameAutoProxyCreator.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByProxyFactoryBean.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-aop.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-with-xsd.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyBrokenContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForPrimitives.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForWrappers.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyRefreshableContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/support/RefreshableScriptTargetSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ResourceScriptSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ScriptFactoryPostProcessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StaticScriptSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StubMessenger.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/scripting/support/groovyReferences.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/AbstractSpr3350SingleSpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests-context.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264DependencyInjectionSpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264SingleSpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests-context.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/jdbc/JdbcTestUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/transaction/TransactionTestUtils.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/Person.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/CallCountingTransactionManager.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/JndiJtaTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/JtaTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/MockCallbackPreferringTransactionManager.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/MockJtaTransaction.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/TestTransactionManager.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/TransactionSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerEventTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/AbstractTransactionAspectTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/ImplementsNoInterfaces.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/PlatformTransactionManagerFacade.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RollbackRuleTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/noTransactionAttributeSource.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/transactionalBeanFactory.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/MockUOWManager.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/support/JtaTransactionManagerSerializationTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/transaction/txNamespaceHandlerTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/ModelMapTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/DataSourceReport.jasper create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/DataSourceReport.jrxml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/JasperReportsUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/PersonBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/ProductBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/messages_de.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportChild.jasper create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportChild.jrxml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportParent.jasper create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportParent.jrxml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/AssertTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/AutoPopulatingListTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/CachingMapDecoratorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/ClassUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/CollectionUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/FileCopyUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/FileSystemUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/Log4jConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/MethodInvokerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/MockLog4jAppender.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/NumberUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/ObjectUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/PathMatcherTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/PatternMatchUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/PropertiesPersisterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/ReflectionUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/ResourceUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/SerializationTestUtils.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/StopWatchTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/StringUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/comparator/ComparatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/testlog4j.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/util/xml/TransformerUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderFieldAccessTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/validation/ValidationUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/validation/messages1.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/validation/messages2.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/validation/messages3.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/bind/EscapedErrorsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/bind/RequestUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestDataBinderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/ContextLoaderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/ResourceBundleMessageSourceTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletConfigAwareBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareProcessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/applicationContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-addition.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_GB.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_US.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/contextInclude.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/empty-servlet.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/fail.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/more-context-messages.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myoverride.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myplaceholder.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/messageSource.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/themeSource.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/sessionContext.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-messages.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-servlet.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-theme.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/testNamespace.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme_en_GB.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme_en_US.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/web.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/XmlWebApplicationContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestAndSessionScopedProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestContextListenerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopedProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletRequestAttributesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/SessionScopeTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopeTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopedProxyTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/request/sessionScopeTests.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/support/HttpRequestHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/support/ServletContextSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/context/support/WebApplicationObjectSupportTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/filter/CharacterEncodingFilterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/filter/RequestContextFilterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingNavigationHandlerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingPhaseListenerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingVariableResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockFacesContext.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockLifecycle.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/multipart/MockMultipartHttpServletRequestTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/multipart/commons/CommonsMultipartResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/multipart/support/ByteArrayMultipartFileEditorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/GenericPortletBeanTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestDataBinderTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestParameterPropertyValuesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletConfigAwareBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareBean.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareProcessorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletRequestAttributesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/empty-portlet.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/test-portlet.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterMappingInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeParameterHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/parameterMapping.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeMapping.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeParameterMapping.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/ParameterizableViewControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletModeNameViewControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletWrappingControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/complexviews.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/BeanNameUrlHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/PathMatchingUrlHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map1.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2err.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map3.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/BeanPropertyController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/ConstructorController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/PathMapHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/LocaleResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/ControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/UrlFilenameViewControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/AdminController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/Controller.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerBeanNameHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerClassNameHandlerMappingTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/WelcomeController.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/class-mapping.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/name-mapping.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/multiaction/MultiActionControllerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagOutsideDispatcherServletTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/HtmlEscapeTagOutsideDispatcherServletTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/HtmlEscapeTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/MessageTagOutsideDispatcherServletTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/MessageTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/ThemeTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/AbstractFormTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/AbstractHtmlElementTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxesTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/Country.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/ErrorsTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/HiddenInputTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/InputTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/ItemPet.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/LabelTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/OptionTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/OptionsTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/PasswordInputTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/RadioButtonTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/RadioButtonsTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/SelectTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/SimpleFloatEditor.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/TagIdGeneratorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/TagWriterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/TestBeanWithRealCountry.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/TextareaTagTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/theme/ThemeResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/BaseViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/DefaultRequestToViewNameTranslatorTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/DummyMacroRequestContext.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/InternalResourceViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/RedirectViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/ResourceBundleViewResolverNoCacheTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/ResourceBundleViewResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/ViewResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/document/ExcelViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/document/PdfViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/document/template.xls create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/document/template_de.xls create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/document/template_en_US.xls create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerMacroTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/freemarker/test.ftl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/AbstractConfigurableJasperReportsViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/AbstractJasperReportsTests.java create mode 100755 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/AbstractJasperReportsViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/ConfigurableJasperReportsViewWithStreamTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/ConfigurableJasperReportsViewWithWriterTests.java create mode 100755 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/ExporterParameterTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/JasperReportViewResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/JasperReportsCsvViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/JasperReportsHtmlViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/JasperReportsMultiFormatViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/JasperReportsMultiFormatViewWithCustomMappingsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/JasperReportsPdfViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/JasperReportsXlsViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/jasperreports/view.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/testviews.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/testviews_en.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/testviews_fr.properties create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/velocity/TestVelocityEngine.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/velocity/VelocityConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/velocity/VelocityMacroTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/velocity/VelocityViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/velocity/test.vm create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/velocity/toolbox.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/views.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/TestXsltViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/XsltViewResolverTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/XsltViewTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/dummyData.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/errors.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/firstWords.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/productData.xml create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/products.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/productsImport.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/sunnyDay.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/sunnyDayExplicitRoot.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/servlet/view/xslt/valid.xsl create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/ExpressionEvaluationUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/HtmlCharacterEntityReferences.dtd create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/HtmlCharacterEntityReferencesTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/HtmlUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/Log4jWebConfigurerTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/TagUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/UrlPathHelperTests.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/web/util/WebUtilsTests.java create mode 100644 org.springframework.testsuite/src/test/resources/log4j.xml create mode 100644 org.springframework.testsuite/template.mf diff --git a/org.springframework.testsuite/build.xml b/org.springframework.testsuite/build.xml new file mode 100644 index 00000000000..d9b1bf06112 --- /dev/null +++ b/org.springframework.testsuite/build.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/org.springframework.testsuite/ivy.xml b/org.springframework.testsuite/ivy.xml new file mode 100644 index 00000000000..8c468e0bbaa --- /dev/null +++ b/org.springframework.testsuite/ivy.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/pom.xml b/org.springframework.testsuite/pom.xml new file mode 100644 index 00000000000..b4cee14adcb --- /dev/null +++ b/org.springframework.testsuite/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + org.springframework + org.springframework.core + jar + Spring Core Abstractions and Utilities + 3.0.0.M1 + + + com.springsource.repository.bundles.external + SpringSource Enterprise Bundle Repository - External Bundle Releases + http://repository.springsource.com/maven/bundles/external + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + + + + + + org.apache.commons + com.springsource.org.apache.commons.logging + 1.1.1 + + + org.apache.log4j + com.springsource.org.apache.log4j + 1.2.15 + true + + + org.apache.commons + com.springsource.org.apache.commons.collections + 3.2.0 + true + + + org.aspectj + com.springsource.org.aspectj.weaver + 1.6.2.RELEASE + true + + + org.objectweb.asm + com.springsource.org.objectweb.asm.commons + 2.2.3 + true + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdvice.java new file mode 100644 index 00000000000..402625a27d0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdvice.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop; + +/** + * Simple BeforeAdvice for testing. + * + * @author Dmitriy Kopylenko + */ +public interface SimpleBeforeAdvice extends BeforeAdvice { + + void before() throws Throwable; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceAdapter.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceAdapter.java new file mode 100644 index 00000000000..8273435502c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceAdapter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop; + +import java.io.Serializable; + +import org.aopalliance.aop.Advice; +import org.aopalliance.intercept.MethodInterceptor; + +import org.springframework.aop.framework.adapter.AdvisorAdapter; + +/** + * @author Dmitriy Kopylenko + */ +public class SimpleBeforeAdviceAdapter implements AdvisorAdapter, Serializable { + + public boolean supportsAdvice(Advice advice) { + return (advice instanceof SimpleBeforeAdvice); + } + + public MethodInterceptor getInterceptor(Advisor advisor) { + SimpleBeforeAdvice advice = (SimpleBeforeAdvice) advisor.getAdvice(); + return new SimpleBeforeAdviceInterceptor(advice) ; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceImpl.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceImpl.java new file mode 100644 index 00000000000..83715314e74 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceImpl.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop; + +/** + * @author Dmitriy Kopylenko + */ +public class SimpleBeforeAdviceImpl implements SimpleBeforeAdvice { + + private int invocationCounter; + + public void before() throws Throwable { + ++invocationCounter; + } + + public int getInvocationCounter() { + return invocationCounter; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceInterceptor.java new file mode 100644 index 00000000000..d2056190e3e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/SimpleBeforeAdviceInterceptor.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * @author Dmitriy Kopylenko + */ +final class SimpleBeforeAdviceInterceptor implements MethodInterceptor { + + private SimpleBeforeAdvice advice; + + public SimpleBeforeAdviceInterceptor(SimpleBeforeAdvice advice) { + this.advice = advice; + } + + public Object invoke(MethodInvocation mi) throws Throwable { + advice.before(); + return mi.proceed(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AbstractAdviceBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AbstractAdviceBindingTests.java new file mode 100644 index 00000000000..443e736a520 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AbstractAdviceBindingTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Rod Johnson + */ +public abstract class AbstractAdviceBindingTests extends AbstractDependencyInjectionSpringContextTests { + + protected ITestBean testBeanProxy; + + protected TestBean testBeanTarget; + + public final void setTestBean(ITestBean injectedTestBean) throws Exception { + assertTrue(AopUtils.isAopProxy(injectedTestBean)); + this.testBeanProxy = injectedTestBean; + // we need the real target too, not just the proxy... + this.testBeanTarget = (TestBean) ((Advised) testBeanProxy).getTargetSource().getTarget(); + } + + // Simple test to ensure all is well with the XML file. + // Note that this implicitly tests that the arg-names binding is working. + public final void testParse() { + // Do nothing + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AdviceBindingTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AdviceBindingTestAspect.java new file mode 100644 index 00000000000..4c8476397e8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AdviceBindingTestAspect.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.aspectj.lang.JoinPoint; + +/** + * Aspect used as part of before advice binding tests. + * + * @author Adrian Colyer + */ +public class AdviceBindingTestAspect { + + protected AdviceBindingCollaborator collaborator = null; + + public void setCollaborator(AdviceBindingCollaborator aCollaborator) { + this.collaborator = aCollaborator; + } + + // "advice" methods + public void oneIntArg(int age) { + this.collaborator.oneIntArg(age); + } + + public void oneObjectArg(Object bean) { + this.collaborator.oneObjectArg(bean); + } + + public void oneIntAndOneObject(int x, Object o) { + this.collaborator.oneIntAndOneObject(x,o); + } + + public void needsJoinPoint(JoinPoint tjp) { + this.collaborator.needsJoinPoint(tjp.getSignature().getName()); + } + + public void needsJoinPointStaticPart(JoinPoint.StaticPart tjpsp) { + this.collaborator.needsJoinPointStaticPart(tjpsp.getSignature().getName()); + } + + + /** + * Collaborator interface that makes it easy to test this aspect is + * working as expected through mocking. + */ + public interface AdviceBindingCollaborator { + + void oneIntArg(int x); + void oneObjectArg(Object o); + void oneIntAndOneObject(int x, Object o); + void needsJoinPoint(String s); + void needsJoinPointStaticPart(String s); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterAdviceBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterAdviceBindingTests.java new file mode 100644 index 00000000000..f248763a2dc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterAdviceBindingTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.easymock.MockControl; + +import org.springframework.aop.aspectj.AdviceBindingTestAspect.AdviceBindingCollaborator; + +/** + * Tests for various parameter binding scenarios with before advice. + * + * @author Adrian Colyer + * @author Rod Johnson + */ +public class AfterAdviceBindingTests extends AbstractAdviceBindingTests { + + private AdviceBindingTestAspect afterAdviceAspect; + + private MockControl mockControl; + + private AdviceBindingCollaborator mockCollaborator; + + + public void setAfterAdviceAspect(AdviceBindingTestAspect anAspect) { + this.afterAdviceAspect = anAspect; + } + + protected String getConfigPath() { + return "after-advice-tests.xml"; + } + + protected void onSetUp() throws Exception { + super.onSetUp(); + mockControl = MockControl.createNiceControl(AdviceBindingCollaborator.class); + mockCollaborator = (AdviceBindingCollaborator) mockControl.getMock(); + afterAdviceAspect.setCollaborator(mockCollaborator); + } + + + public void testOneIntArg() { + mockCollaborator.oneIntArg(5); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testOneObjectArgBindingProxyWithThis() { + mockCollaborator.oneObjectArg(this.testBeanProxy); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testOneObjectArgBindingTarget() { + mockCollaborator.oneObjectArg(this.testBeanTarget); + mockControl.replay(); + testBeanProxy.getDoctor(); + mockControl.verify(); + } + + public void testOneIntAndOneObjectArgs() { + mockCollaborator.oneIntAndOneObject(5,this.testBeanProxy); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testNeedsJoinPoint() { + mockCollaborator.needsJoinPoint("getAge"); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testNeedsJoinPointStaticPart() { + mockCollaborator.needsJoinPointStaticPart("getAge"); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTestAspect.java new file mode 100644 index 00000000000..29eb3641f81 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTestAspect.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; + +/** + * @author Adrian Colyer + * @author Juergen Hoeller + */ +public class AfterReturningAdviceBindingTestAspect extends AdviceBindingTestAspect { + + private AfterReturningAdviceBindingCollaborator getCollaborator() { + return (AfterReturningAdviceBindingCollaborator) this.collaborator; + } + + public void oneString(String name) { + getCollaborator().oneString(name); + } + + public void oneTestBeanArg(TestBean bean) { + getCollaborator().oneTestBeanArg(bean); + } + + public void testBeanArrayArg(ITestBean[] beans) { + getCollaborator().testBeanArrayArg(beans); + } + + public void objectMatchNoArgs() { + getCollaborator().objectMatchNoArgs(); + } + + public void stringMatchNoArgs() { + getCollaborator().stringMatchNoArgs(); + } + + public void oneInt(int result) { + getCollaborator().oneInt(result); + } + + + interface AfterReturningAdviceBindingCollaborator extends AdviceBindingCollaborator { + + void oneString(String s); + void oneTestBeanArg(TestBean b); + void testBeanArrayArg(ITestBean[] b); + void objectMatchNoArgs(); + void stringMatchNoArgs(); + void oneInt(int result); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTests.java new file mode 100644 index 00000000000..ddf8f622d6c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterReturningAdviceBindingTests.java @@ -0,0 +1,169 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.easymock.MockControl; + +import org.springframework.aop.aspectj.AfterReturningAdviceBindingTestAspect.AfterReturningAdviceBindingCollaborator; +import org.springframework.aop.framework.Advised; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests for various parameter binding scenarios with before advice. + * + * @author Adrian Colyer + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class AfterReturningAdviceBindingTests extends AbstractDependencyInjectionSpringContextTests { + + private AfterReturningAdviceBindingTestAspect afterAdviceAspect; + + private ITestBean testBeanProxy; + + private TestBean testBeanTarget; + + private MockControl mockControl; + + private AfterReturningAdviceBindingCollaborator mockCollaborator; + + + public void setAfterReturningAdviceAspect(AfterReturningAdviceBindingTestAspect anAspect) { + this.afterAdviceAspect = anAspect; + } + + public void setTestBean(ITestBean aBean) throws Exception { + assertTrue(AopUtils.isAopProxy(aBean)); + this.testBeanProxy = aBean; + // we need the real target too, not just the proxy... + this.testBeanTarget = (TestBean) ((Advised)aBean).getTargetSource().getTarget(); + } + + protected String getConfigPath() { + return "afterReturning-advice-tests.xml"; + } + + protected void onSetUp() throws Exception { + super.onSetUp(); + mockControl = MockControl.createNiceControl(AfterReturningAdviceBindingCollaborator.class); + mockCollaborator = (AfterReturningAdviceBindingCollaborator) mockControl.getMock(); + afterAdviceAspect.setCollaborator(mockCollaborator); + } + + + // simple test to ensure all is well with the xml file + // note that this implicitly tests that the arg-names binding is working + public void testParse() { + } + + public void testOneIntArg() { + mockCollaborator.oneIntArg(5); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testOneObjectArg() { + mockCollaborator.oneObjectArg(this.testBeanProxy); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testOneIntAndOneObjectArgs() { + mockCollaborator.oneIntAndOneObject(5,this.testBeanProxy); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testNeedsJoinPoint() { + mockCollaborator.needsJoinPoint("getAge"); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testNeedsJoinPointStaticPart() { + mockCollaborator.needsJoinPointStaticPart("getAge"); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testReturningString() { + mockCollaborator.oneString("adrian"); + mockControl.replay(); + testBeanProxy.setName("adrian"); + testBeanProxy.getName(); + mockControl.verify(); + } + + public void testReturningObject() { + mockCollaborator.oneObjectArg(this.testBeanTarget); + mockControl.replay(); + testBeanProxy.returnsThis(); + mockControl.verify(); + } + + public void testReturningBean() { + mockCollaborator.oneTestBeanArg(this.testBeanTarget); + mockControl.replay(); + testBeanProxy.returnsThis(); + mockControl.verify(); + } + + public void testReturningBeanArray() { + this.testBeanTarget.setSpouse(new TestBean()); + ITestBean[] spouses = (ITestBean[]) this.testBeanTarget.getSpouses(); + mockCollaborator.testBeanArrayArg(spouses); + mockControl.replay(); + testBeanProxy.getSpouses(); + mockControl.verify(); + } + + public void testNoInvokeWhenReturningParameterTypeDoesNotMatch() { + // we need a strict mock for this... + mockControl = MockControl.createControl(AfterReturningAdviceBindingCollaborator.class); + mockCollaborator = (AfterReturningAdviceBindingCollaborator) mockControl.getMock(); + afterAdviceAspect.setCollaborator(mockCollaborator); + + mockControl.replay(); + testBeanProxy.setSpouse(this.testBeanProxy); + testBeanProxy.getSpouse(); + mockControl.verify(); + } + + public void testReturningByType() { + mockCollaborator.objectMatchNoArgs(); + mockControl.replay(); + testBeanProxy.returnsThis(); + mockControl.verify(); + } + + public void testReturningPrimitive() { + mockCollaborator.oneInt(20); + mockControl.replay(); + testBeanProxy.setAge(20); + testBeanProxy.haveBirthday(); + mockControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTestAspect.java new file mode 100644 index 00000000000..6f202654100 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTestAspect.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj; + +/** + * Aspect used as part of before advice binding tests. + * @author Adrian Colyer + */ +public class AfterThrowingAdviceBindingTestAspect { + + // collaborator interface that makes it easy to test this aspect is + // working as expected through mocking. + public interface AfterThrowingAdviceBindingCollaborator { + void noArgs(); + void oneThrowable(Throwable t); + void oneRuntimeException(RuntimeException re); + void noArgsOnThrowableMatch(); + void noArgsOnRuntimeExceptionMatch(); + } + + protected AfterThrowingAdviceBindingCollaborator collaborator = null; + + public void setCollaborator(AfterThrowingAdviceBindingCollaborator aCollaborator) { + this.collaborator = aCollaborator; + } + + public void noArgs() { + this.collaborator.noArgs(); + } + + public void oneThrowable(Throwable t) { + this.collaborator.oneThrowable(t); + } + + public void oneRuntimeException(RuntimeException ex) { + this.collaborator.oneRuntimeException(ex); + } + + public void noArgsOnThrowableMatch() { + this.collaborator.noArgsOnThrowableMatch(); + } + + public void noArgsOnRuntimeExceptionMatch() { + this.collaborator.noArgsOnRuntimeExceptionMatch(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTests.java new file mode 100644 index 00000000000..a4a9b24fdac --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AfterThrowingAdviceBindingTests.java @@ -0,0 +1,147 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.easymock.MockControl; + +import org.springframework.aop.aspectj.AfterThrowingAdviceBindingTestAspect.AfterThrowingAdviceBindingCollaborator; +import org.springframework.beans.ITestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests for various parameter binding scenarios with before advice. + * + * @author Adrian Colyer + */ +public class AfterThrowingAdviceBindingTests extends AbstractDependencyInjectionSpringContextTests { + + private AfterThrowingAdviceBindingTestAspect afterThrowingAdviceAspect; + + private ITestBean testBean; + + private MockControl mockControl; + + private AfterThrowingAdviceBindingCollaborator mockCollaborator; + + + public void setAfterAdviceAspect(AfterThrowingAdviceBindingTestAspect anAspect) { + this.afterThrowingAdviceAspect = anAspect; + } + + public void setTestBean(ITestBean aBean) throws Exception { + this.testBean = aBean; + } + + protected String getConfigPath() { + return "afterThrowing-advice-tests.xml"; + } + + protected void onSetUp() throws Exception { + mockControl = MockControl.createNiceControl(AfterThrowingAdviceBindingCollaborator.class); + mockCollaborator = (AfterThrowingAdviceBindingCollaborator) mockControl.getMock(); + afterThrowingAdviceAspect.setCollaborator(mockCollaborator); + } + + + // Simple test to ensure all is well with the XML file. + // Note that this implicitly tests that the arg-names binding is working. + public void testParse() { + } + + public void testSimpleAfterThrowing() { + mockCollaborator.noArgs(); + mockControl.replay(); + try { + this.testBean.exceptional(new Throwable()); + fail("should throw exception"); + } catch (Throwable t) { + // no-op + } + mockControl.verify(); + } + + public void testAfterThrowingWithBinding() { + Throwable t = new Throwable(); + mockCollaborator.oneThrowable(t); + mockControl.replay(); + try { + this.testBean.exceptional(t); + fail("should throw exception"); + } catch (Throwable x) { + // no-op + } + mockControl.verify(); + } + + public void testAfterThrowingWithNamedTypeRestriction() { + Throwable t = new Throwable(); + // need a strict mock for this test... + mockControl = MockControl.createControl(AfterThrowingAdviceBindingCollaborator.class); + mockCollaborator = (AfterThrowingAdviceBindingCollaborator) mockControl.getMock(); + afterThrowingAdviceAspect.setCollaborator(mockCollaborator); + + mockCollaborator.noArgs(); + mockCollaborator.oneThrowable(t); + mockCollaborator.noArgsOnThrowableMatch(); + mockControl.replay(); + try { + this.testBean.exceptional(t); + fail("should throw exception"); + } catch (Throwable x) { + // no-op + } + mockControl.verify(); + } + + public void testAfterThrowingWithRuntimeExceptionBinding() { + RuntimeException ex = new RuntimeException(); + mockCollaborator.oneRuntimeException(ex); + mockControl.replay(); + try { + this.testBean.exceptional(ex); + fail("should throw exception"); + } catch (Throwable x) { + // no-op + } + mockControl.verify(); + } + + public void testAfterThrowingWithTypeSpecified() { + mockCollaborator.noArgsOnThrowableMatch(); + mockControl.replay(); + try { + this.testBean.exceptional(new Throwable()); + fail("should throw exception"); + } catch (Throwable t) { + // no-op + } + mockControl.verify(); + } + + public void testAfterThrowingWithRuntimeTypeSpecified() { + mockCollaborator.noArgsOnRuntimeExceptionMatch(); + mockControl.replay(); + try { + this.testBean.exceptional(new RuntimeException()); + fail("should throw exception"); + } catch (Throwable t) { + // no-op + } + mockControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTestAspect.java new file mode 100644 index 00000000000..58ab8855909 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTestAspect.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.aspectj.lang.ProceedingJoinPoint; + +/** + * Aspect used as part of before advice binding tests. + * + * @author Adrian Colyer + */ +public class AroundAdviceBindingTestAspect { + + private AroundAdviceBindingCollaborator collaborator = null; + + public void setCollaborator(AroundAdviceBindingCollaborator aCollaborator) { + this.collaborator = aCollaborator; + } + + // "advice" methods + public void oneIntArg(ProceedingJoinPoint pjp, int age) throws Throwable { + this.collaborator.oneIntArg(age); + pjp.proceed(); + } + + public int oneObjectArg(ProceedingJoinPoint pjp, Object bean) throws Throwable { + this.collaborator.oneObjectArg(bean); + return ((Integer) pjp.proceed()).intValue(); + } + + public void oneIntAndOneObject(ProceedingJoinPoint pjp, int x , Object o) throws Throwable { + this.collaborator.oneIntAndOneObject(x,o); + pjp.proceed(); + } + + public int justJoinPoint(ProceedingJoinPoint pjp) throws Throwable { + this.collaborator.justJoinPoint(pjp.getSignature().getName()); + return ((Integer) pjp.proceed()).intValue(); + } + + + /** + * Collaborator interface that makes it easy to test this aspect + * is working as expected through mocking. + */ + public interface AroundAdviceBindingCollaborator { + + void oneIntArg(int x); + + void oneObjectArg(Object o); + + void oneIntAndOneObject(int x, Object o); + + void justJoinPoint(String s); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTests.java new file mode 100644 index 00000000000..5a4f8409912 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceBindingTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.easymock.MockControl; + +import org.springframework.aop.aspectj.AroundAdviceBindingTestAspect.AroundAdviceBindingCollaborator; + +/** + * Tests for various parameter binding scenarios with before advice. + * + * @author Adrian Colyer + */ +public class AroundAdviceBindingTests extends AbstractAdviceBindingTests { + + private MockControl mockControl; + + private AroundAdviceBindingCollaborator mockCollaborator; + + private AroundAdviceBindingTestAspect aroundAdviceAspect; + + + public void setAroundAdviceAspect(AroundAdviceBindingTestAspect anAspect) { + this.aroundAdviceAspect = anAspect; + } + + protected String getConfigPath() { + return "around-advice-tests.xml"; + } + + protected void onSetUp() throws Exception { + super.onSetUp(); + mockControl = MockControl.createNiceControl(AroundAdviceBindingCollaborator.class); + mockCollaborator = (AroundAdviceBindingCollaborator) mockControl.getMock(); + aroundAdviceAspect.setCollaborator(mockCollaborator); + } + + + public void testOneIntArg() { + mockCollaborator.oneIntArg(5); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testOneObjectArgBoundToTarget() { + mockCollaborator.oneObjectArg(this.testBeanTarget); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testOneIntAndOneObjectArgs() { + mockCollaborator.oneIntAndOneObject(5, this.testBeanProxy); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testJustJoinPoint() { + mockCollaborator.justJoinPoint("getAge"); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceCircularTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceCircularTests.java new file mode 100644 index 00000000000..7294ebb1be9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AroundAdviceCircularTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.aop.support.AopUtils; + +/** + * @author Juergen Hoeller + */ +public class AroundAdviceCircularTests extends AroundAdviceBindingTests { + + protected String getConfigPath() { + return "around-advice-circular-tests.xml"; + } + + public void testBothBeansAreProxies() { + Object tb = getApplicationContext().getBean("testBean"); + assertTrue(AopUtils.isAopProxy(tb)); + Object tb2 = getApplicationContext().getBean("testBean2"); + assertTrue(AopUtils.isAopProxy(tb2)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java new file mode 100644 index 00000000000..f670edfbc52 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java @@ -0,0 +1,140 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.beans.ITestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Adrian Colyer + */ +public class AspectAndAdvicePrecedenceTests extends AbstractDependencyInjectionSpringContextTests { + + private PrecedenceTestAspect highPrecedenceAspect; + private PrecedenceTestAspect lowPrecedenceAspect; + private SimpleSpringBeforeAdvice lowPrecedenceSpringAdvice; + private SimpleSpringBeforeAdvice highPrecedenceSpringAdvice; + private ITestBean testBean; + + + public AspectAndAdvicePrecedenceTests() { + setAutowireMode(AUTOWIRE_BY_NAME); + } + + public void setHighPrecedenceAspect(PrecedenceTestAspect highPrecedenceAspect) { + this.highPrecedenceAspect = highPrecedenceAspect; + } + + public void setLowPrecedenceAspect(PrecedenceTestAspect lowPrecedenceAspect) { + this.lowPrecedenceAspect = lowPrecedenceAspect; + } + + public void setLowPrecedenceSpringAdvice(SimpleSpringBeforeAdvice lowPrecedenceSpringAdvice) { + this.lowPrecedenceSpringAdvice = lowPrecedenceSpringAdvice; + } + + public void setHighPrecedenceSpringAdvice(SimpleSpringBeforeAdvice highPrecedenceSpringAdvice) { + this.highPrecedenceSpringAdvice = highPrecedenceSpringAdvice; + } + + public void setTestBean(ITestBean testBean) { + this.testBean = testBean; + } + + protected String getConfigPath() { + return "advice-precedence-tests.xml"; + } + + + // ========== end of test case set up, start of tests proper =================== + + public void testAdviceOrder() { + PrecedenceTestAspect.Collaborator collaborator = new PrecedenceVerifyingCollaborator(); + this.highPrecedenceAspect.setCollaborator(collaborator); + this.lowPrecedenceAspect.setCollaborator(collaborator); + this.highPrecedenceSpringAdvice.setCollaborator(collaborator); + this.lowPrecedenceSpringAdvice.setCollaborator(collaborator); + this.testBean.getAge(); + } + + + private static class PrecedenceVerifyingCollaborator implements PrecedenceTestAspect.Collaborator { + + private static final String[] EXPECTED = { + // this order confirmed by running the same aspects (minus the Spring AOP advisors) + // through AspectJ... + "beforeAdviceOne(highPrecedenceAspect)", // 1 + "beforeAdviceTwo(highPrecedenceAspect)", // 2 + "aroundAdviceOne(highPrecedenceAspect)", // 3, before proceed + "aroundAdviceTwo(highPrecedenceAspect)", // 4, before proceed + "beforeAdviceOne(highPrecedenceSpringAdvice)", // 5 + "beforeAdviceOne(lowPrecedenceSpringAdvice)", // 6 + "beforeAdviceOne(lowPrecedenceAspect)", // 7 + "beforeAdviceTwo(lowPrecedenceAspect)", // 8 + "aroundAdviceOne(lowPrecedenceAspect)", // 9, before proceed + "aroundAdviceTwo(lowPrecedenceAspect)", // 10, before proceed + "aroundAdviceTwo(lowPrecedenceAspect)", // 11, after proceed + "aroundAdviceOne(lowPrecedenceAspect)", // 12, after proceed + "afterAdviceOne(lowPrecedenceAspect)", // 13 + "afterAdviceTwo(lowPrecedenceAspect)", // 14 + "aroundAdviceTwo(highPrecedenceAspect)", // 15, after proceed + "aroundAdviceOne(highPrecedenceAspect)", // 16, after proceed + "afterAdviceOne(highPrecedenceAspect)", // 17 + "afterAdviceTwo(highPrecedenceAspect)" // 18 + }; + + private int adviceInvocationNumber = 0; + + private void checkAdvice(String whatJustHappened) { + //System.out.println("[" + adviceInvocationNumber + "] " + whatJustHappened + " ==> " + EXPECTED[adviceInvocationNumber]); + if (adviceInvocationNumber > (EXPECTED.length - 1)) { + fail("Too many advice invocations, expecting " + EXPECTED.length + + " but had " + adviceInvocationNumber); + } + String expecting = EXPECTED[adviceInvocationNumber++]; + if (!whatJustHappened.equals(expecting)) { + fail("Expecting '" + expecting + "' on advice invocation " + adviceInvocationNumber + + " but got '" + whatJustHappened + "'"); + } + } + + public void beforeAdviceOne(String beanName) { + checkAdvice("beforeAdviceOne(" + beanName + ")"); + } + + public void beforeAdviceTwo(String beanName) { + checkAdvice("beforeAdviceTwo(" + beanName + ")"); + } + + public void aroundAdviceOne(String beanName) { + checkAdvice("aroundAdviceOne(" + beanName + ")"); + } + + public void aroundAdviceTwo(String beanName) { + checkAdvice("aroundAdviceTwo(" + beanName + ")"); + } + + public void afterAdviceOne(String beanName) { + checkAdvice("afterAdviceOne(" + beanName + ")"); + } + + public void afterAdviceTwo(String beanName) { + checkAdvice("afterAdviceTwo(" + beanName + ")"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java new file mode 100644 index 00000000000..b061363a1e2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java @@ -0,0 +1,298 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import junit.framework.TestCase; +import org.aspectj.lang.JoinPoint; +import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException; + +import java.lang.reflect.Method; + +/** + * Unit tests for the {@link AspectJAdviceParameterNameDiscoverer} class. + *

+ *

See also TigerAspectJAdviceParameterNameDiscovererTests in + * the 'tiger' tree for tests relating to annotations. + * + * @author Adrian Colyer + */ +public class AspectJAdviceParameterNameDiscovererTests extends TestCase { + + // methods to discover parameter names for + public void noArgs() { + } + + public void tjp(JoinPoint jp) { + } + + public void tjpsp(JoinPoint.StaticPart tjpsp) { + } + + public void twoJoinPoints(JoinPoint jp1, JoinPoint jp2) { + } + + public void oneThrowable(Exception ex) { + } + + public void jpAndOneThrowable(JoinPoint jp, Exception ex) { + } + + public void jpAndTwoThrowables(JoinPoint jp, Exception ex, Error err) { + } + + public void oneObject(Object x) { + } + + public void twoObjects(Object x, Object y) { + } + + public void onePrimitive(int x) { + } + + public void oneObjectOnePrimitive(Object x, int y) { + } + + public void oneThrowableOnePrimitive(Throwable x, int y) { + } + + public void theBigOne(JoinPoint jp, Throwable x, int y, Object foo) { + } + + + public void testNoArgs() { + assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]); + } + + public void testJoinPointOnly() { + assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[]{"thisJoinPoint"}); + } + + public void testJoinPointStaticPartOnly() { + assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[]{"thisJoinPointStaticPart"}); + } + + public void testTwoJoinPoints() { + assertException(getMethod("twoJoinPoints"), "foo()", IllegalStateException.class, "Failed to bind all argument names: 1 argument(s) could not be bound"); + } + + public void testOneThrowable() { + assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[]{"ex"}); + } + + public void testOneJPAndOneThrowable() { + assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[]{"thisJoinPoint", "ex"}); + } + + public void testOneJPAndTwoThrowables() { + assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class, + "Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2"); + } + + public void testThrowableNoCandidates() { + assertException(getMethod("noArgs"), "foo()", null, "ex", IllegalStateException.class, + "Not enough arguments in method to satisfy binding of returning and throwing variables"); + } + + public void testReturning() { + assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[]{"obj"}); + } + + public void testAmbiguousReturning() { + assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class, + "Binding of returning parameter 'obj' is ambiguous, there are 2 candidates."); + } + + public void testReturningNoCandidates() { + assertException(getMethod("noArgs"), "foo()", "obj", null, IllegalStateException.class, + "Not enough arguments in method to satisfy binding of returning and throwing variables"); + } + + public void testThisBindingOneCandidate() { + assertParameterNames(getMethod("oneObject"), "this(x)", new String[]{"x"}); + } + + public void testThisBindingWithAlternateTokenizations() { + assertParameterNames(getMethod("oneObject"), "this( x )", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "this( x)", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "this (x )", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "this(x )", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[]{"x"}); + } + + public void testThisBindingTwoCandidates() { + assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class, + "Found 2 candidate this(), target() or args() variables but only one unbound argument slot"); + } + + public void testThisBindingWithBadPointcutExpressions() { + assertException(getMethod("oneObject"), "this(", IllegalStateException.class, + "Failed to bind all argument names: 1 argument(s) could not be bound"); + assertException(getMethod("oneObject"), "this(x && foo()", IllegalStateException.class, + "Failed to bind all argument names: 1 argument(s) could not be bound"); + } + + public void testTargetBindingOneCandidate() { + assertParameterNames(getMethod("oneObject"), "target(x)", new String[]{"x"}); + } + + public void testTargetBindingWithAlternateTokenizations() { + assertParameterNames(getMethod("oneObject"), "target( x )", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "target( x)", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "target (x )", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "target(x )", new String[]{"x"}); + assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[]{"x"}); + } + + public void testTargetBindingTwoCandidates() { + assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class, + "Found 2 candidate this(), target() or args() variables but only one unbound argument slot"); + } + + public void testTargetBindingWithBadPointcutExpressions() { + assertException(getMethod("oneObject"), "target(", IllegalStateException.class, + "Failed to bind all argument names: 1 argument(s) could not be bound"); + assertException(getMethod("oneObject"), "target(x && foo()", IllegalStateException.class, + "Failed to bind all argument names: 1 argument(s) could not be bound"); + } + + public void testArgsBindingOneObject() { + assertParameterNames(getMethod("oneObject"), "args(x)", new String[]{"x"}); + } + + public void testArgsBindingOneObjectTwoCandidates() { + assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class, + "Found 2 candidate this(), target() or args() variables but only one unbound argument slot"); + } + + public void testAmbiguousArgsBinding() { + assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class, + "Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them"); + } + + public void testArgsOnePrimitive() { + assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[]{"count"}); + } + + public void testArgsOnePrimitiveOneObject() { + assertException(getMethod("oneObjectOnePrimitive"), "args(count,obj)", AmbiguousBindingException.class, + "Found 2 candidate variable names but only one candidate binding slot when matching primitive args"); + } + + public void testThisAndPrimitive() { + assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)", new String[]{"obj", "count"}); + } + + public void testTargetAndPrimitive() { + assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)", new String[]{"obj", "count"}); + } + + public void testThrowingAndPrimitive() { + assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex", new String[]{"ex", "count"}); + } + + public void testAllTogetherNow() { + assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex", new String[]{"thisJoinPoint", "ex", "x", "foo"}); + } + + public void testReferenceBinding() { + assertParameterNames(getMethod("onePrimitive"),"somepc(foo)",new String[] {"foo"}); + } + + public void testReferenceBindingWithAlternateTokenizations() { + assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)",new String[] {"foo"}); + assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )",new String[] {"foo"}); + assertParameterNames(getMethod("onePrimitive"),"somepc( foo)",new String[] {"foo"}); + } + + + protected Method getMethod(String name) { + // assumes no overloading of test methods... + Method[] candidates = this.getClass().getMethods(); + for (int i = 0; i < candidates.length; i++) { + if (candidates[i].getName().equals(name)) { + return candidates[i]; + } + } + fail("Bad test specification, no method '" + name + "' found in test class"); + return null; + } + + protected void assertParameterNames(Method m, String pointcut, String[] parameterNames) { + assertParameterNames(m, pointcut, null, null, parameterNames); + } + + protected void assertParameterNames(Method m, String pointcut, String returning, String throwing, String[] parameterNames) { + assertEquals("bad test specification, must have same number of parameter names as method arguments", + m.getParameterTypes().length, parameterNames.length); + + AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut); + discoverer.setRaiseExceptions(true); + discoverer.setReturningName(returning); + discoverer.setThrowingName(throwing); + String[] discoveredNames = discoverer.getParameterNames(m); + + String formattedExpectedNames = format(parameterNames); + String formattedActualNames = format(discoveredNames); + + assertEquals("Expecting " + parameterNames.length + " parameter names in return set '" + + formattedExpectedNames + "', but found " + discoveredNames.length + + " '" + formattedActualNames + "'", + parameterNames.length, discoveredNames.length); + + for (int i = 0; i < discoveredNames.length; i++) { + assertNotNull("Parameter names must never be null", discoveredNames[i]); + assertEquals("Expecting parameter " + i + " to be named '" + + parameterNames[i] + "' but was '" + discoveredNames[i] + "'", + parameterNames[i], discoveredNames[i]); + } + } + + protected void assertException(Method m, String pointcut, Class exceptionType, String message) { + assertException(m, pointcut, null, null, exceptionType, message); + } + + protected void assertException(Method m, String pointcut, String returning, String throwing, Class exceptionType, String message) { + AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut); + discoverer.setRaiseExceptions(true); + discoverer.setReturningName(returning); + discoverer.setThrowingName(throwing); + + try { + discoverer.getParameterNames(m); + fail("Expecting " + exceptionType.getName() + " with message '" + message + "'"); + } catch (RuntimeException expected) { + assertEquals("Expecting exception of type " + exceptionType.getName(), + exceptionType, expected.getClass()); + assertEquals("Exception message does not match expected", message, expected.getMessage()); + } + } + + + private static String format(String[] names) { + StringBuffer sb = new StringBuffer(); + sb.append("("); + for (int i = 0; i < names.length; i++) { + sb.append(names[i]); + if ((i + 1) < names.length) { + sb.append(","); + } + } + sb.append(")"); + return sb.toString(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutAdvisorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutAdvisorTests.java new file mode 100644 index 00000000000..cdfcf2684c2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutAdvisorTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.beans.ITestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AspectJExpressionPointcutAdvisorTests extends AbstractDependencyInjectionSpringContextTests { + + private ITestBean testBean; + + private CallCountingInterceptor interceptor; + + + public void setTestBean(ITestBean testBean) { + this.testBean = testBean; + } + + public void setInterceptor(CallCountingInterceptor interceptor) { + this.interceptor = interceptor; + } + + protected String getConfigPath() { + return "aspectj.xml"; + } + + protected void onSetUp() throws Exception { + interceptor.reset(); + } + + + public void testPointcutting() throws Exception { + assertEquals("Count should be 0", 0, interceptor.getCount()); + testBean.getSpouses(); + assertEquals("Count should be 1", 1, interceptor.getCount()); + testBean.getSpouse(); + assertEquals("Count should be 1", 1, interceptor.getCount()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java new file mode 100644 index 00000000000..a050e5bf342 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java @@ -0,0 +1,332 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.aspectj.weaver.tools.PointcutExpression; +import org.aspectj.weaver.tools.PointcutPrimitive; +import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException; +import org.springframework.aop.ClassFilter; +import org.springframework.aop.MethodMatcher; +import org.springframework.aop.Pointcut; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.beans.IOther; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; + +/** + * @author Rob Harrop + * @author Rod Johnson + */ +public class AspectJExpressionPointcutTests extends TestCase { + + public static final String MATCH_ALL_METHODS = "execution(* *(..))"; + + private Method getAge; + + private Method setAge; + + private Method setSomeNumber; + + private Method isPostProcessed; + + public void testMatchExplicit() { + String expression = "execution(int org.springframework.beans.TestBean.getAge())"; + + Pointcut pointcut = getPointcut(expression); + ClassFilter classFilter = pointcut.getClassFilter(); + MethodMatcher methodMatcher = pointcut.getMethodMatcher(); + + assertMatchesTestBeanClass(classFilter); + + // not currently testable in a reliable fashion + //assertDoesNotMatchStringClass(classFilter); + + assertFalse("Should not be a runtime match", methodMatcher.isRuntime()); + assertMatchesGetAge(methodMatcher); + assertFalse("Expression should match setAge() method", methodMatcher.matches(setAge, TestBean.class)); + } + + + public void setUp() throws NoSuchMethodException { + getAge = TestBean.class.getMethod("getAge", null); + setAge = TestBean.class.getMethod("setAge", new Class[]{int.class}); + setSomeNumber = TestBean.class.getMethod("setSomeNumber", new Class[]{Number.class}); + isPostProcessed = TestBean.class.getMethod("isPostProcessed", (Class[]) null); + } + + + + public void testMatchWithTypePattern() throws Exception { + String expression = "execution(* *..TestBean.*Age(..))"; + + Pointcut pointcut = getPointcut(expression); + ClassFilter classFilter = pointcut.getClassFilter(); + MethodMatcher methodMatcher = pointcut.getMethodMatcher(); + + assertMatchesTestBeanClass(classFilter); + + // not currently testable in a reliable fashion + //assertDoesNotMatchStringClass(classFilter); + + assertFalse("Should not be a runtime match", methodMatcher.isRuntime()); + assertMatchesGetAge(methodMatcher); + assertTrue("Expression should match setAge(int) method", methodMatcher.matches(setAge, TestBean.class)); + } + + + public void testThis() throws SecurityException, NoSuchMethodException{ + testThisOrTarget("this"); + } + + public void testTarget() throws SecurityException, NoSuchMethodException { + testThisOrTarget("target"); + } + + public static class OtherIOther implements IOther { + + public void absquatulate() { + // Empty + } + + } + + /** + * This and target are equivalent. Really instanceof pointcuts. + * @throws Exception + * @param which this or target + * @throws NoSuchMethodException + * @throws SecurityException + */ + private void testThisOrTarget(String which) throws SecurityException, NoSuchMethodException { + String matchesTestBean = which + "(org.springframework.beans.TestBean)"; + String matchesIOther = which + "(org.springframework.beans.IOther)"; + AspectJExpressionPointcut testBeanPc = new AspectJExpressionPointcut(); + testBeanPc.setExpression(matchesTestBean); + + AspectJExpressionPointcut iOtherPc = new AspectJExpressionPointcut(); + iOtherPc.setExpression(matchesIOther); + + assertTrue(testBeanPc.matches(TestBean.class)); + assertTrue(testBeanPc.matches(getAge, TestBean.class)); + assertTrue(iOtherPc.matches(OtherIOther.class.getMethod("absquatulate", null), + OtherIOther.class)); + + assertFalse(testBeanPc.matches(OtherIOther.class.getMethod("absquatulate", null), + OtherIOther.class)); + } + + public void testWithinRootPackage() throws SecurityException, NoSuchMethodException { + testWithinPackage(false); + } + + public void testWithinRootAndSubpackages() throws SecurityException, NoSuchMethodException { + testWithinPackage(true); + } + + private void testWithinPackage(boolean matchSubpackages) throws SecurityException, NoSuchMethodException { + String withinBeansPackage = "within(org.springframework.beans."; + // Subpackages are matched by ** + if (matchSubpackages) { + withinBeansPackage += "."; + } + withinBeansPackage = withinBeansPackage + "*)"; + AspectJExpressionPointcut withinBeansPc = new AspectJExpressionPointcut(); + withinBeansPc.setExpression(withinBeansPackage); + + assertTrue(withinBeansPc.matches(TestBean.class)); + assertTrue(withinBeansPc.matches(getAge, TestBean.class)); + assertEquals(matchSubpackages, withinBeansPc.matches(BeanFactory.class)); + assertEquals(matchSubpackages, withinBeansPc.matches( + DefaultListableBeanFactory.class.getMethod("getBeanDefinitionCount", null), + DefaultListableBeanFactory.class)); + assertFalse(withinBeansPc.matches(String.class)); + assertFalse(withinBeansPc.matches(OtherIOther.class.getMethod("absquatulate", null), + OtherIOther.class)); + } + + public void testFriendlyErrorOnNoLocationClassMatching() { + AspectJExpressionPointcut pc = new AspectJExpressionPointcut(); + try { + pc.matches(ITestBean.class); + fail(); + } + catch (IllegalStateException ex) { + assertTrue(ex.getMessage().indexOf("expression") != -1); + } + } + + public void testFriendlyErrorOnNoLocation2ArgMatching() { + AspectJExpressionPointcut pc = new AspectJExpressionPointcut(); + try { + pc.matches(getAge, ITestBean.class); + fail(); + } + catch (IllegalStateException ex) { + assertTrue(ex.getMessage().indexOf("expression") != -1); + } + } + + public void testFriendlyErrorOnNoLocation3ArgMatching() { + AspectJExpressionPointcut pc = new AspectJExpressionPointcut(); + try { + pc.matches(getAge, ITestBean.class, (Object[]) null); + fail(); + } + catch (IllegalStateException ex) { + assertTrue(ex.getMessage().indexOf("expression") != -1); + } + } + + + public void testMatchWithArgs() throws Exception { + String expression = "execution(void org.springframework.beans.TestBean.setSomeNumber(Number)) && args(Double)"; + + Pointcut pointcut = getPointcut(expression); + ClassFilter classFilter = pointcut.getClassFilter(); + MethodMatcher methodMatcher = pointcut.getMethodMatcher(); + + assertMatchesTestBeanClass(classFilter); + + // not currently testable in a reliable fashion + //assertDoesNotMatchStringClass(classFilter); + + assertTrue("Should match with setSomeNumber with Double input", + methodMatcher.matches(setSomeNumber, TestBean.class, new Object[]{new Double(12)})); + assertFalse("Should not match setSomeNumber with Integer input", + methodMatcher.matches(setSomeNumber, TestBean.class, new Object[]{new Integer(11)})); + assertFalse("Should not match getAge", methodMatcher.matches(getAge, TestBean.class, null)); + assertTrue("Should be a runtime match", methodMatcher.isRuntime()); + } + + public void testSimpleAdvice() { + String expression = "execution(int org.springframework.beans.TestBean.getAge())"; + + CallCountingInterceptor interceptor = new CallCountingInterceptor(); + + TestBean testBean = getAdvisedProxy(expression, interceptor); + + assertEquals("Calls should be 0", 0, interceptor.getCount()); + + testBean.getAge(); + + assertEquals("Calls should be 1", 1, interceptor.getCount()); + + testBean.setAge(90); + + assertEquals("Calls should still be 1", 1, interceptor.getCount()); + } + + public void testDynamicMatchingProxy() { + String expression = "execution(void org.springframework.beans.TestBean.setSomeNumber(Number)) && args(Double)"; + + CallCountingInterceptor interceptor = new CallCountingInterceptor(); + + TestBean testBean = getAdvisedProxy(expression, interceptor); + + assertEquals("Calls should be 0", 0, interceptor.getCount()); + + testBean.setSomeNumber(new Double(30)); + + assertEquals("Calls should be 1", 1, interceptor.getCount()); + + testBean.setSomeNumber(new Integer(90)); + + assertEquals("Calls should be 1", 1, interceptor.getCount()); + } + + public void testInvalidExpression() { + String expression = "execution(void org.springframework.beans.TestBean.setSomeNumber(Number) && args(Double)"; + + try { + getPointcut(expression).getClassFilter(); // call to getClassFilter forces resolution + fail("Invalid expression should throw IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + assertTrue(true); + System.out.println(ex.getMessage()); + } + } + + private TestBean getAdvisedProxy(String pointcutExpression, CallCountingInterceptor interceptor) { + TestBean target = new TestBean(); + + Pointcut pointcut = getPointcut(pointcutExpression); + + DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); + advisor.setAdvice(interceptor); + advisor.setPointcut(pointcut); + + ProxyFactory pf = new ProxyFactory(); + pf.setTarget(target); + pf.addAdvisor(advisor); + + return (TestBean) pf.getProxy(); + } + + private void assertMatchesGetAge(MethodMatcher methodMatcher) { + assertTrue("Expression should match getAge() method", methodMatcher.matches(getAge, TestBean.class)); + } + + private void assertMatchesTestBeanClass(ClassFilter classFilter) { + assertTrue("Expression should match TestBean class", classFilter.matches(TestBean.class)); + } + + private void assertDoesNotMatchStringClass(ClassFilter classFilter) { + assertFalse("Expression should not match String class", classFilter.matches(String.class)); + } + + public void testWithUnsupportedPointcutPrimitive() throws Exception { + String expression = "call(int org.springframework.beans.TestBean.getAge())"; + + try { + getPointcut(expression).getClassFilter(); // call to getClassFilter forces resolution... + fail("Should not support call pointcuts"); + } + catch (UnsupportedPointcutPrimitiveException ex) { + assertEquals("Should not support call pointcut", PointcutPrimitive.CALL, ex.getUnsupportedPrimitive()); + } + + } + + public void testAndSubstitution() { + Pointcut pc = getPointcut("execution(* *(..)) and args(String)"); + PointcutExpression expr = + ((AspectJExpressionPointcut) pc).getPointcutExpression(); + assertEquals("execution(* *(..)) && args(String)",expr.getPointcutExpression()); + } + + public void testMultipleAndSubstitutions() { + Pointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)"); + PointcutExpression expr = + ((AspectJExpressionPointcut) pc).getPointcutExpression(); + assertEquals("execution(* *(..)) && args(String) && this(Object)",expr.getPointcutExpression()); + } + + private Pointcut getPointcut(String expression) { + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(expression); + return pointcut; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AuthenticationLogger.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AuthenticationLogger.java new file mode 100644 index 00000000000..d3d46b30c9a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/AuthenticationLogger.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 13-Feb-2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj; + +/** + * Used by before-advice-tests.xml + * @author Adrian Colyer + * @since 2.0 + */ +public class AuthenticationLogger { + + public void logAuthenticationAttempt(String username) { + System.out.println("User [" + username + "] attempting to authenticate"); + } + +} + +class SecurityManager { + public boolean authenticate(String username, String password) { + return false; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNameAwareMixin.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNameAwareMixin.java new file mode 100644 index 00000000000..1bc6e9c22dd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNameAwareMixin.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 15 Nov 2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj; + +import org.springframework.beans.factory.BeanNameAware; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class BeanNameAwareMixin implements BeanNameAware { + + private String beanName; + + /* (non-Javadoc) + * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String) + */ + public void setBeanName(String name) { + this.beanName = name; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java new file mode 100644 index 00000000000..df40ef37bdc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; + +/** + * Tests for matching of bean() pointcut designator. + * + * @author Ramnivas Laddad + */ +public class BeanNamePointcutMatchingTests extends TestCase { + + public void testMatchingPointcuts() { + assertMatch("someName", "bean(someName)"); + + // Spring bean names are less restrictive compared to AspectJ names (methods, types etc.) + // MVC Controller-kind + assertMatch("someName/someOtherName", "bean(someName/someOtherName)"); + assertMatch("someName/foo/someOtherName", "bean(someName/*/someOtherName)"); + assertMatch("someName/foo/bar/someOtherName", "bean(someName/*/someOtherName)"); + assertMatch("someName/*/**", "bean(someName/*)"); + // JMX-kind + assertMatch("service:name=traceService", "bean(service:name=traceService)"); + assertMatch("service:name=traceService", "bean(service:name=*)"); + assertMatch("service:name=traceService", "bean(*:name=traceService)"); + + // Wildcards + assertMatch("someName", "bean(*someName)"); + assertMatch("someName", "bean(*Name)"); + assertMatch("someName", "bean(*)"); + assertMatch("someName", "bean(someName*)"); + assertMatch("someName", "bean(some*)"); + assertMatch("someName", "bean(some*Name)"); + assertMatch("someName", "bean(*some*Name*)"); + assertMatch("someName", "bean(*s*N*)"); + + // Or, and, not expressions + assertMatch("someName", "bean(someName) || bean(someOtherName)"); + assertMatch("someOtherName", "bean(someName) || bean(someOtherName)"); + + assertMatch("someName", "!bean(someOtherName)"); + + assertMatch("someName", "bean(someName) || !bean(someOtherName)"); + assertMatch("someName", "bean(someName) && !bean(someOtherName)"); + } + + public void testNonMatchingPointcuts() { + assertMisMatch("someName", "bean(someNamex)"); + assertMisMatch("someName", "bean(someX*Name)"); + + // And, not expressions + assertMisMatch("someName", "bean(someName) && bean(someOtherName)"); + assertMisMatch("someName", "!bean(someName)"); + assertMisMatch("someName", "!bean(someName) && bean(someOtherName)"); + assertMisMatch("someName", "!bean(someName) || bean(someOtherName)"); + } + + private void assertMatch(String beanName, String pcExpression) { + assertTrue("Unexpected mismatch for bean \"" + beanName + "\" for pcExpression \"" + pcExpression + "\"", + matches(beanName, pcExpression)); + } + + private void assertMisMatch(String beanName, String pcExpression) { + assertFalse("Unexpected match for bean \"" + beanName + "\" for pcExpression \"" + pcExpression + "\"", + matches(beanName, pcExpression)); + } + + private static boolean matches(final String beanName, String pcExpression) { + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut() { + protected String getCurrentProxiedBeanName() { + return beanName; + } + }; + pointcut.setExpression(pcExpression); + return pointcut.matches(TestBean.class); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutTests.java new file mode 100644 index 00000000000..7935a1777b9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import java.lang.reflect.Method; +import java.util.Map; + +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.framework.Advised; +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Test for correct application of the bean() PCD for XML-based AspectJ aspects. + * + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +public class BeanNamePointcutTests extends AbstractDependencyInjectionSpringContextTests { + + protected ITestBean testBean1; + protected ITestBean testBean2; + protected ITestBean testBeanContainingNestedBean; + protected Map testFactoryBean1; + protected Map testFactoryBean2; + protected Counter counterAspect; + + protected ITestBean interceptThis; + protected ITestBean dontInterceptThis; + protected TestInterceptor testInterceptor; + + + public BeanNamePointcutTests() { + setPopulateProtectedVariables(true); + } + + protected String getConfigPath() { + return "bean-name-pointcut-tests.xml"; + } + + protected void onSetUp() throws Exception { + this.counterAspect.reset(); + super.onSetUp(); + } + + + // We don't need to test all combination of pointcuts due to BeanNamePointcutMatchingTests + + public void testMatchingBeanName() { + assertTrue("Matching bean must be advised (proxied)", this.testBean1 instanceof Advised); + // Call two methods to test for SPR-3953-like condition + this.testBean1.setAge(20); + this.testBean1.setName(""); + assertEquals("Advice not executed: must have been", 2, this.counterAspect.getCount()); + } + + public void testNonMatchingBeanName() { + assertFalse("Non-matching bean must *not* be advised (proxied)", this.testBean2 instanceof Advised); + this.testBean2.setAge(20); + assertEquals("Advice must *not* have been executed", 0, this.counterAspect.getCount()); + } + + public void testNonMatchingNestedBeanName() { + assertFalse("Non-matching bean must *not* be advised (proxied)", this.testBeanContainingNestedBean.getDoctor() instanceof Advised); + } + + public void testMatchingFactoryBeanObject() { + assertTrue("Matching bean must be advised (proxied)", this.testFactoryBean1 instanceof Advised); + assertEquals("myValue", this.testFactoryBean1.get("myKey")); + assertEquals("myValue", this.testFactoryBean1.get("myKey")); + assertEquals("Advice not executed: must have been", 2, this.counterAspect.getCount()); + FactoryBean fb = (FactoryBean) getApplicationContext().getBean("&testFactoryBean1"); + assertTrue("FactoryBean itself must *not* be advised", !(fb instanceof Advised)); + } + + public void testMatchingFactoryBeanItself() { + assertTrue("Matching bean must *not* be advised (proxied)", !(this.testFactoryBean2 instanceof Advised)); + FactoryBean fb = (FactoryBean) getApplicationContext().getBean("&testFactoryBean2"); + assertTrue("FactoryBean itself must be advised", fb instanceof Advised); + assertTrue(Map.class.isAssignableFrom(fb.getObjectType())); + assertTrue(Map.class.isAssignableFrom(fb.getObjectType())); + assertEquals("Advice not executed: must have been", 2, this.counterAspect.getCount()); + } + + public void testPointcutAdvisorCombination() { + assertTrue("Matching bean must be advised (proxied)", this.interceptThis instanceof Advised); + assertFalse("Non-matching bean must *not* be advised (proxied)", this.dontInterceptThis instanceof Advised); + interceptThis.setAge(20); + assertEquals(1, testInterceptor.interceptionCount); + dontInterceptThis.setAge(20); + assertEquals(1, testInterceptor.interceptionCount); + } + + + public static class TestInterceptor implements MethodBeforeAdvice { + + private int interceptionCount; + + public void before(Method method, Object[] args, Object target) throws Throwable { + interceptionCount++; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeforeAdviceBindingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeforeAdviceBindingTests.java new file mode 100644 index 00000000000..52792be6222 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/BeforeAdviceBindingTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.easymock.MockControl; + +import org.springframework.aop.aspectj.AdviceBindingTestAspect.AdviceBindingCollaborator; + +/** + * Tests for various parameter binding scenarios with before advice. + * + * @author Adrian Colyer + * @author Rod Johnson + */ +public class BeforeAdviceBindingTests extends AbstractAdviceBindingTests { + + private AdviceBindingTestAspect beforeAdviceAspect; + + private MockControl mockControl; + + private AdviceBindingCollaborator mockCollaborator; + + + public void setBeforeAdviceAspect(AdviceBindingTestAspect anAspect) { + this.beforeAdviceAspect = anAspect; + } + + protected String getConfigPath() { + return "before-advice-tests.xml"; + } + + protected void onSetUp() throws Exception { + super.onSetUp(); + mockControl = MockControl.createNiceControl(AdviceBindingCollaborator.class); + mockCollaborator = (AdviceBindingCollaborator) mockControl.getMock(); + beforeAdviceAspect.setCollaborator(mockCollaborator); + } + + + public void testOneIntArg() { + mockCollaborator.oneIntArg(5); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testOneObjectArgBoundToProxyUsingThis() { + mockCollaborator.oneObjectArg(this.testBeanProxy); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testOneIntAndOneObjectArgs() { + mockCollaborator.oneIntAndOneObject(5,this.testBeanTarget); + mockControl.replay(); + testBeanProxy.setAge(5); + mockControl.verify(); + } + + public void testNeedsJoinPoint() { + mockCollaborator.needsJoinPoint("getAge"); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + public void testNeedsJoinPointStaticPart() { + mockCollaborator.needsJoinPointStaticPart("getAge"); + mockControl.replay(); + testBeanProxy.getAge(); + mockControl.verify(); + } + + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/CallCountingInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/CallCountingInterceptor.java new file mode 100644 index 00000000000..aa5eb61eddc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/CallCountingInterceptor.java @@ -0,0 +1,26 @@ + +package org.springframework.aop.aspectj; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * @author robh + */ +class CallCountingInterceptor implements MethodInterceptor { + + private int count; + + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + count++; + return methodInvocation.proceed(); + } + + public int getCount() { + return count; + } + + public void reset() { + this.count = 0; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/Counter.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/Counter.java new file mode 100644 index 00000000000..c8ae64ce444 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/Counter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +/** + * A simple counter for use in simple tests (for example, how many times an advice was executed) + * + * @author Ramnivas Laddad + */ +public class Counter implements ICounter { + + private int count; + + public Counter() { + } + + public void increment() { + count++; + } + + public void decrement() { + count--; + } + + public int getCount() { + return count; + } + + public void setCount(int counter) { + this.count = counter; + } + + public void reset() { + this.count = 0; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclarationOrderIndependenceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclarationOrderIndependenceTests.java new file mode 100644 index 00000000000..a962b3d04bf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclarationOrderIndependenceTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import java.io.Serializable; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Adrian Colyer + */ +public class DeclarationOrderIndependenceTests extends AbstractDependencyInjectionSpringContextTests { + + private TopsyTurvyAspect aspect; + + private TopsyTurvyTarget target; + + + public DeclarationOrderIndependenceTests() { + setAutowireMode(AUTOWIRE_BY_NAME); + } + + public void setTopsyTurvyAspect(TopsyTurvyAspect aspect) { + this.aspect = aspect; + } + + public void setTopsyTurvyTarget(TopsyTurvyTarget target) { + this.target = target; + } + + protected String getConfigPath() { + return "topsy-turvy-aspect.xml"; + } + + + public void testTargetIsSerializable() { + assertTrue("target bean is serializable",this.target instanceof Serializable); + } + + public void testTargetIsBeanNameAware() { + assertTrue("target bean is bean name aware",this.target instanceof BeanNameAware); + } + + public void testBeforeAdviceFiringOk() { + AspectCollaborator collab = new AspectCollaborator(); + this.aspect.setCollaborator(collab); + this.target.doSomething(); + assertTrue("before advice fired",collab.beforeFired); + } + + public void testAroundAdviceFiringOk() { + AspectCollaborator collab = new AspectCollaborator(); + this.aspect.setCollaborator(collab); + this.target.getX(); + assertTrue("around advice fired",collab.aroundFired); + } + + public void testAfterReturningFiringOk() { + AspectCollaborator collab = new AspectCollaborator(); + this.aspect.setCollaborator(collab); + this.target.getX(); + assertTrue("after returning advice fired",collab.afterReturningFired); + } + + private static class AspectCollaborator implements TopsyTurvyAspect.Collaborator { + + public boolean afterReturningFired = false; + public boolean aroundFired = false; + public boolean beforeFired = false; + + /* (non-Javadoc) + * @see org.springframework.aop.aspectj.TopsyTurvyAspect.Collaborator#afterReturningAdviceFired() + */ + public void afterReturningAdviceFired() { + this.afterReturningFired = true; + } + + /* (non-Javadoc) + * @see org.springframework.aop.aspectj.TopsyTurvyAspect.Collaborator#aroundAdviceFired() + */ + public void aroundAdviceFired() { + this.aroundFired = true; + } + + /* (non-Javadoc) + * @see org.springframework.aop.aspectj.TopsyTurvyAspect.Collaborator#beforeAdviceFired() + */ + public void beforeAdviceFired() { + this.beforeFired = true; + } + + } +} + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsDelegateRefTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsDelegateRefTests.java new file mode 100644 index 00000000000..8da46feed6b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsDelegateRefTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Ramnivas Laddad + */ +public class DeclareParentsDelegateRefTests extends AbstractDependencyInjectionSpringContextTests { + + protected NoMethodsBean noMethodsBean; + + protected CounterImpl counter; + + + public DeclareParentsDelegateRefTests() { + setPopulateProtectedVariables(true); + } + + protected void onSetUp() throws Exception { + counter.reset(); + } + + protected String getConfigPath() { + return "declare-parents-delegate-ref-tests.xml"; + } + + + public void testIntroductionWasMade() { + assertTrue("Introduction must have been made", noMethodsBean instanceof Counter); + } + + public void testIntroductionDelegation() { + ((Counter)noMethodsBean).increment(); + assertEquals("Delegate's counter should be updated", 1, counter.count); + } + + public static interface NoMethodsBean { + } + + public static class NoMethodsBeanImpl implements NoMethodsBean { + } + + public static interface Counter { + public void increment(); + } + + + public static class CounterImpl implements Counter { + + int count; + + public void increment() { + count++; + } + + public void reset() { + count = 0; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsTests.java new file mode 100644 index 00000000000..0eb09b31ec6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/DeclareParentsTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.aop.framework.Lockable; +import org.springframework.aop.support.AopUtils; + +/** + * @author Rod Johnson + */ +public class DeclareParentsTests extends AbstractAdviceBindingTests { + + protected String getConfigPath() { + return "declare-parents-tests.xml"; + } + + public void testIntroductionWasMade() { + assertTrue("Introduction must have been made", testBeanProxy instanceof Lockable); + } + + // TODO if you change type pattern from org.springframework.beans..* + // to org.springframework..* it also matches introduction. + // Perhaps generated advisor bean definition could be made to depend + // on the introduction, in which case this would not be a problem. + public void testLockingWorks() { + Object introductionObject = applicationContext.getBean("introduction"); + assertFalse("Introduction should not be proxied", AopUtils.isAopProxy(introductionObject)); + + Lockable lockable = (Lockable) testBeanProxy; + assertFalse(lockable.locked()); + + // Invoke a non-advised method + testBeanProxy.getAge(); + + testBeanProxy.setName(""); + lockable.lock(); + try { + testBeanProxy.setName(" "); + fail("Should be locked"); + } + catch (IllegalStateException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ICounter.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ICounter.java new file mode 100644 index 00000000000..4c35daf9d80 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ICounter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +/** + * @author Ramnivas Laddad + */ +public interface ICounter { + + void increment(); + + void decrement(); + + int getCount(); + + void setCount(int counter); + + void reset(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingTests.java new file mode 100644 index 00000000000..20662199d3d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ImplicitJPArgumentMatchingTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.beans.TestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests to check if the first implicit join point argument is correctly processed. + * See SPR-3723 for more details. + * + * @author Ramnivas Laddad + */ +public class ImplicitJPArgumentMatchingTests extends AbstractDependencyInjectionSpringContextTests { + protected TestBean testBean; + + public ImplicitJPArgumentMatchingTests() { + setPopulateProtectedVariables(true); + } + + protected String getConfigPath() { + return "implicit-jp-argument-matching-tests.xml"; + } + + public void testAspect() { + // nothing to really test; it is enough if we don't get error while creating app context + testBean.setCountry("US"); + } + + public static class CounterAspect { + public void increment(ProceedingJoinPoint pjp, Object bean, Object argument) throws Throwable { + pjp.proceed(); + } + } +} + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java new file mode 100644 index 00000000000..0238e8caeb4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java @@ -0,0 +1,180 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import java.lang.reflect.Method; +import java.util.Arrays; + +import junit.framework.TestCase; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.JoinPoint.StaticPart; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.aspectj.lang.reflect.SourceLocation; + +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.framework.AopContext; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.interceptor.ExposeInvocationInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; + +/** + * @author Rod Johnson + * @since 2.0 + */ +public class MethodInvocationProceedingJoinPointTests extends TestCase { + + public void testingBindingWithJoinPoint() { + try { + AbstractAspectJAdvice.currentJoinPoint(); + fail("Needs to be bound by interceptor action"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testingBindingWithProceedingJoinPoint() { + try { + AbstractAspectJAdvice.currentJoinPoint(); + fail("Needs to be bound by interceptor action"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testCanGetMethodSignatureFromJoinPoint() { + final Object raw = new TestBean(); + // Will be set by advice during a method call + final int newAge = 23; + + ProxyFactory pf = new ProxyFactory(raw); + pf.setExposeProxy(true); + pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR); + pf.addAdvice(new MethodBeforeAdvice() { + private int depth; + + public void before(Method method, Object[] args, Object target) throws Throwable { + JoinPoint jp = AbstractAspectJAdvice.currentJoinPoint(); + assertTrue("Method named in toString", jp.toString().indexOf(method.getName()) != -1); + // Ensure that these don't cause problems + jp.toShortString(); + jp.toLongString(); + + assertSame(target, AbstractAspectJAdvice.currentJoinPoint().getTarget()); + assertFalse(AopUtils.isAopProxy(AbstractAspectJAdvice.currentJoinPoint().getTarget())); + + ITestBean thisProxy = (ITestBean) AbstractAspectJAdvice.currentJoinPoint().getThis(); + assertTrue(AopUtils.isAopProxy(AbstractAspectJAdvice.currentJoinPoint().getThis())); + + assertNotSame(target, thisProxy); + + // Check getting again doesn't cause a problem + assertSame(thisProxy, AbstractAspectJAdvice.currentJoinPoint().getThis()); + + // Try reentrant call--will go through this advice. + // Be sure to increment depth to avoid infinite recursion + if (depth++ == 0) { + // Check that toString doesn't cause a problem + thisProxy.toString(); + // Change age, so this will be returned by invocation + thisProxy.setAge(newAge); + assertEquals(newAge, thisProxy.getAge()); + } + + assertSame(AopContext.currentProxy(), thisProxy); + assertSame(target, raw); + + assertSame(method.getName(), AbstractAspectJAdvice.currentJoinPoint().getSignature().getName()); + assertEquals(method.getModifiers(), AbstractAspectJAdvice.currentJoinPoint().getSignature().getModifiers()); + + MethodSignature msig = (MethodSignature) AbstractAspectJAdvice.currentJoinPoint().getSignature(); + assertSame("Return same MethodSignature repeatedly", msig, AbstractAspectJAdvice.currentJoinPoint().getSignature()); + assertSame("Return same JoinPoint repeatedly", AbstractAspectJAdvice.currentJoinPoint(), AbstractAspectJAdvice.currentJoinPoint()); + assertEquals(method.getDeclaringClass(), msig.getDeclaringType()); + assertTrue(Arrays.equals(method.getParameterTypes(), msig.getParameterTypes())); + assertEquals(method.getReturnType(), msig.getReturnType()); + assertTrue(Arrays.equals(method.getExceptionTypes(), msig.getExceptionTypes())); + try { + msig.getParameterNames(); + fail("Can't determine parameter names"); + } + catch (UnsupportedOperationException ex) { + // Expected + } + msig.toLongString(); + msig.toShortString(); + } + }); + ITestBean itb = (ITestBean) pf.getProxy(); + // Any call will do + assertEquals("Advice reentrantly set age", newAge, itb.getAge()); + } + + public void testCanGetSourceLocationFromJoinPoint() { + final Object raw = new TestBean(); + ProxyFactory pf = new ProxyFactory(raw); + pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR); + pf.addAdvice(new MethodBeforeAdvice() { + public void before(Method method, Object[] args, Object target) throws Throwable { + SourceLocation sloc = AbstractAspectJAdvice.currentJoinPoint().getSourceLocation(); + assertEquals("Same source location must be returned on subsequent requests", sloc, AbstractAspectJAdvice.currentJoinPoint().getSourceLocation()); + assertEquals(TestBean.class, sloc.getWithinType()); + try { + sloc.getLine(); + fail("Can't get line number"); + } + catch (UnsupportedOperationException ex) { + // Expected + } + + try { + sloc.getFileName(); + fail("Can't get file name"); + } + catch (UnsupportedOperationException ex) { + // Expected + } + } + }); + ITestBean itb = (ITestBean) pf.getProxy(); + // Any call will do + itb.getAge(); + } + + public void testCanGetStaticPartFromJoinPoint() { + final Object raw = new TestBean(); + ProxyFactory pf = new ProxyFactory(raw); + pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR); + pf.addAdvice(new MethodBeforeAdvice() { + public void before(Method method, Object[] args, Object target) throws Throwable { + StaticPart staticPart = AbstractAspectJAdvice.currentJoinPoint().getStaticPart(); + assertEquals("Same static part must be returned on subsequent requests", staticPart, AbstractAspectJAdvice.currentJoinPoint().getStaticPart()); + assertEquals(ProceedingJoinPoint.METHOD_EXECUTION, staticPart.getKind()); + assertSame(AbstractAspectJAdvice.currentJoinPoint().getSignature(), staticPart.getSignature()); + assertEquals(AbstractAspectJAdvice.currentJoinPoint().getSourceLocation(), staticPart.getSourceLocation()); + } + }); + ITestBean itb = (ITestBean) pf.getProxy(); + // Any call will do + itb.getAge(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/NonAnnotatedMakeLockable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/NonAnnotatedMakeLockable.java new file mode 100644 index 00000000000..e608d4e8d21 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/NonAnnotatedMakeLockable.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.aop.framework.Lockable; + +/** + * @author Rod Johnson + */ +public class NonAnnotatedMakeLockable { + + public void checkNotLocked(Lockable mixin) { + if (mixin.locked()) { + throw new IllegalStateException("locked"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTestAspect.java new file mode 100644 index 00000000000..196a6bc3ae2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTestAspect.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.aspectj; + + +/** + * Aspect used as part of overloaded advice tests. + * @author Adrian Colyer + */ +public class OverloadedAdviceTestAspect { + + public void myBeforeAdvice(String name) { + // no-op + } + + public void myBeforeAdvice(int age) { + // no-op + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTests.java new file mode 100644 index 00000000000..42d60c89cf6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/OverloadedAdviceTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Tests for overloaded advice. + * + * @author Adrian Colyer + */ +public class OverloadedAdviceTests extends TestCase { + + public void testExceptionOnConfigParsingWithMismatchedAdviceMethod() { + try { + new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/overloaded-advice-tests.xml"); + } + catch (BeanCreationException ex) { + Throwable cause = ex.getRootCause(); + assertTrue("Should be IllegalArgumentException", cause instanceof IllegalArgumentException); + assertTrue("invalidAbsoluteTypeName should be detected by AJ", + cause.getMessage().indexOf("invalidAbsoluteTypeName") != -1); + } + } + + public void testExceptionOnConfigParsingWithAmbiguousAdviceMethod() { + try { + new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/ambiguous-advice-tests.xml"); + } + catch (BeanCreationException ex) { + Throwable cause = ex.getRootCause(); + assertTrue("Should be IllegalArgumentException", cause instanceof IllegalArgumentException); + assertTrue("Cannot resolve method 'myBeforeAdvice' to a unique method", + cause.getMessage().indexOf("Cannot resolve method 'myBeforeAdvice' to a unique method") != -1); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PrecedenceTestAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PrecedenceTestAspect.java new file mode 100644 index 00000000000..bf0b092bc62 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/PrecedenceTestAspect.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.aspectj.lang.ProceedingJoinPoint; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.core.Ordered; + +/** + * Used in advice precedence tests (surprise!) + * + * @author Adrian Colyer + */ +public class PrecedenceTestAspect implements BeanNameAware, Ordered { + + private String name; + + private int order = Ordered.LOWEST_PRECEDENCE; + + private Collaborator collaborator; + + + public void setBeanName(String name) { + this.name = name; + } + + public void setOrder(int order) { + this.order = order; + } + + public int getOrder() { + return order; + } + + public void setCollaborator(Collaborator collaborator) { + this.collaborator = collaborator; + } + + public void beforeAdviceOne() { + this.collaborator.beforeAdviceOne(this.name); + } + + public void beforeAdviceTwo() { + this.collaborator.beforeAdviceTwo(this.name); + } + + public int aroundAdviceOne(ProceedingJoinPoint pjp) { + int ret = -1; + this.collaborator.aroundAdviceOne(this.name); + try { + ret = ((Integer)pjp.proceed()).intValue(); + } + catch(Throwable t) { throw new RuntimeException(t); } + this.collaborator.aroundAdviceOne(this.name); + return ret; + } + + public int aroundAdviceTwo(ProceedingJoinPoint pjp) { + int ret = -1; + this.collaborator.aroundAdviceTwo(this.name); + try { + ret = ((Integer)pjp.proceed()).intValue(); + } + catch(Throwable t) {throw new RuntimeException(t);} + this.collaborator.aroundAdviceTwo(this.name); + return ret; + } + + public void afterAdviceOne() { + this.collaborator.afterAdviceOne(this.name); + } + + public void afterAdviceTwo() { + this.collaborator.afterAdviceTwo(this.name); + } + + + public interface Collaborator { + + void beforeAdviceOne(String beanName); + void beforeAdviceTwo(String beanName); + void aroundAdviceOne(String beanName); + void aroundAdviceTwo(String beanName); + void afterAdviceOne(String beanName); + void afterAdviceTwo(String beanName); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ProceedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ProceedTests.java new file mode 100644 index 00000000000..b882dcc83fb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ProceedTests.java @@ -0,0 +1,214 @@ +/** + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; + +import org.springframework.core.JdkVersion; +import org.springframework.core.Ordered; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Test for SPR-3522. Arguments changed on a call to proceed should be + * visible to advice further down the invocation chain. + * + * @author Adrian Colyer + */ +public class ProceedTests extends AbstractDependencyInjectionSpringContextTests { + + private SimpleBean testBean; + + private ProceedTestingAspect testAspect; + + private ProceedTestingAspect secondTestAspect; + + + public ProceedTests() { + setAutowireMode(AUTOWIRE_BY_NAME); + } + + protected String[] getConfigLocations() { + return new String[] {"org/springframework/aop/aspectj/proceedTests.xml"}; + } + + public void setFirstTestAspect(ProceedTestingAspect anAspect) { + this.testAspect = anAspect; + } + + public void setSecondTestAspect(ProceedTestingAspect anAspect) { + this.secondTestAspect = anAspect; + } + + public void setTestBean(SimpleBean aBean) { + this.testBean = aBean; + } + + + public void testSimpleProceedWithChangedArgs() { + this.testBean.setName("abc"); + assertEquals("Name changed in around advice", "ABC", this.testBean.getName()); + } + + public void testGetArgsIsDefensive() { + this.testBean.setAge(5); + assertEquals("getArgs is defensive", 5, this.testBean.getAge()); + } + + public void testProceedWithArgsInSameAspect() { + if (!JdkVersion.isAtLeastJava15()) { + // Doesn't work on JDK 1.4 for some reason... + return; + } + + this.testBean.setMyFloat(1.0F); + assertTrue("value changed in around advice", this.testBean.getMyFloat() > 1.9F); + assertTrue("changed value visible to next advice in chain", this.testAspect.getLastBeforeFloatValue() > 1.9F); + } + + public void testProceedWithArgsAcrossAspects() { + this.testBean.setSex("male"); + assertEquals("value changed in around advice","MALE", this.testBean.getSex()); + assertEquals("changed value visible to next before advice in chain","MALE", this.secondTestAspect.getLastBeforeStringValue()); + assertEquals("changed value visible to next around advice in chain","MALE", this.secondTestAspect.getLastAroundStringValue()); + } + + + public interface SimpleBean { + + public void setName(String name); + public String getName(); + public void setAge(int age); + public int getAge(); + public void setMyFloat(float f); + public float getMyFloat(); + public void setSex(String sex); + public String getSex(); + } + + + public static class SimpleBeanImpl implements SimpleBean { + + private int age; + private float aFloat; + private String name; + private String sex; + + public int getAge() { + return age; + } + + public float getMyFloat() { + return aFloat; + } + + public String getName() { + return name; + } + + public String getSex() { + return sex; + } + + public void setAge(int age) { + this.age = age; + } + + public void setMyFloat(float f) { + this.aFloat = f; + } + + public void setName(String name) { + this.name = name; + } + + public void setSex(String sex) { + this.sex = sex; + } + } + + + public static class ProceedTestingAspect implements Ordered { + + private String lastBeforeStringValue; + private String lastAroundStringValue; + private float lastBeforeFloatValue; + private int order; + + public void setOrder(int order) { this.order = order; } + public int getOrder() { return this.order; } + + public Object capitalize(ProceedingJoinPoint pjp, String value) throws Throwable { + return pjp.proceed(new Object[] {value.toUpperCase()}); + } + + public Object doubleOrQuits(ProceedingJoinPoint pjp) throws Throwable { + int value = ((Integer) pjp.getArgs()[0]).intValue(); + pjp.getArgs()[0] = new Integer(value * 2); + return pjp.proceed(); + } + + public Object addOne(ProceedingJoinPoint pjp, Float value) throws Throwable { + float fv = value.floatValue(); + return pjp.proceed(new Object[] {new Float(fv + 1.0F)}); + } + + public void captureStringArgument(JoinPoint tjp, String arg) { + if (!tjp.getArgs()[0].equals(arg)) { + throw new IllegalStateException( + "argument is '" + arg + "', " + + "but args array has '" + tjp.getArgs()[0] + "'" + ); + } + this.lastBeforeStringValue = arg; + } + + public Object captureStringArgumentInAround(ProceedingJoinPoint pjp, String arg) throws Throwable { + if (!pjp.getArgs()[0].equals(arg)) { + throw new IllegalStateException( + "argument is '" + arg + "', " + + "but args array has '" + pjp.getArgs()[0] + "'"); + } + this.lastAroundStringValue = arg; + return pjp.proceed(); + } + + public void captureFloatArgument(JoinPoint tjp, float arg) { + float tjpArg = ((Float) tjp.getArgs()[0]).floatValue(); + if (Math.abs(tjpArg - arg) > 0.000001) { + throw new IllegalStateException( + "argument is '" + arg + "', " + + "but args array has '" + tjpArg + "'" + ); + } + this.lastBeforeFloatValue = arg; + } + + public String getLastBeforeStringValue() { + return this.lastBeforeStringValue; + } + + public String getLastAroundStringValue() { + return this.lastAroundStringValue; + } + + public float getLastBeforeFloatValue() { + return this.lastBeforeFloatValue; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SerializableMixin.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SerializableMixin.java new file mode 100644 index 00000000000..2046942aa42 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SerializableMixin.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 15 Nov 2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj; + +import java.io.Serializable; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class SerializableMixin implements Serializable { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SharedPointcutWithArgsMismatch.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SharedPointcutWithArgsMismatch.java new file mode 100644 index 00000000000..9083ebe1df5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SharedPointcutWithArgsMismatch.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * See SPR-1682. + * + * @author Adrian Colyer + */ +public class SharedPointcutWithArgsMismatch extends AbstractDependencyInjectionSpringContextTests { + + private ToBeAdvised toBeAdvised; + + + public void setToBeAdvised(ToBeAdvised tba) { + this.toBeAdvised = tba; + } + + protected String getConfigPath() { + return "args-mismatch.xml"; + } + + + public void testMismatchedArgBinding() { + this.toBeAdvised.foo("Hello"); + } + + + public static class ToBeAdvised { + + public void foo(String s) { + System.out.println(s); + } + } + + + public static class MyAspect { + + public void doBefore(int x) { + System.out.println(x); + } + + public void doBefore(String x) { + System.out.println(x); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SimpleSpringBeforeAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SimpleSpringBeforeAdvice.java new file mode 100644 index 00000000000..77a3ca45ef9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SimpleSpringBeforeAdvice.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 14-Feb-2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj; + +import java.lang.reflect.Method; + +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.beans.factory.BeanNameAware; + +/** + * Used as part of aspect precedence tests + * + * @author Adrian Colyer + * @since 2.0 + */ +public class SimpleSpringBeforeAdvice implements MethodBeforeAdvice, BeanNameAware { + + private PrecedenceTestAspect.Collaborator collaborator; + private String name; + + /* (non-Javadoc) + * @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object) + */ + public void before(Method method, Object[] args, Object target) + throws Throwable { + this.collaborator.beforeAdviceOne(this.name); + } + + public void setCollaborator(PrecedenceTestAspect.Collaborator collaborator) { + this.collaborator = collaborator; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String) + */ + public void setBeanName(String name) { + this.name = name; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeMatchingTestClasses.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeMatchingTestClasses.java new file mode 100644 index 00000000000..ce5a77189fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeMatchingTestClasses.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import java.io.Serializable; + + +// strange looking interfaces are just to set up certain test conditions... +interface NonSerializableFoo { void foo(); } +interface SerializableFoo extends Serializable { void foo(); } + +class SubtypeMatchingTestClassA implements NonSerializableFoo { + + public void foo() {} + +} + +class SubtypeMatchingTestClassB implements SerializableFoo { + + public void foo() {} + +} + +interface Bar { void bar(Object o); } + +class SubtypeMatchingTestClassC implements Bar { + + public void bar(Object o) {} + +} + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeSensitiveMatchingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeSensitiveMatchingTests.java new file mode 100644 index 00000000000..13dff54d618 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/SubtypeSensitiveMatchingTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.aop.framework.Advised; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Adrian Colyer + */ +public class SubtypeSensitiveMatchingTests extends AbstractDependencyInjectionSpringContextTests { + + private NonSerializableFoo nonSerializableBean; + + private SerializableFoo serializableBean; + + private Bar bar; + + + public void setNonSerializableFoo(NonSerializableFoo aBean) { + this.nonSerializableBean = aBean; + } + + public void setSerializableFoo(SerializableFoo aBean) { + this.serializableBean = aBean; + } + + public void setBar(Bar aBean) { + this.bar = aBean; + } + + protected String getConfigPath() { + return "subtype-sensitive-matching.xml"; + } + + + public void testBeansAreProxiedOnStaticMatch() { + assertTrue("bean with serializable type should be proxied", + this.serializableBean instanceof Advised); + } + + public void testBeansThatDoNotMatchBasedSolelyOnRuntimeTypeAreNotProxied() { + assertFalse("bean with non-serializable type should not be proxied", + this.nonSerializableBean instanceof Advised); + } + + public void testBeansThatDoNotMatchBasedOnOtherTestAreProxied() { + assertTrue("bean with args check should be proxied", + this.bar instanceof Advised); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TargetPointcutSelectionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TargetPointcutSelectionTests.java new file mode 100644 index 00000000000..1146b777f61 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TargetPointcutSelectionTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Tests for target selection matching (see SPR-3783). + * Thanks to Tomasz Blachowicz for the bug report! + * + * @author Ramnivas Laddad + */ +public class TargetPointcutSelectionTests extends AbstractDependencyInjectionSpringContextTests { + + protected TestInterface testImpl1; + protected TestInterface testImpl2; + protected TestAspect testAspectForTestImpl1; + protected TestAspect testAspectForAbstractTestImpl; + protected TestInterceptor testInterceptor; + + + public TargetPointcutSelectionTests() { + setPopulateProtectedVariables(true); + } + + protected String getConfigPath() { + return "targetPointcutSelectionTests.xml"; + } + + protected void onSetUp() throws Exception { + testAspectForTestImpl1.count = 0; + testAspectForAbstractTestImpl.count = 0; + testInterceptor.count = 0; + super.onSetUp(); + } + + + public void testTargetSelectionForMatchedType() { + testImpl1.interfaceMethod(); + assertEquals("Should have been advised by POJO advice for impl", 1, testAspectForTestImpl1.count); + assertEquals("Should have been advised by POJO advice for base type", 1, testAspectForAbstractTestImpl.count); + assertEquals("Should have been advised by advisor", 1, testInterceptor.count); + } + + public void testTargetNonSelectionForMismatchedType() { + testImpl2.interfaceMethod(); + assertEquals("Shouldn't have been advised by POJO advice for impl", 0, testAspectForTestImpl1.count); + assertEquals("Should have been advised by POJO advice for base type", 1, testAspectForAbstractTestImpl.count); + assertEquals("Shouldn't have been advised by advisor", 0, testInterceptor.count); + } + + + public static interface TestInterface { + + public void interfaceMethod(); + } + + + // Reproducing bug requires that the class specified in target() pointcut doesn't + // include the advised method's implementation (instead a base class should include it) + public static abstract class AbstractTestImpl implements TestInterface { + + public void interfaceMethod() { + } + } + + + public static class TestImpl1 extends AbstractTestImpl { + } + + + public static class TestImpl2 extends AbstractTestImpl { + } + + + public static class TestAspect { + + public int count; + + public void increment() { + count++; + } + } + + + public static class TestInterceptor extends TestAspect implements MethodInterceptor { + + public Object invoke(MethodInvocation mi) throws Throwable { + increment(); + return mi.proceed(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsTests.java new file mode 100644 index 00000000000..f2b470e738e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ThisAndTargetSelectionOnlyPointcutsTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Ramnivas Laddad + */ +public class ThisAndTargetSelectionOnlyPointcutsTests extends AbstractDependencyInjectionSpringContextTests { + protected TestInterface testBean; + + protected Counter thisAsClassCounter; + protected Counter thisAsInterfaceCounter; + protected Counter targetAsClassCounter; + protected Counter targetAsInterfaceCounter; + protected Counter thisAsClassAndTargetAsClassCounter; + protected Counter thisAsInterfaceAndTargetAsInterfaceCounter; + protected Counter thisAsInterfaceAndTargetAsClassCounter; + + public ThisAndTargetSelectionOnlyPointcutsTests() { + setPopulateProtectedVariables(true); + } + + protected void onSetUp() throws Exception { + super.onSetUp(); + thisAsClassCounter.reset(); + thisAsInterfaceCounter.reset(); + targetAsClassCounter.reset(); + targetAsInterfaceCounter.reset(); + + thisAsClassAndTargetAsClassCounter.reset(); + thisAsInterfaceAndTargetAsInterfaceCounter.reset(); + thisAsInterfaceAndTargetAsClassCounter.reset(); + } + + protected String getConfigPath() { + return "this-and-target-selectionOnly-pointcuts-tests.xml"; + } + + public void testThisAsClassDoesNotMatch() { + testBean.doIt(); + assertEquals(0, thisAsClassCounter.getCount()); + } + + public void testThisAsInterfaceMatch() { + testBean.doIt(); + assertEquals(1, thisAsInterfaceCounter.getCount()); + } + + public void testTargetAsClassDoesMatch() { + testBean.doIt(); + assertEquals(1, targetAsClassCounter.getCount()); + } + + public void testTargetAsInterfaceMatch() { + testBean.doIt(); + assertEquals(1, targetAsInterfaceCounter.getCount()); + } + + public void testThisAsClassAndTargetAsClassCounterNotMatch() { + testBean.doIt(); + assertEquals(0, thisAsClassAndTargetAsClassCounter.getCount()); + } + + public void testThisAsInterfaceAndTargetAsInterfaceCounterMatch() { + testBean.doIt(); + assertEquals(1, thisAsInterfaceAndTargetAsInterfaceCounter.getCount()); + } + + public void testThisAsInterfaceAndTargetAsClassCounterMatch() { + testBean.doIt(); + assertEquals(1, thisAsInterfaceAndTargetAsInterfaceCounter.getCount()); + } + + public static interface TestInterface { + public void doIt(); + } + + public static class TestImpl implements TestInterface { + public void doIt() { + } + } +} + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyAspect.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyAspect.java new file mode 100644 index 00000000000..489f7621323 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyAspect.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 15 Nov 2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj; + +import org.aspectj.lang.ProceedingJoinPoint; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class TopsyTurvyAspect { + + interface Collaborator { + void beforeAdviceFired(); + void afterReturningAdviceFired(); + void aroundAdviceFired(); + } + + private Collaborator collaborator; + + public void setCollaborator(Collaborator collaborator) { + this.collaborator = collaborator; + } + + public void before() { + this.collaborator.beforeAdviceFired(); + } + + public void afterReturning() { + this.collaborator.afterReturningAdviceFired(); + } + + public Object around(ProceedingJoinPoint pjp) throws Throwable { + Object ret = pjp.proceed(); + this.collaborator.aroundAdviceFired(); + return ret; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTarget.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTarget.java new file mode 100644 index 00000000000..3cb679c0de7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTarget.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 15 Nov 2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public interface TopsyTurvyTarget { + + public abstract void doSomething(); + + public abstract int getX(); + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTargetImpl.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTargetImpl.java new file mode 100644 index 00000000000..bfebb397bb6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TopsyTurvyTargetImpl.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 15 Nov 2006 by Adrian Colyer + */ +package org.springframework.aop.aspectj; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class TopsyTurvyTargetImpl implements TopsyTurvyTarget { + + private int x = 5; + + /* (non-Javadoc) + * @see org.springframework.aop.aspectj.TopsyTurvyTarget#doSomething() + */ + public void doSomething() { + this.x = 10; + } + + /* (non-Javadoc) + * @see org.springframework.aop.aspectj.TopsyTurvyTarget#getX() + */ + public int getX() { + return x; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java new file mode 100644 index 00000000000..d6deb96c0ab --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj; + +import junit.framework.TestCase; +import org.springframework.aop.framework.autoproxy.CountingTestBean; +import org.springframework.beans.IOther; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link TypePatternClassFilter} class. + * + * @author Rod Johnson + * @author Rick Evans + */ +public final class TypePatternClassFilterTests extends TestCase { + + public void testInvalidPattern() { + try { + new TypePatternClassFilter("-"); + fail("Pattern must be recognized as invalid."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testValidPatternMatching() { + TypePatternClassFilter tpcf = new TypePatternClassFilter("org.springframework.beans.*"); + assertTrue("Must match: in package", tpcf.matches(TestBean.class)); + assertTrue("Must match: in package", tpcf.matches(ITestBean.class)); + assertTrue("Must match: in package", tpcf.matches(IOther.class)); + assertFalse("Must be excluded: in wrong package", tpcf.matches(CountingTestBean.class)); + assertFalse("Must be excluded: in wrong package", tpcf.matches(BeanFactory.class)); + assertFalse("Must be excluded: in wrong package", tpcf.matches(DefaultListableBeanFactory.class)); + } + + public void testSubclassMatching() { + TypePatternClassFilter tpcf = new TypePatternClassFilter("org.springframework.beans.ITestBean+"); + assertTrue("Must match: in package", tpcf.matches(TestBean.class)); + assertTrue("Must match: in package", tpcf.matches(ITestBean.class)); + assertTrue("Must match: in package", tpcf.matches(CountingTestBean.class)); + assertFalse("Must be excluded: not subclass", tpcf.matches(IOther.class)); + assertFalse("Must be excluded: not subclass", tpcf.matches(DefaultListableBeanFactory.class)); + } + + public void testAndOrNotReplacement() { + TypePatternClassFilter tpcf = new TypePatternClassFilter("java.lang.Object or java.lang.String"); + assertFalse("matches Number",tpcf.matches(Number.class)); + assertTrue("matches Object",tpcf.matches(Object.class)); + assertTrue("matchesString",tpcf.matches(String.class)); + tpcf = new TypePatternClassFilter("java.lang.Number+ and java.lang.Float"); + assertTrue("matches Float",tpcf.matches(Float.class)); + assertFalse("matches Double",tpcf.matches(Double.class)); + tpcf = new TypePatternClassFilter("java.lang.Number+ and not java.lang.Float"); + assertFalse("matches Float",tpcf.matches(Float.class)); + assertTrue("matches Double",tpcf.matches(Double.class)); + } + + public void testSetTypePatternWithNullArgument() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new TypePatternClassFilter(null); + } + }.runTest(); + } + + public void testInvocationOfMatchesMethodBlowsUpWhenNoTypePatternHasBeenSet() throws Exception { + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + new TypePatternClassFilter().matches(String.class); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/advice-precedence-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/advice-precedence-tests.xml new file mode 100644 index 00000000000..6dae894ae62 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/advice-precedence-tests.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/after-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/after-advice-tests.xml new file mode 100644 index 00000000000..9a55cc823e3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/after-advice-tests.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterReturning-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterReturning-advice-tests.xml new file mode 100644 index 00000000000..197afbf0695 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterReturning-advice-tests.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterThrowing-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterThrowing-advice-tests.xml new file mode 100644 index 00000000000..9152fe1853e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/afterThrowing-advice-tests.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ambiguous-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ambiguous-advice-tests.xml new file mode 100644 index 00000000000..3268b8ccecc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/ambiguous-advice-tests.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/args-mismatch.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/args-mismatch.xml new file mode 100644 index 00000000000..d82ac51900c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/args-mismatch.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-circular-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-circular-tests.xml new file mode 100644 index 00000000000..7f947101837 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-circular-tests.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-tests.xml new file mode 100644 index 00000000000..91ca7c6540c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/around-advice-tests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/aspectj.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/aspectj.xml new file mode 100644 index 00000000000..8a23b5ad4d5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/aspectj.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectImplementingInterfaceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectImplementingInterfaceTests.java new file mode 100644 index 00000000000..3ef06b4001b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectImplementingInterfaceTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.aop.framework.Advised; +import org.springframework.beans.ITestBean; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * Test for ensuring the aspects aren't advised. See SPR-3893 for more details. + * + * @author Ramnivas Laddad + */ +public class AspectImplementingInterfaceTests extends AbstractDependencyInjectionSpringContextTests { + protected ITestBean testBean; + protected AnInterface interfaceExtendingAspect; + + public AspectImplementingInterfaceTests() { + setPopulateProtectedVariables(true); + } + + protected String getConfigPath() { + return "aspect-implementing-interface-tests.xml"; + } + + protected void onSetUp() throws Exception { + super.onSetUp(); + } + + public void testProxyCreation() { + assertTrue(testBean instanceof Advised); + assertFalse(interfaceExtendingAspect instanceof Advised); + } + + public static interface AnInterface { + public void interfaceMethod(); + } + + public static class InterfaceExtendingAspect implements AnInterface { + public void increment(ProceedingJoinPoint pjp) throws Throwable { + pjp.proceed(); + } + + public void interfaceMethod() { + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparatorTests.java new file mode 100644 index 00000000000..7e8374f4b3a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparatorTests.java @@ -0,0 +1,223 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.aop.Advisor; +import org.springframework.aop.AfterReturningAdvice; +import org.springframework.aop.BeforeAdvice; +import org.springframework.aop.aspectj.AbstractAspectJAdvice; +import org.springframework.aop.aspectj.AspectJAfterAdvice; +import org.springframework.aop.aspectj.AspectJAfterReturningAdvice; +import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice; +import org.springframework.aop.aspectj.AspectJAroundAdvice; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice; +import org.springframework.aop.aspectj.AspectJPointcutAdvisor; +import org.springframework.aop.support.DefaultPointcutAdvisor; + +/** + * @author Adrian Colyer + */ +public class AspectJPrecedenceComparatorTests extends TestCase { + + /* + * Specification for the comparator (as defined in the + * AspectJPrecedenceComparator class) + * + *

+ * Orders AspectJ advice/advisors by invocation order. + *

+ *

+ * Given two pieces of advice, a and b: + *

+ * + */ + + private static final int HIGH_PRECEDENCE_ADVISOR_ORDER = 100; + private static final int LOW_PRECEDENCE_ADVISOR_ORDER = 200; + private static final int EARLY_ADVICE_DECLARATION_ORDER = 5; + private static final int LATE_ADVICE_DECLARATION_ORDER = 10; + + + private AspectJPrecedenceComparator comparator; + + private Method anyOldMethod; + + private AspectJExpressionPointcut anyOldPointcut; + + + protected void setUp() throws Exception { + this.comparator = new AspectJPrecedenceComparator(); + this.anyOldMethod = getClass().getMethods()[0]; + this.anyOldPointcut = new AspectJExpressionPointcut(); + this.anyOldPointcut.setExpression("execution(* *(..))"); + } + + + public void testSameAspectNoAfterAdvice() { + Advisor advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + assertEquals("advisor2 sorted before advisor1", 1, this.comparator.compare(advisor1, advisor2)); + } + + public void testSameAspectAfterAdvice() { + Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + assertEquals("advisor2 sorted before advisor1", 1, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createAspectJAfterReturningAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + advisor2 = createAspectJAfterThrowingAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2)); + } + + public void testSameAspectOneOfEach() { + Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + assertEquals("advisor1 and advisor2 not comparable", 0, this.comparator.compare(advisor1, advisor2)); + } + + public void testSameAdvisorPrecedenceDifferentAspectNoAfterAdvice() { + Advisor advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2)); + } + + public void testSameAdvisorPrecedenceDifferentAspectAfterAdvice() { + Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createAspectJAfterReturningAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + advisor2 = createAspectJAfterThrowingAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2)); + } + + public void testHigherAdvisorPrecedenceNoAfterAdvice() { + Advisor advisor1 = createSpringAOPBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER); + Advisor advisor2 = createAspectJBeforeAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + advisor2 = createAspectJAroundAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2)); + } + + public void testHigherAdvisorPrecedenceAfterAdvice() { + Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJAroundAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createAspectJAfterReturningAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + advisor2 = createAspectJAfterThrowingAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor2 sorted after advisor1", -1, this.comparator.compare(advisor1, advisor2)); + } + + public void testLowerAdvisorPrecedenceNoAfterAdvice() { + Advisor advisor1 = createAspectJBeforeAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createAspectJBeforeAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect"); + advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2)); + } + + public void testLowerAdvisorPrecedenceAfterAdvice() { + Advisor advisor1 = createAspectJAfterAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect"); + Advisor advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2)); + + advisor1 = createSpringAOPAfterAdvice(LOW_PRECEDENCE_ADVISOR_ORDER); + advisor2 = createAspectJAfterThrowingAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect"); + assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2)); + } + + + private Advisor createAspectJBeforeAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) { + AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(this.anyOldMethod, this.anyOldPointcut, null); + return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice); + } + + private Advisor createAspectJAroundAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) { + AspectJAroundAdvice advice = new AspectJAroundAdvice(this.anyOldMethod, this.anyOldPointcut, null); + return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice); + } + + private Advisor createAspectJAfterAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) { + AspectJAfterAdvice advice = new AspectJAfterAdvice(this.anyOldMethod, this.anyOldPointcut, null); + return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice); + } + + private Advisor createAspectJAfterReturningAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) { + AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(this.anyOldMethod, this.anyOldPointcut, null); + return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice); + } + + private Advisor createAspectJAfterThrowingAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) { + AspectJAfterThrowingAdvice advice = new AspectJAfterThrowingAdvice(this.anyOldMethod, this.anyOldPointcut, null); + return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice); + } + + private Advisor createAspectJAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName, AbstractAspectJAdvice advice) { + advice.setDeclarationOrder(adviceDeclarationOrder); + advice.setAspectName(aspectName); + AspectJPointcutAdvisor advisor = new AspectJPointcutAdvisor(advice); + advisor.setOrder(advisorOrder); + return advisor; + } + + private Advisor createSpringAOPAfterAdvice(int order) { + AfterReturningAdvice advice = new AfterReturningAdvice() { + public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { + } + }; + DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(this.anyOldPointcut, advice); + advisor.setOrder(order); + return advisor; + } + + private Advisor createSpringAOPBeforeAdvice(int order) { + BeforeAdvice advice = new BeforeAdvice() { + }; + DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(this.anyOldPointcut, advice); + advisor.setOrder(order); + return advisor; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspect-implementing-interface-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspect-implementing-interface-tests.xml new file mode 100644 index 00000000000..dffe959a329 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/autoproxy/aspect-implementing-interface-tests.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-tests.xml new file mode 100644 index 00000000000..66ccb584951 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/bean-name-pointcut-tests.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/before-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/before-advice-tests.xml new file mode 100644 index 00000000000..d12031f34eb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/before-advice-tests.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-delegate-ref-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-delegate-ref-tests.xml new file mode 100644 index 00000000000..0c6ee0117b9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-delegate-ref-tests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-tests.xml new file mode 100644 index 00000000000..f8b682c84f7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/declare-parents-tests.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-tests.xml new file mode 100644 index 00000000000..1c10ec952fe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/implicit-jp-argument-matching-tests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/overloaded-advice-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/overloaded-advice-tests.xml new file mode 100644 index 00000000000..57f3f9dd4d7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/overloaded-advice-tests.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/proceedTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/proceedTests.xml new file mode 100644 index 00000000000..2b4ca898e2f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/proceedTests.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/subtype-sensitive-matching.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/subtype-sensitive-matching.xml new file mode 100644 index 00000000000..6fb76c1b525 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/subtype-sensitive-matching.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/targetPointcutSelectionTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/targetPointcutSelectionTests.xml new file mode 100644 index 00000000000..1e57557518f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/targetPointcutSelectionTests.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-tests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-tests.xml new file mode 100644 index 00000000000..acf51f5ccd8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/this-and-target-selectionOnly-pointcuts-tests.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/topsy-turvy-aspect.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/topsy-turvy-aspect.xml new file mode 100644 index 00000000000..f0d90523d9e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/aspectj/topsy-turvy-aspect.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceAdviceTypeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceAdviceTypeTests.java new file mode 100644 index 00000000000..a62a6dec0e4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceAdviceTypeTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.xml.sax.SAXParseException; + +/** + * @author Adrian Colyer + */ +public class AopNamespaceAdviceTypeTests extends TestCase { + + private ApplicationContext context; + + protected String getOKConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerAdviceTypeOKTests.xml"; + } + + protected String getErrorConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerAdviceTypeErrorTests.xml"; + } + + public void testParsingOfAdviceTypes() { + this.context = new ClassPathXmlApplicationContext(getOKConfigLocation()); + } + + public void testParsingOfAdviceTypesWithError() { + try { + this.context = new ClassPathXmlApplicationContext(getErrorConfigLocation()); + fail("Expected BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + assertTrue(ex.contains(SAXParseException.class)); + } + } + + protected ITestBean getTestBean() { + return (ITestBean) this.context.getBean("testBean"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerArgNamesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerArgNamesTests.java new file mode 100644 index 00000000000..6f58ae39319 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerArgNamesTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Adrian Colyer + */ +public class AopNamespaceHandlerArgNamesTests extends TestCase { + + private ApplicationContext context; + + protected String getOKConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerArgNamesOKTests.xml"; + } + + protected String getErrorConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerArgNamesErrorTests.xml"; + } + + public void testArgNamesOK() { + this.context = new ClassPathXmlApplicationContext(getOKConfigLocation()); + } + + public void testArgNamesError() { + try { + this.context = new ClassPathXmlApplicationContext(getErrorConfigLocation()); + fail("Expected BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.contains(IllegalArgumentException.class)); + } + } + + protected ITestBean getTestBean() { + return (ITestBean) this.context.getBean("testBean"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java new file mode 100644 index 00000000000..7e49b8e845f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java @@ -0,0 +1,181 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CollectingReaderEventListener; +import org.springframework.beans.factory.parsing.ComponentDefinition; +import org.springframework.beans.factory.parsing.CompositeComponentDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AopNamespaceHandlerEventTests extends TestCase { + + private CollectingReaderEventListener eventListener = new CollectingReaderEventListener(); + + private XmlBeanDefinitionReader reader; + + private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + + + protected void setUp() throws Exception { + this.reader = new XmlBeanDefinitionReader(this.beanFactory); + this.reader.setEventListener(this.eventListener); + } + + public void testPointcutEvents() throws Exception { + loadBeansFrom("aopNamespaceHandlerPointcutEventTests.xml"); + ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions(); + assertEquals("Incorrect number of events fired", 1, componentDefinitions.length); + assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition); + + CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0]; + assertEquals("aop:config", compositeDef.getName()); + + ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents(); + assertEquals("Incorrect number of inner components", 2, nestedComponentDefs.length); + PointcutComponentDefinition pcd = null; + for (int i = 0; i < nestedComponentDefs.length; i++) { + ComponentDefinition componentDefinition = nestedComponentDefs[i]; + if (componentDefinition instanceof PointcutComponentDefinition) { + pcd = (PointcutComponentDefinition) componentDefinition; + break; + } + } + assertNotNull("PointcutComponentDefinition not found", pcd); + assertEquals("Incorrect number of BeanDefinitions", 1, pcd.getBeanDefinitions().length); + } + + public void testAdvisorEventsWithPointcutRef() throws Exception { + loadBeansFrom("aopNamespaceHandlerAdvisorWithPointcutRefEventTests.xml"); + ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions(); + assertEquals("Incorrect number of events fired", 2, componentDefinitions.length); + + assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition); + CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0]; + assertEquals("aop:config", compositeDef.getName()); + + ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents(); + assertEquals("Incorrect number of inner components", 3, nestedComponentDefs.length); + AdvisorComponentDefinition acd = null; + for (int i = 0; i < nestedComponentDefs.length; i++) { + ComponentDefinition componentDefinition = nestedComponentDefs[i]; + if (componentDefinition instanceof AdvisorComponentDefinition) { + acd = (AdvisorComponentDefinition) componentDefinition; + break; + } + } + assertNotNull("AdvisorComponentDefinition not found", acd); + assertEquals(1, acd.getBeanDefinitions().length); + assertEquals(2, acd.getBeanReferences().length); + + assertTrue("No advice bean found", componentDefinitions[1] instanceof BeanComponentDefinition); + BeanComponentDefinition adviceDef = (BeanComponentDefinition) componentDefinitions[1]; + assertEquals("countingAdvice", adviceDef.getBeanName()); + } + + public void testAdvisorEventsWithDirectPointcut() throws Exception { + loadBeansFrom("aopNamespaceHandlerAdvisorWithDirectPointcutEventTests.xml"); + ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions(); + assertEquals("Incorrect number of events fired", 2, componentDefinitions.length); + + assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition); + CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0]; + assertEquals("aop:config", compositeDef.getName()); + + ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents(); + assertEquals("Incorrect number of inner components", 2, nestedComponentDefs.length); + AdvisorComponentDefinition acd = null; + for (int i = 0; i < nestedComponentDefs.length; i++) { + ComponentDefinition componentDefinition = nestedComponentDefs[i]; + if (componentDefinition instanceof AdvisorComponentDefinition) { + acd = (AdvisorComponentDefinition) componentDefinition; + break; + } + } + assertNotNull("AdvisorComponentDefinition not found", acd); + assertEquals(2, acd.getBeanDefinitions().length); + assertEquals(1, acd.getBeanReferences().length); + + assertTrue("No advice bean found", componentDefinitions[1] instanceof BeanComponentDefinition); + BeanComponentDefinition adviceDef = (BeanComponentDefinition) componentDefinitions[1]; + assertEquals("countingAdvice", adviceDef.getBeanName()); + } + + public void testAspectEvent() throws Exception { + loadBeansFrom("aopNamespaceHandlerAspectEventTests.xml"); + ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions(); + assertEquals("Incorrect number of events fired", 5, componentDefinitions.length); + + assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition); + CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0]; + assertEquals("aop:config", compositeDef.getName()); + + ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents(); + assertEquals("Incorrect number of inner components", 2, nestedComponentDefs.length); + AspectComponentDefinition acd = null; + for (int i = 0; i < nestedComponentDefs.length; i++) { + ComponentDefinition componentDefinition = nestedComponentDefs[i]; + if (componentDefinition instanceof AspectComponentDefinition) { + acd = (AspectComponentDefinition) componentDefinition; + break; + } + } + + assertNotNull("AspectComponentDefinition not found", acd); + BeanDefinition[] beanDefinitions = acd.getBeanDefinitions(); + assertEquals(5, beanDefinitions.length); + BeanReference[] beanReferences = acd.getBeanReferences(); + assertEquals(6, beanReferences.length); + + Set expectedReferences = new HashSet(); + expectedReferences.add("pc"); + expectedReferences.add("countingAdvice"); + for (int i = 0; i < beanReferences.length; i++) { + BeanReference beanReference = beanReferences[i]; + expectedReferences.remove(beanReference.getBeanName()); + } + assertEquals("Incorrect references found", 0, expectedReferences.size()); + + for (int i = 1; i < componentDefinitions.length; i++) { + assertTrue(componentDefinitions[i] instanceof BeanComponentDefinition); + } + + ComponentDefinition[] nestedComponentDefs2 = acd.getNestedComponents(); + assertEquals("Inner PointcutComponentDefinition not found", 1, nestedComponentDefs2.length); + assertTrue(nestedComponentDefs2[0] instanceof PointcutComponentDefinition); + PointcutComponentDefinition pcd = (PointcutComponentDefinition) nestedComponentDefs2[0]; + assertEquals("Incorrect number of BeanDefinitions", 1, pcd.getBeanDefinitions().length); + } + + private void loadBeansFrom(String path) { + this.reader.loadBeanDefinitions(new ClassPathResource(path, getClass())); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java new file mode 100644 index 00000000000..c5dfcab6b07 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Mark Fisher + */ +public class AopNamespaceHandlerPointcutErrorTests extends TestCase { + + public void testDuplicatePointcutConfig() { + try { + new XmlBeanFactory(new ClassPathResource( + "org/springframework/aop/config/aopNamespaceHandlerPointcutDuplicationTests.xml")); + fail("parsing should have caused a BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + assertTrue(ex.contains(BeanDefinitionParsingException.class)); + } + } + + public void testMissingPointcutConfig() { + try { + new XmlBeanFactory(new ClassPathResource( + "org/springframework/aop/config/aopNamespaceHandlerPointcutMissingTests.xml")); + fail("parsing should have caused a BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + assertTrue(ex.contains(BeanDefinitionParsingException.class)); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerProxyTargetClassTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerProxyTargetClassTests.java new file mode 100644 index 00000000000..73e9f377be5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerProxyTargetClassTests.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.aop.config; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; + +/** + * @author Rob Harrop + */ +public class AopNamespaceHandlerProxyTargetClassTests extends AopNamespaceHandlerTests { + + public void testIsClassProxy() { + ITestBean bean = getTestBean(); + assertTrue("Should be a CGLIB proxy", AopUtils.isCglibProxy(bean)); + } + + protected String getConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerProxyTargetClassTests.xml"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerReturningTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerReturningTests.java new file mode 100644 index 00000000000..9852cdfef4e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerReturningTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.xml.sax.SAXParseException; + +/** + * @author Adrian Colyer + */ +public class AopNamespaceHandlerReturningTests extends TestCase { + + private ApplicationContext context; + + protected String getOKConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerReturningOKTests.xml"; + } + + protected String getErrorConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerReturningErrorTests.xml"; + } + + public void testReturningOnReturningAdvice() { + this.context = new ClassPathXmlApplicationContext(getOKConfigLocation()); + } + + public void testParseReturningOnOtherAdviceType() { + try { + this.context = new ClassPathXmlApplicationContext(getErrorConfigLocation()); + fail("Expected BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + assertTrue(ex.contains(SAXParseException.class)); + } + } + + protected ITestBean getTestBean() { + return (ITestBean) this.context.getBean("testBean"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeTests.java new file mode 100644 index 00000000000..e8bce909650 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeTests.java @@ -0,0 +1,106 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.context.support.XmlWebApplicationContext; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AopNamespaceHandlerScopeTests extends TestCase { + + private ApplicationContext context; + + public void setUp() { + XmlWebApplicationContext wac = new XmlWebApplicationContext(); + wac.setConfigLocations(new String[] {"classpath:org/springframework/aop/config/aopNamespaceHandlerScopeTests.xml"}); + wac.refresh(); + this.context = wac; + } + + public void testRequestScoping() throws Exception { + MockHttpServletRequest oldRequest = new MockHttpServletRequest(); + MockHttpServletRequest newRequest = new MockHttpServletRequest(); + + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(oldRequest)); + + ITestBean scoped = (ITestBean) this.context.getBean("requestScoped"); + assertTrue("Should be AOP proxy", AopUtils.isAopProxy(scoped)); + assertTrue("Should be target class proxy", scoped instanceof TestBean); + + ITestBean testBean = (ITestBean) this.context.getBean("testBean"); + assertTrue("Should be AOP proxy", AopUtils.isAopProxy(testBean)); + assertFalse("Regular bean should be JDK proxy", testBean instanceof TestBean); + + String rob = "Rob Harrop"; + String bram = "Bram Smeets"; + + assertEquals(rob, scoped.getName()); + scoped.setName(bram); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(newRequest)); + assertEquals(rob, scoped.getName()); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(oldRequest)); + assertEquals(bram, scoped.getName()); + + assertTrue("Should have advisors", ((Advised) scoped).getAdvisors().length > 0); + } + + public void testSessionScoping() throws Exception { + MockHttpSession oldSession = new MockHttpSession(); + MockHttpSession newSession = new MockHttpSession(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(oldSession); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + + ITestBean scoped = (ITestBean) this.context.getBean("sessionScoped"); + assertTrue("Should be AOP proxy", AopUtils.isAopProxy(scoped)); + assertFalse("Should not be target class proxy", scoped instanceof TestBean); + + ITestBean scopedAlias = (ITestBean) this.context.getBean("sessionScopedAlias"); + assertSame(scoped, scopedAlias); + + ITestBean testBean = (ITestBean) this.context.getBean("testBean"); + assertTrue("Should be AOP proxy", AopUtils.isAopProxy(testBean)); + assertFalse("Regular bean should be JDK proxy", testBean instanceof TestBean); + + String rob = "Rob Harrop"; + String bram = "Bram Smeets"; + + assertEquals(rob, scoped.getName()); + scoped.setName(bram); + request.setSession(newSession); + assertEquals(rob, scoped.getName()); + request.setSession(oldSession); + assertEquals(bram, scoped.getName()); + + assertTrue("Should have advisors", ((Advised) scoped).getAdvisors().length > 0); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerTests.java new file mode 100644 index 00000000000..70e57beed78 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerTests.java @@ -0,0 +1,98 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; +import org.springframework.aop.Advisor; +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.CountingBeforeAdvice; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Rob Harrop + */ +public class AopNamespaceHandlerTests extends TestCase { + + private ApplicationContext context; + + public void setUp() { + this.context = new ClassPathXmlApplicationContext(getConfigLocation()); + } + + protected String getConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerTests.xml"; + } + + public void testIsProxy() throws Exception { + ITestBean bean = getTestBean(); + + assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean)); + + // check the advice details + Advised advised = (Advised) bean; + Advisor[] advisors = advised.getAdvisors(); + + assertTrue("Advisors should not be empty", advisors.length > 0); + } + + public void testAdviceInvokedCorrectly() throws Exception { + CountingBeforeAdvice getAgeCounter = (CountingBeforeAdvice) this.context.getBean("getAgeCounter"); + CountingBeforeAdvice getNameCounter = (CountingBeforeAdvice) this.context.getBean("getNameCounter"); + + ITestBean bean = getTestBean(); + + assertEquals("Incorrect initial getAge count", 0, getAgeCounter.getCalls("getAge")); + assertEquals("Incorrect initial getName count", 0, getNameCounter.getCalls("getName")); + + bean.getAge(); + + assertEquals("Incorrect getAge count on getAge counter", 1, getAgeCounter.getCalls("getAge")); + assertEquals("Incorrect getAge count on getName counter", 0, getNameCounter.getCalls("getAge")); + + bean.getName(); + + assertEquals("Incorrect getName count on getName counter", 1, getNameCounter.getCalls("getName")); + assertEquals("Incorrect getName count on getAge counter", 0, getAgeCounter.getCalls("getName")); + } + + public void testAspectApplied() throws Exception { + ITestBean testBean = getTestBean(); + + CountingAspectJAdvice advice = (CountingAspectJAdvice) this.context.getBean("countingAdvice"); + + assertEquals("Incorrect before count", 0, advice.getBeforeCount()); + assertEquals("Incorrect after count", 0, advice.getAfterCount()); + + testBean.setName("Sally"); + + assertEquals("Incorrect before count", 1, advice.getBeforeCount()); + assertEquals("Incorrect after count", 1, advice.getAfterCount()); + + testBean.getName(); + + assertEquals("Incorrect before count", 1, advice.getBeforeCount()); + assertEquals("Incorrect after count", 1, advice.getAfterCount()); + } + + protected ITestBean getTestBean() { + return (ITestBean) this.context.getBean("testBean"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerThrowingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerThrowingTests.java new file mode 100644 index 00000000000..597e069ee90 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/AopNamespaceHandlerThrowingTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.xml.sax.SAXParseException; + +/** + * @author Adrian Colyer + */ +public class AopNamespaceHandlerThrowingTests extends TestCase { + + private ApplicationContext context; + + protected String getOKConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerThrowingOKTests.xml"; + } + + protected String getErrorConfigLocation() { + return "org/springframework/aop/config/aopNamespaceHandlerThrowingErrorTests.xml"; + } + + public void testThrowingOnThrowingAdvice() { + this.context = new ClassPathXmlApplicationContext(getOKConfigLocation()); + } + + public void testParseThrowingOnOtherAdviceType() { + try { + this.context = new ClassPathXmlApplicationContext(getErrorConfigLocation()); + fail("Expected BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + assertTrue(ex.contains(SAXParseException.class)); + } + } + + protected ITestBean getTestBean() { + return (ITestBean) this.context.getBean("testBean"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/CountingAspectJAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/CountingAspectJAdvice.java new file mode 100644 index 00000000000..6251cf40948 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/CountingAspectJAdvice.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.beans.ITestBean; + +/** + * @author Rob Harrop + */ +public class CountingAspectJAdvice { + + private int beforeCount; + + private int afterCount; + + private int aroundCount; + + public void myBeforeAdvice() throws Throwable { + this.beforeCount++; + } + + public void myAfterAdvice() throws Throwable { + this.afterCount++; + } + + public void myAroundAdvice(ProceedingJoinPoint pjp) throws Throwable { + this.aroundCount++; + pjp.proceed(); + } + + public void myAfterReturningAdvice(int age) { + this.afterCount++; + } + + public void myAfterThrowingAdvice(RuntimeException ex) { + this.afterCount++; + } + + public void mySetAgeAdvice(int newAge, ITestBean bean) { + // no-op + } + + public int getBeforeCount() { + return this.beforeCount; + } + + public int getAfterCount() { + return this.afterCount; + } + + public int getAroundCount() { + return this.aroundCount; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/MethodLocatingFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/MethodLocatingFactoryBeanTests.java new file mode 100644 index 00000000000..55699b56fae --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/MethodLocatingFactoryBeanTests.java @@ -0,0 +1,183 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.mock.easymock.AbstractScalarMockTemplate; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + */ +public final class MethodLocatingFactoryBeanTests extends TestCase { + + private static final String BEAN_NAME = "string"; + + + public void testIsSingleton() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + assertTrue(factory.isSingleton()); + } + + public void testGetObjectType() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + assertEquals(Method.class, factory.getObjectType()); + } + + public void testWithNullTargetBeanName() throws Exception { + new BeanFactoryScalarMockTemplate() { + public void doTestInternal(final BeanFactory beanFactory) throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + factory.setMethodName("toString()"); + factory.setBeanFactory(beanFactory); + } + }.runTest(); + } + }.test(); + } + + public void testWithEmptyTargetBeanName() throws Exception { + new BeanFactoryScalarMockTemplate() { + public void doTestInternal(final BeanFactory beanFactory) throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + factory.setTargetBeanName(""); + factory.setMethodName("toString()"); + factory.setBeanFactory(beanFactory); + } + }.runTest(); + } + }.test(); + } + + public void testWithNullTargetMethodName() throws Exception { + new BeanFactoryScalarMockTemplate() { + public void doTestInternal(final BeanFactory beanFactory) throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + factory.setTargetBeanName(BEAN_NAME); + factory.setBeanFactory(beanFactory); + } + }.runTest(); + } + }.test(); + } + + public void testWithEmptyTargetMethodName() throws Exception { + new BeanFactoryScalarMockTemplate() { + public void doTestInternal(final BeanFactory beanFactory) throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + factory.setTargetBeanName(BEAN_NAME); + factory.setMethodName(""); + factory.setBeanFactory(beanFactory); + } + }.runTest(); + } + }.test(); + } + + public void testWhenTargetBeanClassCannotBeResolved() throws Exception { + new BeanFactoryScalarMockTemplate() { + protected void setupBeanFactoryExpectations(MockControl mockControl, BeanFactory beanFactory) throws Exception { + beanFactory.getType(BEAN_NAME); + mockControl.setReturnValue(null); + } + protected void doTestInternal(final BeanFactory beanFactory) throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + factory.setTargetBeanName(BEAN_NAME); + factory.setMethodName("toString()"); + factory.setBeanFactory(beanFactory); + } + }.runTest(); + } + }.test(); + } + + public void testSunnyDayPath() throws Exception { + new BeanFactoryScalarMockTemplate() { + protected void setupBeanFactoryExpectations(MockControl mockControl, BeanFactory beanFactory) throws Exception { + beanFactory.getType(BEAN_NAME); + mockControl.setReturnValue(String.class); + } + protected void doTestInternal(final BeanFactory beanFactory) throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + factory.setTargetBeanName(BEAN_NAME); + factory.setMethodName("toString()"); + factory.setBeanFactory(beanFactory); + Object result = factory.getObject(); + assertNotNull(result); + assertTrue(result instanceof Method); + Method method = (Method) result; + assertEquals("Bingo", method.invoke("Bingo", new Object[]{})); + } + }.test(); + } + + public void testWhereMethodCannotBeResolved() throws Exception { + new BeanFactoryScalarMockTemplate() { + protected void setupBeanFactoryExpectations(MockControl mockControl, BeanFactory beanFactory) throws Exception { + beanFactory.getType(BEAN_NAME); + mockControl.setReturnValue(String.class); + } + protected void doTestInternal(final BeanFactory beanFactory) throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MethodLocatingFactoryBean factory = new MethodLocatingFactoryBean(); + factory.setTargetBeanName(BEAN_NAME); + factory.setMethodName("loadOfOld()"); + factory.setBeanFactory(beanFactory); + } + }.runTest(); + } + }.test(); + } + + + private static abstract class BeanFactoryScalarMockTemplate extends AbstractScalarMockTemplate { + + public BeanFactoryScalarMockTemplate() { + super(BeanFactory.class); + } + + public void setupExpectations(MockControl mockControl, Object mockObject) throws Exception { + setupBeanFactoryExpectations(mockControl, (BeanFactory) mockObject); + } + + public void doTest(Object mockObject) throws Exception { + doTestInternal((BeanFactory) mockObject); + } + + protected void setupBeanFactoryExpectations(MockControl mockControl, BeanFactory beanFactory) throws Exception { + } + + protected abstract void doTestInternal(final BeanFactory beanFactory) throws Exception; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/PrototypeProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/PrototypeProxyTests.java new file mode 100644 index 00000000000..1c64d884c7c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/PrototypeProxyTests.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Juergen Hoeller + */ +public class PrototypeProxyTests extends TestCase { + + public void testInjectionBeforeWrappingCheckDoesNotKickInForPrototypeProxy() { + new ClassPathXmlApplicationContext("prototypeProxy.xml", getClass()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java new file mode 100644 index 00000000000..f9d6f66e565 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.config; + +import junit.framework.TestCase; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +/** + * Tests that the <aop:config/> element can be used as a top level element. + * + * @author Rob Harrop + */ +public final class TopLevelAopTagTests extends TestCase { + + public void testParse() throws Exception { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + reader.loadBeanDefinitions(new ClassPathResource("topLevelAop.xml", getClass())); + + assertTrue(beanFactory.containsBeanDefinition("testPointcut")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeErrorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeErrorTests.xml new file mode 100644 index 00000000000..efdd2acb7c2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeErrorTests.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeOKTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeOKTests.xml new file mode 100644 index 00000000000..157ffe66781 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdviceTypeOKTests.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithDirectPointcutEventTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithDirectPointcutEventTests.xml new file mode 100644 index 00000000000..42291802335 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithDirectPointcutEventTests.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithPointcutRefEventTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithPointcutRefEventTests.xml new file mode 100644 index 00000000000..23e4a88b3fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAdvisorWithPointcutRefEventTests.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesErrorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesErrorTests.xml new file mode 100644 index 00000000000..c156060d093 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesErrorTests.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesOKTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesOKTests.xml new file mode 100644 index 00000000000..1cafd6663a1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerArgNamesOKTests.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAspectEventTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAspectEventTests.xml new file mode 100644 index 00000000000..157ffe66781 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerAspectEventTests.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutDuplicationTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutDuplicationTests.xml new file mode 100644 index 00000000000..e5c02022290 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutDuplicationTests.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutEventTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutEventTests.xml new file mode 100644 index 00000000000..8350030c171 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutEventTests.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutMissingTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutMissingTests.xml new file mode 100644 index 00000000000..712c5c783ba --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerPointcutMissingTests.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerProxyTargetClassTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerProxyTargetClassTests.xml new file mode 100644 index 00000000000..4d0f93b4e70 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerProxyTargetClassTests.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningErrorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningErrorTests.xml new file mode 100644 index 00000000000..26da583dd3d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningErrorTests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningOKTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningOKTests.xml new file mode 100644 index 00000000000..17f64373dcc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerReturningOKTests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerScopeTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerScopeTests.xml new file mode 100644 index 00000000000..d57f82193cb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerScopeTests.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerTests.xml new file mode 100644 index 00000000000..1ac7a3c38be --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerTests.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingErrorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingErrorTests.xml new file mode 100644 index 00000000000..1334e21719b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingErrorTests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingOKTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingOKTests.xml new file mode 100644 index 00000000000..86d7624c0a6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/aopNamespaceHandlerThrowingOKTests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/prototypeProxy.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/prototypeProxy.xml new file mode 100644 index 00000000000..a46f0bec3b2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/prototypeProxy.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/config/topLevelAop.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/topLevelAop.xml new file mode 100644 index 00000000000..6c9e44b560f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/config/topLevelAop.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java new file mode 100644 index 00000000000..9ce0ed576b1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java @@ -0,0 +1,1838 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.transaction.TransactionRequiredException; + +import junit.framework.TestCase; +import org.aopalliance.aop.Advice; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.aop.Advisor; +import org.springframework.aop.AfterReturningAdvice; +import org.springframework.aop.DynamicIntroductionAdvice; +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.TargetSource; +import org.springframework.aop.framework.adapter.ThrowsAdviceInterceptorTests; +import org.springframework.aop.interceptor.DebugInterceptor; +import org.springframework.aop.interceptor.ExposeInvocationInterceptor; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.interceptor.SerializableNopInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.support.DefaultIntroductionAdvisor; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.DelegatingIntroductionInterceptor; +import org.springframework.aop.support.DynamicMethodMatcherPointcut; +import org.springframework.aop.support.NameMatchMethodPointcut; +import org.springframework.aop.support.Pointcuts; +import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; +import org.springframework.aop.target.HotSwappableTargetSource; +import org.springframework.aop.target.SingletonTargetSource; +import org.springframework.beans.IOther; +import org.springframework.beans.ITestBean; +import org.springframework.beans.Person; +import org.springframework.beans.SerializablePerson; +import org.springframework.beans.TestBean; +import org.springframework.jdbc.CannotGetJdbcConnectionException; +import org.springframework.util.SerializationTestUtils; +import org.springframework.util.StopWatch; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 13.03.2003 + */ +public abstract class AbstractAopProxyTests extends TestCase { + + protected final MockTargetSource mockTargetSource = new MockTargetSource(); + + + /** + * Make a clean target source available if code wants to use it. + * The target must be set. Verification will be automatic in tearDown + * to ensure that it was used appropriately by code. + */ + protected void setUp() { + mockTargetSource.reset(); + } + + protected void tearDown() { + mockTargetSource.verify(); + } + + + /** + * Set in CGLIB or JDK mode. + */ + protected abstract Object createProxy(ProxyCreatorSupport as); + + protected abstract AopProxy createAopProxy(AdvisedSupport as); + + /** + * Is a target always required? + */ + protected boolean requiresTarget() { + return false; + } + + + public void testNoInterceptorsAndNoTarget() { + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class}); + // Add no interceptors + try { + AopProxy aop = createAopProxy(pc); + aop.getProxy(); + fail("Shouldn't allow no interceptors"); + } + catch (AopConfigException ex) { + // Ok + } + } + + /** + * Simple test that if we set values we can get them out again. + */ + public void testValuesStick() { + int age1 = 33; + int age2 = 37; + String name = "tony"; + + TestBean target1 = new TestBean(); + target1.setAge(age1); + ProxyFactory pf1 = new ProxyFactory(target1); + pf1.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + pf1.addAdvisor(new DefaultPointcutAdvisor(new TimestampIntroductionInterceptor())); + ITestBean tb = (ITestBean) pf1.getProxy(); + + assertEquals(age1, tb.getAge()); + tb.setAge(age2); + assertEquals(age2, tb.getAge()); + assertNull(tb.getName()); + tb.setName(name); + assertEquals(name, tb.getName()); + } + + /** + * This is primarily a test for the efficiency of our + * usage of CGLIB. If we create too many classes with + * CGLIB this will be slow or will run out of memory. + */ + public void testManyProxies() { + int howMany = 10000; + StopWatch sw = new StopWatch(); + sw.start("Create " + howMany + " proxies"); + testManyProxies(howMany); + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("Proxy creation was too slow", sw.getTotalTimeMillis() < 5000); + } + + private void testManyProxies(int howMany) { + int age1 = 33; + TestBean target1 = new TestBean(); + target1.setAge(age1); + ProxyFactory pf1 = new ProxyFactory(target1); + pf1.addAdvice(new NopInterceptor()); + pf1.addAdvice(new NopInterceptor()); + ITestBean proxies[] = new ITestBean[howMany]; + for (int i = 0; i < howMany; i++) { + proxies[i] = (ITestBean) createAopProxy(pf1).getProxy(); + assertEquals(age1, proxies[i].getAge()); + } + } + + public void testSerializationAdviceAndTargetNotSerializable() throws Exception { + TestBean tb = new TestBean(); + assertFalse(SerializationTestUtils.isSerializable(tb)); + + ProxyFactory pf = new ProxyFactory(tb); + + pf.addAdvice(new NopInterceptor()); + ITestBean proxy = (ITestBean) createAopProxy(pf).getProxy(); + + assertFalse(SerializationTestUtils.isSerializable(proxy)); + } + + public void testSerializationAdviceNotSerializable() throws Exception { + SerializablePerson sp = new SerializablePerson(); + assertTrue(SerializationTestUtils.isSerializable(sp)); + + ProxyFactory pf = new ProxyFactory(sp); + + // This isn't serializable + Advice i = new NopInterceptor(); + pf.addAdvice(i); + assertFalse(SerializationTestUtils.isSerializable(i)); + Object proxy = createAopProxy(pf).getProxy(); + + assertFalse(SerializationTestUtils.isSerializable(proxy)); + } + + public void testSerializationSerializableTargetAndAdvice() throws Throwable { + SerializablePerson personTarget = new SerializablePerson(); + personTarget.setName("jim"); + personTarget.setAge(26); + + assertTrue(SerializationTestUtils.isSerializable(personTarget)); + + ProxyFactory pf = new ProxyFactory(personTarget); + + CountingThrowsAdvice cta = new CountingThrowsAdvice(); + + pf.addAdvice(new SerializableNopInterceptor()); + // Try various advice types + pf.addAdvice(new CountingBeforeAdvice()); + pf.addAdvice(new CountingAfterReturningAdvice()); + pf.addAdvice(cta); + Person p = (Person) createAopProxy(pf).getProxy(); + + p.echo(null); + assertEquals(0, cta.getCalls()); + try { + p.echo(new ServletException()); + } + catch (ServletException ex) { + + } + assertEquals(1, cta.getCalls()); + + // Will throw exception if it fails + Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p); + assertNotSame(p, p2); + assertEquals(p.getName(), p2.getName()); + assertEquals(p.getAge(), p2.getAge()); + assertTrue("Deserialized object is an AOP proxy", AopUtils.isAopProxy(p2)); + + Advised a1 = (Advised) p; + Advised a2 = (Advised) p2; + // Check we can manipulate state of p2 + assertEquals(a1.getAdvisors().length, a2.getAdvisors().length); + + // This should work as SerializablePerson is equal + assertEquals("Proxies should be equal, even after one was serialized", p, p2); + assertEquals("Proxies should be equal, even after one was serialized", p2, p); + + // Check we can add a new advisor to the target + NopInterceptor ni = new NopInterceptor(); + p2.getAge(); + assertEquals(0, ni.getCount()); + a2.addAdvice(ni); + p2.getAge(); + assertEquals(1, ni.getCount()); + + cta = (CountingThrowsAdvice) a2.getAdvisors()[3].getAdvice(); + p2.echo(null); + assertEquals(1, cta.getCalls()); + try { + p2.echo(new ServletException()); + } + catch (ServletException ex) { + + } + assertEquals(2, cta.getCalls()); + + } + + /** + * Check that the two MethodInvocations necessary are independent and + * don't conflict. + * Check also proxy exposure. + */ + public void testOneAdvisedObjectCallsAnother() { + int age1 = 33; + int age2 = 37; + + TestBean target1 = new TestBean(); + ProxyFactory pf1 = new ProxyFactory(target1); + // Permit proxy and invocation checkers to get context from AopContext + pf1.setExposeProxy(true); + NopInterceptor di1 = new NopInterceptor(); + pf1.addAdvice(0, di1); + pf1.addAdvice(1, new ProxyMatcherInterceptor()); + pf1.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor()); + pf1.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor()); + // Must be first + pf1.addAdvice(0, ExposeInvocationInterceptor.INSTANCE); + ITestBean advised1 = (ITestBean) pf1.getProxy(); + advised1.setAge(age1); // = 1 invocation + + TestBean target2 = new TestBean(); + ProxyFactory pf2 = new ProxyFactory(target2); + pf2.setExposeProxy(true); + NopInterceptor di2 = new NopInterceptor(); + pf2.addAdvice(0, di2); + pf2.addAdvice(1, new ProxyMatcherInterceptor()); + pf2.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor()); + pf2.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor()); + pf2.addAdvice(0, ExposeInvocationInterceptor.INSTANCE); + //System.err.println(pf2.toProxyConfigString()); + ITestBean advised2 = (ITestBean) createProxy(pf2); + advised2.setAge(age2); + advised1.setSpouse(advised2); // = 2 invocations + + assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations + assertEquals("Advised two has correct age", age2, advised2.getAge()); + // Means extra call on advised 2 + assertEquals("Advised one spouse has correct age", age2, advised1.getSpouse().getAge()); // = 4 invocations on 1 and another one on 2 + + assertEquals("one was invoked correct number of times", 4, di1.getCount()); + // Got hit by call to advised1.getSpouse().getAge() + assertEquals("one was invoked correct number of times", 3, di2.getCount()); + } + + + public void testReentrance() { + int age1 = 33; + + TestBean target1 = new TestBean(); + ProxyFactory pf1 = new ProxyFactory(target1); + NopInterceptor di1 = new NopInterceptor(); + pf1.addAdvice(0, di1); + ITestBean advised1 = (ITestBean) createProxy(pf1); + advised1.setAge(age1); // = 1 invocation + advised1.setSpouse(advised1); // = 2 invocations + + assertEquals("one was invoked correct number of times", 2, di1.getCount()); + + assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations + assertEquals("one was invoked correct number of times", 3, di1.getCount()); + + // = 5 invocations, as reentrant call to spouse is advised also + assertEquals("Advised spouse has correct age", age1, advised1.getSpouse().getAge()); + + assertEquals("one was invoked correct number of times", 5, di1.getCount()); + } + + public void testTargetCanGetProxy() { + NopInterceptor di = new NopInterceptor(); + INeedsToSeeProxy target = new TargetChecker(); + ProxyFactory proxyFactory = new ProxyFactory(target); + proxyFactory.setExposeProxy(true); + assertTrue(proxyFactory.isExposeProxy()); + + proxyFactory.addAdvice(0, di); + INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(proxyFactory); + assertEquals(0, di.getCount()); + assertEquals(0, target.getCount()); + proxied.incrementViaThis(); + assertEquals("Increment happened", 1, target.getCount()); + + assertEquals("Only one invocation via AOP as use of this wasn't proxied", 1, di.getCount()); + // 1 invocation + assertEquals("Increment happened", 1, proxied.getCount()); + proxied.incrementViaProxy(); // 2 invoocations + assertEquals("Increment happened", 2, target.getCount()); + assertEquals("3 more invocations via AOP as the first call was reentrant through the proxy", 4, di.getCount()); + } + + + public void testTargetCantGetProxyByDefault() { + NeedsToSeeProxy et = new NeedsToSeeProxy(); + ProxyFactory pf1 = new ProxyFactory(et); + assertFalse(pf1.isExposeProxy()); + INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(pf1); + try { + proxied.incrementViaProxy(); + fail("Should have failed to get proxy as exposeProxy wasn't set to true"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testContext() throws Throwable { + testContext(true); + } + + public void testNoContext() throws Throwable { + testContext(false); + } + + /** + * @param context if true, want context + */ + private void testContext(final boolean context) throws Throwable { + final String s = "foo"; + // Test return value + MethodInterceptor mi = new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + if (!context) { + assertNoInvocationContext(); + } else { + assertTrue("have context", ExposeInvocationInterceptor.currentInvocation() != null); + } + return s; + } + }; + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class}); + if (context) { + pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); + } + pc.addAdvice(mi); + // Keep CGLIB happy + if (requiresTarget()) { + pc.setTarget(new TestBean()); + } + AopProxy aop = createAopProxy(pc); + + assertNoInvocationContext(); + ITestBean tb = (ITestBean) aop.getProxy(); + assertNoInvocationContext(); + assertTrue("correct return value", tb.getName() == s); + } + + /** + * Test that the proxy returns itself when the + * target returns this + */ + public void testTargetReturnsThis() throws Throwable { + // Test return value + TestBean raw = new OwnSpouse(); + + ProxyCreatorSupport pc = new ProxyCreatorSupport(); + pc.setInterfaces(new Class[] {ITestBean.class}); + pc.setTarget(raw); + + ITestBean tb = (ITestBean) createProxy(pc); + assertTrue("this return is wrapped in proxy", tb.getSpouse() == tb); + } + + public void testDeclaredException() throws Throwable { + final Exception expectedException = new Exception(); + // Test return value + MethodInterceptor mi = new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + throw expectedException; + } + }; + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class}); + pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); + pc.addAdvice(mi); + + // We don't care about the object + mockTargetSource.setTarget(new Object()); + pc.setTargetSource(mockTargetSource); + AopProxy aop = createAopProxy(pc); + + try { + ITestBean tb = (ITestBean) aop.getProxy(); + // Note: exception param below isn't used + tb.exceptional(expectedException); + fail("Should have thrown exception raised by interceptor"); + } + catch (Exception thrown) { + assertEquals("exception matches", expectedException, thrown); + } + } + + /** + * An interceptor throws a checked exception not on the method signature. + * For efficiency, we don't bother unifying java.lang.reflect and + * net.sf.cglib UndeclaredThrowableException + */ + public void testUndeclaredCheckedException() throws Throwable { + final Exception unexpectedException = new Exception(); + // Test return value + MethodInterceptor mi = new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + throw unexpectedException; + } + }; + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class}); + pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); + pc.addAdvice(mi); + + // We don't care about the object + pc.setTarget(new TestBean()); + AopProxy aop = createAopProxy(pc); + ITestBean tb = (ITestBean) aop.getProxy(); + + try { + // Note: exception param below isn't used + tb.getAge(); + fail("Should have wrapped exception raised by interceptor"); + } + catch (UndeclaredThrowableException thrown) { + assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable()); + } + //catch (net.sf.cglib.proxy.UndeclaredThrowableException thrown) { + // assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable()); + //} + catch (Exception ex) { + ex.printStackTrace(); + fail("Didn't expect exception: " + ex); + } + } + + public void testUndeclaredUnheckedException() throws Throwable { + final RuntimeException unexpectedException = new RuntimeException(); + // Test return value + MethodInterceptor mi = new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + throw unexpectedException; + } + }; + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class}); + pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); + pc.addAdvice(mi); + + // We don't care about the object + pc.setTarget(new TestBean()); + AopProxy aop = createAopProxy(pc); + ITestBean tb = (ITestBean) aop.getProxy(); + + try { + // Note: exception param below isn't used + tb.getAge(); + fail("Should have wrapped exception raised by interceptor"); + } + catch (RuntimeException thrown) { + assertEquals("exception matches", unexpectedException, thrown); + } + //catch (net.sf.cglib.proxy.UndeclaredThrowableException thrown) { + // assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable()); + //} + } + + /** + * Check that although a method is eligible for advice chain optimization and + * direct reflective invocation, it doesn't happen if we've asked to see the proxy, + * so as to guarantee a consistent programming model. + * @throws Throwable + */ + public void testTargetCanGetInvocationEvenIfNoAdviceChain() throws Throwable { + NeedsToSeeProxy target = new NeedsToSeeProxy(); + AdvisedSupport pc = new AdvisedSupport(new Class[] {INeedsToSeeProxy.class}); + pc.setTarget(target); + pc.setExposeProxy(true); + + // Now let's try it with the special target + AopProxy aop = createAopProxy(pc); + INeedsToSeeProxy proxied = (INeedsToSeeProxy) aop.getProxy(); + // It will complain if it can't get the proxy + proxied.incrementViaProxy(); + } + + public void testTargetCanGetInvocation() throws Throwable { + final InvocationCheckExposedInvocationTestBean expectedTarget = new InvocationCheckExposedInvocationTestBean(); + + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class, IOther.class}); + pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); + TrapTargetInterceptor tii = new TrapTargetInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + // Assert that target matches BEFORE invocation returns + assertEquals("Target is correct", expectedTarget, invocation.getThis()); + return super.invoke(invocation); + } + }; + pc.addAdvice(tii); + pc.setTarget(expectedTarget); + AopProxy aop = createAopProxy(pc); + + ITestBean tb = (ITestBean) aop.getProxy(); + tb.getName(); + // Not safe to trap invocation + //assertTrue(tii.invocation == target.invocation); + + //assertTrue(target.invocation.getProxy() == tb); + + // ((IOther) tb).absquatulate(); + //MethodInvocation minv = tii.invocation; + //assertTrue("invoked on iother, not " + minv.getMethod().getDeclaringClass(), minv.getMethod().getDeclaringClass() == IOther.class); + //assertTrue(target.invocation == tii.invocation); + } + + /** + * Throw an exception if there is an Invocation. + */ + private void assertNoInvocationContext() { + try { + ExposeInvocationInterceptor.currentInvocation(); + fail("Expected no invocation context"); + } + catch (IllegalStateException ex) { + // ok + } + } + + /** + * Test stateful interceptor + */ + public void testMixinWithIntroductionAdvisor() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(new Class[] {ITestBean.class}); + pc.addAdvisor(new LockMixinAdvisor()); + pc.setTarget(tb); + + testTestBeanIntroduction(pc); + } + + public void testMixinWithIntroductionInfo() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(new Class[] {ITestBean.class}); + // We don't use an IntroductionAdvisor, we can just add an advice that implements IntroductionInfo + pc.addAdvice(new LockMixin()); + pc.setTarget(tb); + + testTestBeanIntroduction(pc); + } + + private void testTestBeanIntroduction(ProxyFactory pc) { + int newAge = 65; + ITestBean itb = (ITestBean) createProxy(pc); + itb.setAge(newAge); + assertTrue(itb.getAge() == newAge); + + Lockable lockable = (Lockable) itb; + assertFalse(lockable.locked()); + lockable.lock(); + + assertTrue(itb.getAge() == newAge); + try { + itb.setAge(1); + fail("Setters should fail when locked"); + } + catch (LockedException ex) { + // ok + } + assertTrue(itb.getAge() == newAge); + + // Unlock + assertTrue(lockable.locked()); + lockable.unlock(); + itb.setAge(1); + assertTrue(itb.getAge() == 1); + } + + + public void testReplaceArgument() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(new Class[] {ITestBean.class}); + pc.setTarget(tb); + pc.addAdvisor(new StringSetterNullReplacementAdvice()); + + ITestBean t = (ITestBean) pc.getProxy(); + int newAge = 5; + t.setAge(newAge); + assertTrue(t.getAge() == newAge); + String newName = "greg"; + t.setName(newName); + assertEquals(newName, t.getName()); + + t.setName(null); + // Null replacement magic should work + assertTrue(t.getName().equals("")); + } + + public void testCanCastProxyToProxyConfig() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(tb); + NopInterceptor di = new NopInterceptor(); + pc.addAdvice(0, di); + + ITestBean t = (ITestBean) createProxy(pc); + assertEquals(0, di.getCount()); + t.setAge(23); + assertEquals(23, t.getAge()); + assertEquals(2, di.getCount()); + + Advised advised = (Advised) t; + assertEquals("Have 1 advisor", 1, advised.getAdvisors().length); + assertEquals(di, advised.getAdvisors()[0].getAdvice()); + NopInterceptor di2 = new NopInterceptor(); + advised.addAdvice(1, di2); + t.getName(); + assertEquals(3, di.getCount()); + assertEquals(1, di2.getCount()); + // will remove di + advised.removeAdvisor(0); + t.getAge(); + // Unchanged + assertEquals(3, di.getCount()); + assertEquals(2, di2.getCount()); + + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + assertEquals(0, cba.getCalls()); + advised.addAdvice(cba); + t.setAge(16); + assertEquals(16, t.getAge()); + assertEquals(2, cba.getCalls()); + } + + public void testAdviceImplementsIntroductionInfo() throws Throwable { + TestBean tb = new TestBean(); + String name = "tony"; + tb.setName(name); + ProxyFactory pc = new ProxyFactory(tb); + NopInterceptor di = new NopInterceptor(); + pc.addAdvice(di); + final long ts = 37; + pc.addAdvice(new DelegatingIntroductionInterceptor(new TimeStamped() { + public long getTimeStamp() { + return ts; + } + })); + + ITestBean proxied = (ITestBean) createProxy(pc); + assertEquals(name, proxied.getName()); + TimeStamped intro = (TimeStamped) proxied; + assertEquals(ts, intro.getTimeStamp()); + } + + public void testCannotAddDynamicIntroductionAdviceExceptInIntroductionAdvice() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + try { + pc.addAdvice(new DummyIntroductionAdviceImpl()); + fail("Shouldn't be able to add introduction interceptor except via introduction advice"); + } + catch (AopConfigException ex) { + assertTrue(ex.getMessage().indexOf("ntroduction") > -1); + } + // Check it still works: proxy factory state shouldn't have been corrupted + ITestBean proxied = (ITestBean) createProxy(pc); + assertEquals(target.getAge(), proxied.getAge()); + } + + public void testRejectsBogusDynamicIntroductionAdviceWithNoAdapter() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + pc.addAdvisor(new DefaultIntroductionAdvisor(new DummyIntroductionAdviceImpl(), Comparable.class)); + try { + // TODO May fail on either call: may want to tighten up definition + ITestBean proxied = (ITestBean) createProxy(pc); + proxied.getName(); + fail("Bogus introduction"); + } + catch (Exception ex) { + // TODO used to catch UnknownAdviceTypeException, but + // with CGLIB some errors are in proxy creation and are wrapped + // in aspect exception. Error message is still fine. + //assertTrue(ex.getMessage().indexOf("ntroduction") > -1); + } + } + + /** + * Check that the introduction advice isn't allowed to introduce interfaces + * that are unsupported by the IntroductionInterceptor. + */ + public void testCannotAddIntroductionAdviceWithUnimplementedInterface() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + try { + pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), ITestBean.class)); + fail("Shouldn't be able to add introduction advice introducing an unimplemented interface"); + } + catch (IllegalArgumentException ex) { + //assertTrue(ex.getMessage().indexOf("ntroduction") > -1); + } + // Check it still works: proxy factory state shouldn't have been corrupted + ITestBean proxied = (ITestBean) createProxy(pc); + assertEquals(target.getAge(), proxied.getAge()); + } + + /** + * Note that an introduction can't throw an unexpected checked exception, + * as it's constained by the interface. + */ + public void testIntroductionThrowsUncheckedException() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + + class MyDi extends DelegatingIntroductionInterceptor implements TimeStamped { + /** + * @see org.springframework.aop.framework.TimeStamped#getTimeStamp() + */ + public long getTimeStamp() { + throw new UnsupportedOperationException(); + } + } + pc.addAdvisor(new DefaultIntroductionAdvisor(new MyDi())); + + TimeStamped ts = (TimeStamped) createProxy(pc); + try { + ts.getTimeStamp(); + fail("Should throw UnsupportedOperationException"); + } + catch (UnsupportedOperationException ex) { + } + } + + /** + * Should only be able to introduce interfaces, not classes. + */ + public void testCannotAddIntroductionAdviceToIntroduceClass() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + try { + pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), TestBean.class)); + fail("Shouldn't be able to add introduction advice that introduces a class, rather than an interface"); + } + catch (IllegalArgumentException ex) { + assertTrue(ex.getMessage().indexOf("interface") > -1); + } + // Check it still works: proxy factory state shouldn't have been corrupted + ITestBean proxied = (ITestBean) createProxy(pc); + assertEquals(target.getAge(), proxied.getAge()); + } + + public void testCannotAddInterceptorWhenFrozen() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + assertFalse(pc.isFrozen()); + pc.addAdvice(new NopInterceptor()); + ITestBean proxied = (ITestBean) createProxy(pc); + pc.setFrozen(true); + try { + pc.addAdvice(0, new NopInterceptor()); + fail("Shouldn't be able to add interceptor when frozen"); + } + catch (AopConfigException ex) { + assertTrue(ex.getMessage().indexOf("frozen") > -1); + } + // Check it still works: proxy factory state shouldn't have been corrupted + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(1, ((Advised) proxied).getAdvisors().length); + } + + /** + * Check that casting to Advised can't get around advice freeze. + */ + public void testCannotAddAdvisorWhenFrozenUsingCast() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + assertFalse(pc.isFrozen()); + pc.addAdvice(new NopInterceptor()); + ITestBean proxied = (ITestBean) createProxy(pc); + pc.setFrozen(true); + Advised advised = (Advised) proxied; + + assertTrue(pc.isFrozen()); + try { + advised.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + fail("Shouldn't be able to add Advisor when frozen"); + } + catch (AopConfigException ex) { + assertTrue(ex.getMessage().indexOf("frozen") > -1); + } + // Check it still works: proxy factory state shouldn't have been corrupted + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(1, advised.getAdvisors().length); + } + + public void testCannotRemoveAdvisorWhenFrozen() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + ProxyFactory pc = new ProxyFactory(target); + assertFalse(pc.isFrozen()); + pc.addAdvice(new NopInterceptor()); + ITestBean proxied = (ITestBean) createProxy(pc); + pc.setFrozen(true); + Advised advised = (Advised) proxied; + + assertTrue(pc.isFrozen()); + try { + advised.removeAdvisor(0); + fail("Shouldn't be able to remove Advisor when frozen"); + } + catch (AopConfigException ex) { + assertTrue(ex.getMessage().indexOf("frozen") > -1); + } + // Didn't get removed + assertEquals(1, advised.getAdvisors().length); + pc.setFrozen(false); + // Can now remove it + advised.removeAdvisor(0); + // Check it still works: proxy factory state shouldn't have been corrupted + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(0, advised.getAdvisors().length); + } + + public void testUseAsHashKey() { + TestBean target1 = new TestBean(); + ProxyFactory pf1 = new ProxyFactory(target1); + pf1.addAdvice(new NopInterceptor()); + ITestBean proxy1 = (ITestBean) createProxy(pf1); + + TestBean target2 = new TestBean(); + ProxyFactory pf2 = new ProxyFactory(target2); + pf2.addAdvisor(new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor())); + ITestBean proxy2 = (ITestBean) createProxy(pf2); + + HashMap h = new HashMap(); + Object value1 = "foo"; + Object value2 = "bar"; + assertNull(h.get(proxy1)); + h.put(proxy1, value1); + h.put(proxy2, value2); + assertEquals(h.get(proxy1), value1); + assertEquals(h.get(proxy2), value2); + } + + /** + * Check that the string is informative. + */ + public void testProxyConfigString() { + TestBean target = new TestBean(); + ProxyFactory pc = new ProxyFactory(target); + pc.setInterfaces(new Class[] {ITestBean.class}); + pc.addAdvice(new NopInterceptor()); + MethodBeforeAdvice mba = new CountingBeforeAdvice(); + Advisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut(), mba); + pc.addAdvisor(advisor); + ITestBean proxied = (ITestBean) createProxy(pc); + + String proxyConfigString = ((Advised) proxied).toProxyConfigString(); + assertTrue(proxyConfigString.indexOf(advisor.toString()) != -1); + assertTrue(proxyConfigString.indexOf("1 interface") != -1); + } + + public void testCanPreventCastToAdvisedUsingOpaque() { + TestBean target = new TestBean(); + ProxyFactory pc = new ProxyFactory(target); + pc.setInterfaces(new Class[] {ITestBean.class}); + pc.addAdvice(new NopInterceptor()); + CountingBeforeAdvice mba = new CountingBeforeAdvice(); + Advisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut().addMethodName("setAge"), mba); + pc.addAdvisor(advisor); + assertFalse("Opaque defaults to false", pc.isOpaque()); + pc.setOpaque(true); + assertTrue("Opaque now true for this config", pc.isOpaque()); + ITestBean proxied = (ITestBean) createProxy(pc); + proxied.setAge(10); + assertEquals(10, proxied.getAge()); + assertEquals(1, mba.getCalls()); + + assertFalse("Cannot be cast to Advised", proxied instanceof Advised); + } + + public void testAdviceSupportListeners() throws Throwable { + TestBean target = new TestBean(); + target.setAge(21); + + ProxyFactory pc = new ProxyFactory(target); + CountingAdvisorListener l = new CountingAdvisorListener(pc); + pc.addListener(l); + RefreshCountingAdvisorChainFactory acf = new RefreshCountingAdvisorChainFactory(); + // Should be automatically added as a listener + pc.addListener(acf); + assertFalse(pc.isActive()); + assertEquals(0, l.activates); + assertEquals(0, acf.refreshes); + ITestBean proxied = (ITestBean) createProxy(pc); + assertEquals(1, acf.refreshes); + assertEquals(1, l.activates); + assertTrue(pc.isActive()); + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(0, l.adviceChanges); + NopInterceptor di = new NopInterceptor(); + pc.addAdvice(0, di); + assertEquals(1, l.adviceChanges); + assertEquals(2, acf.refreshes); + assertEquals(target.getAge(), proxied.getAge()); + pc.removeAdvice(di); + assertEquals(2, l.adviceChanges); + assertEquals(3, acf.refreshes); + assertEquals(target.getAge(), proxied.getAge()); + pc.getProxy(); + assertEquals(1, l.activates); + + pc.removeListener(l); + assertEquals(2, l.adviceChanges); + pc.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); + // No longer counting + assertEquals(2, l.adviceChanges); + } + + public void testExistingProxyChangesTarget() throws Throwable { + TestBean tb1 = new TestBean(); + tb1.setAge(33); + + TestBean tb2 = new TestBean(); + tb2.setAge(26); + tb2.setName("Juergen"); + TestBean tb3 = new TestBean(); + tb3.setAge(37); + ProxyFactory pc = new ProxyFactory(tb1); + NopInterceptor nop = new NopInterceptor(); + pc.addAdvice(nop); + ITestBean proxy = (ITestBean) createProxy(pc); + assertEquals(nop.getCount(), 0); + assertEquals(tb1.getAge(), proxy.getAge()); + assertEquals(nop.getCount(), 1); + // Change to a new static target + pc.setTarget(tb2); + assertEquals(tb2.getAge(), proxy.getAge()); + assertEquals(nop.getCount(), 2); + + // Change to a new dynamic target + HotSwappableTargetSource hts = new HotSwappableTargetSource(tb3); + pc.setTargetSource(hts); + assertEquals(tb3.getAge(), proxy.getAge()); + assertEquals(nop.getCount(), 3); + hts.swap(tb1); + assertEquals(tb1.getAge(), proxy.getAge()); + tb1.setName("Colin"); + assertEquals(tb1.getName(), proxy.getName()); + assertEquals(nop.getCount(), 5); + + // Change back, relying on casting to Advised + Advised advised = (Advised) proxy; + assertSame(hts, advised.getTargetSource()); + SingletonTargetSource sts = new SingletonTargetSource(tb2); + advised.setTargetSource(sts); + assertEquals(tb2.getName(), proxy.getName()); + assertSame(sts, advised.getTargetSource()); + assertEquals(tb2.getAge(), proxy.getAge()); + } + + public void testDynamicMethodPointcutThatAlwaysAppliesStatically() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(new Class[] {ITestBean.class}); + TestDynamicPointcutAdvice dp = new TestDynamicPointcutAdvice(new NopInterceptor(), "getAge"); + pc.addAdvisor(dp); + pc.setTarget(tb); + ITestBean it = (ITestBean) createProxy(pc); + assertEquals(dp.count, 0); + int age = it.getAge(); + assertEquals(dp.count, 1); + it.setAge(11); + assertEquals(it.getAge(), 11); + assertEquals(dp.count, 2); + } + + public void testDynamicMethodPointcutThatAppliesStaticallyOnlyToSetters() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(new Class[] {ITestBean.class}); + // Could apply dynamically to getAge/setAge but not to getName + TestDynamicPointcutForSettersOnly dp = new TestDynamicPointcutForSettersOnly(new NopInterceptor(), "Age"); + pc.addAdvisor(dp); + this.mockTargetSource.setTarget(tb); + pc.setTargetSource(mockTargetSource); + ITestBean it = (ITestBean) createProxy(pc); + assertEquals(dp.count, 0); + int age = it.getAge(); + // Statically vetoed + assertEquals(0, dp.count); + it.setAge(11); + assertEquals(it.getAge(), 11); + assertEquals(dp.count, 1); + // Applies statically but not dynamically + it.setName("joe"); + assertEquals(dp.count, 1); + } + + public void testStaticMethodPointcut() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(new Class[] {ITestBean.class}); + NopInterceptor di = new NopInterceptor(); + TestStaticPointcutAdvice sp = new TestStaticPointcutAdvice(di, "getAge"); + pc.addAdvisor(sp); + pc.setTarget(tb); + ITestBean it = (ITestBean) createProxy(pc); + assertEquals(di.getCount(), 0); + int age = it.getAge(); + assertEquals(di.getCount(), 1); + it.setAge(11); + assertEquals(it.getAge(), 11); + assertEquals(di.getCount(), 2); + } + + /** + * There are times when we want to call proceed() twice. + * We can do this if we clone the invocation. + */ + public void testCloneInvocationToProceedThreeTimes() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(tb); + pc.addInterface(ITestBean.class); + + MethodInterceptor twoBirthdayInterceptor = new MethodInterceptor() { + public Object invoke(MethodInvocation mi) throws Throwable { + // Clone the invocation to proceed three times + // "The Moor's Last Sigh": this technology can cause premature aging + MethodInvocation clone1 = ((ReflectiveMethodInvocation) mi).invocableClone(); + MethodInvocation clone2 = ((ReflectiveMethodInvocation) mi).invocableClone(); + clone1.proceed(); + clone2.proceed(); + return mi.proceed(); + } + }; + StaticMethodMatcherPointcutAdvisor advisor = new StaticMethodMatcherPointcutAdvisor(twoBirthdayInterceptor) { + public boolean matches(Method m, Class targetClass) { + return "haveBirthday".equals(m.getName()); + } + }; + pc.addAdvisor(advisor); + ITestBean it = (ITestBean) createProxy(pc); + + final int age = 20; + it.setAge(age); + assertEquals(age, it.getAge()); + // Should return the age before the third, AOP-induced birthday + assertEquals(age + 2, it.haveBirthday()); + // Return the final age produced by 3 birthdays + assertEquals(age + 3, it.getAge()); + } + + /** + * We want to change the arguments on a clone: it shouldn't affect the original. + */ + public void testCanChangeArgumentsIndependentlyOnClonedInvocation() throws Throwable { + TestBean tb = new TestBean(); + ProxyFactory pc = new ProxyFactory(tb); + pc.addInterface(ITestBean.class); + + /** + * Changes the name, then changes it back. + */ + MethodInterceptor nameReverter = new MethodInterceptor() { + public Object invoke(MethodInvocation mi) throws Throwable { + MethodInvocation clone = ((ReflectiveMethodInvocation) mi).invocableClone(); + String oldName = ((ITestBean) mi.getThis()).getName(); + clone.getArguments()[0] = oldName; + // Original method invocation should be unaffected by changes to argument list of clone + mi.proceed(); + return clone.proceed(); + } + }; + + class NameSaver implements MethodInterceptor { + private List names = new LinkedList(); + + public Object invoke(MethodInvocation mi) throws Throwable { + names.add(mi.getArguments()[0]); + return mi.proceed(); + } + } + + NameSaver saver = new NameSaver(); + + pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, nameReverter)); + pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, saver)); + ITestBean it = (ITestBean) createProxy(pc); + + String name1 = "tony"; + String name2 = "gordon"; + + tb.setName(name1); + assertEquals(name1, tb.getName()); + + it.setName(name2); + // NameReverter saved it back + assertEquals(name1, it.getName()); + assertEquals(2, saver.names.size()); + assertEquals(name2, saver.names.get(0)); + assertEquals(name1, saver.names.get(1)); + } + + public void testOverloadedMethodsWithDifferentAdvice() throws Throwable { + Overloads target = new Overloads(); + ProxyFactory pc = new ProxyFactory(target); + NopInterceptor overLoadVoids = new NopInterceptor(); + pc.addAdvisor(new StaticMethodMatcherPointcutAdvisor(overLoadVoids) { + public boolean matches(Method m, Class targetClass) { + return m.getName().equals("overload") && m.getParameterTypes().length == 0; + } + }); + NopInterceptor overLoadInts = new NopInterceptor(); + pc.addAdvisor(new StaticMethodMatcherPointcutAdvisor(overLoadInts) { + public boolean matches(Method m, Class targetClass) { + return m.getName().equals("overload") && m.getParameterTypes().length == 1 && + m.getParameterTypes()[0].equals(int.class); + } + }); + + IOverloads proxy = (IOverloads) createProxy(pc); + assertEquals(0, overLoadInts.getCount()); + assertEquals(0, overLoadVoids.getCount()); + proxy.overload(); + assertEquals(0, overLoadInts.getCount()); + assertEquals(1, overLoadVoids.getCount()); + assertEquals(25, proxy.overload(25)); + assertEquals(1, overLoadInts.getCount()); + assertEquals(1, overLoadVoids.getCount()); + proxy.noAdvice(); + assertEquals(1, overLoadInts.getCount()); + assertEquals(1, overLoadVoids.getCount()); + } + + public void testProxyIsBoundBeforeTargetSourceInvoked() { + final TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new DebugInterceptor()); + pf.setExposeProxy(true); + final ITestBean proxy = (ITestBean) createProxy(pf); + Advised config = (Advised) proxy; + // This class just checks proxy is bound before getTarget() call + config.setTargetSource(new TargetSource() { + public Class getTargetClass() { + return TestBean.class; + } + + public boolean isStatic() { + return false; + } + + public Object getTarget() throws Exception { + assertEquals(proxy, AopContext.currentProxy()); + return target; + } + + public void releaseTarget(Object target) throws Exception { + } + }); + + // Just test anything: it will fail if context wasn't found + assertEquals(0, proxy.getAge()); + } + + public void testEquals() { + IOther a = new AllInstancesAreEqual(); + IOther b = new AllInstancesAreEqual(); + NopInterceptor i1 = new NopInterceptor(); + NopInterceptor i2 = new NopInterceptor(); + ProxyFactory pfa = new ProxyFactory(a); + pfa.addAdvice(i1); + ProxyFactory pfb = new ProxyFactory(b); + pfb.addAdvice(i2); + IOther proxyA = (IOther) createProxy(pfa); + IOther proxyB = (IOther) createProxy(pfb); + + assertEquals(pfa.getAdvisors().length, pfb.getAdvisors().length); + assertTrue(a.equals(b)); + assertTrue(i1.equals(i2)); + assertTrue(proxyA.equals(proxyB)); + assertEquals(proxyA.hashCode(), proxyB.hashCode()); + assertFalse(proxyA.equals(a)); + + // Equality checks were handled by the proxy + assertEquals(0, i1.getCount()); + + // When we invoke A, it's NopInterceptor will have count == 1 + // and won't think it's equal to B's NopInterceptor + proxyA.absquatulate(); + assertEquals(1, i1.getCount()); + assertFalse(proxyA.equals(proxyB)); + } + + public void testBeforeAdvisorIsInvoked() { + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + Advisor matchesNoArgs = new StaticMethodMatcherPointcutAdvisor(cba) { + public boolean matches(Method m, Class targetClass) { + return m.getParameterTypes().length == 0; + } + }; + TestBean target = new TestBean(); + target.setAge(80); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new NopInterceptor()); + pf.addAdvisor(matchesNoArgs); + assertEquals("Advisor was added", matchesNoArgs, pf.getAdvisors()[1]); + ITestBean proxied = (ITestBean) createProxy(pf); + assertEquals(0, cba.getCalls()); + assertEquals(0, cba.getCalls("getAge")); + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(1, cba.getCalls()); + assertEquals(1, cba.getCalls("getAge")); + assertEquals(0, cba.getCalls("setAge")); + // Won't be advised + proxied.setAge(26); + assertEquals(1, cba.getCalls()); + assertEquals(26, proxied.getAge()); + } + + public void testUserAttributes() throws Throwable { + class MapAwareMethodInterceptor implements MethodInterceptor { + private final Map expectedValues; + private final Map valuesToAdd; + public MapAwareMethodInterceptor(Map expectedValues, Map valuesToAdd) { + this.expectedValues = expectedValues; + this.valuesToAdd = valuesToAdd; + } + public Object invoke(MethodInvocation invocation) throws Throwable { + ReflectiveMethodInvocation rmi = (ReflectiveMethodInvocation) invocation; + for (Iterator it = rmi.getUserAttributes().keySet().iterator(); it.hasNext(); ){ + Object key = it.next(); + assertEquals(expectedValues.get(key), rmi.getUserAttributes().get(key)); + } + rmi.getUserAttributes().putAll(valuesToAdd); + return invocation.proceed(); + } + }; + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class}); + MapAwareMethodInterceptor mami1 = new MapAwareMethodInterceptor(new HashMap(), new HashMap()); + Map firstValuesToAdd = new HashMap(); + firstValuesToAdd.put("test", ""); + MapAwareMethodInterceptor mami2 = new MapAwareMethodInterceptor(new HashMap(), firstValuesToAdd); + MapAwareMethodInterceptor mami3 = new MapAwareMethodInterceptor(firstValuesToAdd, new HashMap()); + MapAwareMethodInterceptor mami4 = new MapAwareMethodInterceptor(firstValuesToAdd, new HashMap()); + Map secondValuesToAdd = new HashMap(); + secondValuesToAdd.put("foo", "bar"); + secondValuesToAdd.put("cat", "dog"); + MapAwareMethodInterceptor mami5 = new MapAwareMethodInterceptor(firstValuesToAdd, secondValuesToAdd); + Map finalExpected = new HashMap(firstValuesToAdd); + finalExpected.putAll(secondValuesToAdd); + MapAwareMethodInterceptor mami6 = new MapAwareMethodInterceptor(finalExpected, secondValuesToAdd); + + pc.addAdvice(mami1); + pc.addAdvice(mami2); + pc.addAdvice(mami3); + pc.addAdvice(mami4); + pc.addAdvice(mami5); + pc.addAdvice(mami6); + + // We don't care about the object + pc.setTarget(new TestBean()); + AopProxy aop = createAopProxy(pc); + ITestBean tb = (ITestBean) aop.getProxy(); + + String newName = "foo"; + tb.setName(newName); + assertEquals(newName, tb.getName()); + } + + public void testMultiAdvice() throws Throwable { + CountingMultiAdvice cca = new CountingMultiAdvice(); + Advisor matchesNoArgs = new StaticMethodMatcherPointcutAdvisor(cca) { + public boolean matches(Method m, Class targetClass) { + return m.getParameterTypes().length == 0 || "exceptional".equals(m.getName()); + } + }; + TestBean target = new TestBean(); + target.setAge(80); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new NopInterceptor()); + pf.addAdvisor(matchesNoArgs); + assertEquals("Advisor was added", matchesNoArgs, pf.getAdvisors()[1]); + ITestBean proxied = (ITestBean) createProxy(pf); + + assertEquals(0, cca.getCalls()); + assertEquals(0, cca.getCalls("getAge")); + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(2, cca.getCalls()); + assertEquals(2, cca.getCalls("getAge")); + assertEquals(0, cca.getCalls("setAge")); + // Won't be advised + proxied.setAge(26); + assertEquals(2, cca.getCalls()); + assertEquals(26, proxied.getAge()); + assertEquals(4, cca.getCalls()); + try { + proxied.exceptional(new CannotGetJdbcConnectionException("foo", (SQLException)null)); + fail("Should have thrown CannotGetJdbcConnectionException"); + } + catch (CannotGetJdbcConnectionException ex) { + // expected + } + assertEquals(6, cca.getCalls()); + } + + public void testBeforeAdviceThrowsException() { + final RuntimeException rex = new RuntimeException(); + CountingBeforeAdvice ba = new CountingBeforeAdvice() { + public void before(Method m, Object[] args, Object target) throws Throwable { + super.before(m, args, target); + if (m.getName().startsWith("set")) + throw rex; + } + }; + + TestBean target = new TestBean(); + target.setAge(80); + NopInterceptor nop1 = new NopInterceptor(); + NopInterceptor nop2 = new NopInterceptor(); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(nop1); + pf.addAdvice(ba); + pf.addAdvice(nop2); + ITestBean proxied = (ITestBean) createProxy(pf); + // Won't throw an exception + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(1, ba.getCalls()); + assertEquals(1, ba.getCalls("getAge")); + assertEquals(1, nop1.getCount()); + assertEquals(1, nop2.getCount()); + // Will fail, after invoking Nop1 + try { + proxied.setAge(26); + fail("before advice should have ended chain"); + } + catch (RuntimeException ex) { + assertEquals(rex, ex); + } + assertEquals(2, ba.getCalls()); + assertEquals(2, nop1.getCount()); + // Nop2 didn't get invoked when the exception was thrown + assertEquals(1, nop2.getCount()); + // Shouldn't have changed value in joinpoint + assertEquals(target.getAge(), proxied.getAge()); + } + + + public void testAfterReturningAdvisorIsInvoked() { + class SummingAfterAdvice implements AfterReturningAdvice { + public int sum; + public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable { + sum += ((Integer) returnValue).intValue(); + } + } + SummingAfterAdvice aa = new SummingAfterAdvice(); + Advisor matchesInt = new StaticMethodMatcherPointcutAdvisor(aa) { + public boolean matches(Method m, Class targetClass) { + return m.getReturnType() == int.class; + } + }; + TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new NopInterceptor()); + pf.addAdvisor(matchesInt); + assertEquals("Advisor was added", matchesInt, pf.getAdvisors()[1]); + ITestBean proxied = (ITestBean) createProxy(pf); + assertEquals(0, aa.sum); + int i1 = 12; + int i2 = 13; + + // Won't be advised + proxied.setAge(i1); + assertEquals(i1, proxied.getAge()); + assertEquals(i1, aa.sum); + proxied.setAge(i2); + assertEquals(i2, proxied.getAge()); + assertEquals(i1 + i2, aa.sum); + assertEquals(i2, proxied.getAge()); + } + + public void testAfterReturningAdvisorIsNotInvokedOnException() { + CountingAfterReturningAdvice car = new CountingAfterReturningAdvice(); + TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new NopInterceptor()); + pf.addAdvice(car); + assertEquals("Advice was wrapped in Advisor and added", car, pf.getAdvisors()[1].getAdvice()); + ITestBean proxied = (ITestBean) createProxy(pf); + assertEquals(0, car.getCalls()); + int age = 10; + proxied.setAge(age); + assertEquals(age, proxied.getAge()); + assertEquals(2, car.getCalls()); + Exception exc = new Exception(); + // On exception it won't be invoked + try { + proxied.exceptional(exc); + fail(); + } + catch (Throwable t) { + assertSame(exc, t); + } + assertEquals(2, car.getCalls()); + } + + + public void testThrowsAdvisorIsInvoked() throws Throwable { + // Reacts to ServletException and RemoteException + ThrowsAdviceInterceptorTests.MyThrowsHandler th = new ThrowsAdviceInterceptorTests.MyThrowsHandler(); + Advisor matchesEchoInvocations = new StaticMethodMatcherPointcutAdvisor(th) { + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith("echo"); + } + }; + + ThrowsAdviceInterceptorTests.Echo target = new ThrowsAdviceInterceptorTests.Echo(); + target.setA(16); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new NopInterceptor()); + pf.addAdvisor(matchesEchoInvocations); + assertEquals("Advisor was added", matchesEchoInvocations, pf.getAdvisors()[1]); + ThrowsAdviceInterceptorTests.IEcho proxied = (ThrowsAdviceInterceptorTests.IEcho) createProxy(pf); + assertEquals(0, th.getCalls()); + assertEquals(target.getA(), proxied.getA()); + assertEquals(0, th.getCalls()); + Exception ex = new Exception(); + // Will be advised but doesn't match + try { + proxied.echoException(1, ex); + fail(); + } + catch (Exception caught) { + assertEquals(ex, caught); + } + + ex = new ServletException(); + try { + proxied.echoException(1, ex); + fail(); + } + catch (ServletException caught) { + assertEquals(ex, caught); + } + assertEquals(1, th.getCalls("servletException")); + } + + public void testAddThrowsAdviceWithoutAdvisor() throws Throwable { + // Reacts to ServletException and RemoteException + ThrowsAdviceInterceptorTests.MyThrowsHandler th = new ThrowsAdviceInterceptorTests.MyThrowsHandler(); + + ThrowsAdviceInterceptorTests.Echo target = new ThrowsAdviceInterceptorTests.Echo(); + target.setA(16); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new NopInterceptor()); + pf.addAdvice(th); + ThrowsAdviceInterceptorTests.IEcho proxied = (ThrowsAdviceInterceptorTests.IEcho) createProxy(pf); + assertEquals(0, th.getCalls()); + assertEquals(target.getA(), proxied.getA()); + assertEquals(0, th.getCalls()); + Exception ex = new Exception(); + // Will be advised but doesn't match + try { + proxied.echoException(1, ex); + fail(); + } + catch (Exception caught) { + assertEquals(ex, caught); + } + + // Subclass of RemoteException + ex = new TransactionRequiredException(); + try { + proxied.echoException(1, ex); + fail(); + } + catch (TransactionRequiredException caught) { + assertEquals(ex, caught); + } + assertEquals(1, th.getCalls("remoteException")); + } + + + private static class CheckMethodInvocationIsSameInAndOutInterceptor implements MethodInterceptor { + + public Object invoke(MethodInvocation mi) throws Throwable { + Method m = mi.getMethod(); + Object retval = mi.proceed(); + assertEquals("Method invocation has same method on way back", m, mi.getMethod()); + return retval; + } + } + + + /** + * ExposeInvocation must be set to true. + */ + private static class CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor implements MethodInterceptor { + + public Object invoke(MethodInvocation mi) throws Throwable { + String task = "get invocation on way IN"; + try { + MethodInvocation current = ExposeInvocationInterceptor.currentInvocation(); + assertEquals(mi.getMethod(), current.getMethod()); + Object retval = mi.proceed(); + task = "get invocation on way OUT"; + assertEquals(current, ExposeInvocationInterceptor.currentInvocation()); + return retval; + } + catch (IllegalStateException ex) { + System.err.println(task + " for " + mi.getMethod()); + ex.printStackTrace(); + throw ex; + } + } + } + + + /** + * Same thing for a proxy. + * Only works when exposeProxy is set to true. + * Checks that the proxy is the same on the way in and out. + */ + private static class ProxyMatcherInterceptor implements MethodInterceptor { + + public Object invoke(MethodInvocation mi) throws Throwable { + Object proxy = AopContext.currentProxy(); + Object ret = mi.proceed(); + // TODO why does this cause stack overflow? + //assertEquals(proxy, AopContext.currentProxy()); + assertTrue(proxy == AopContext.currentProxy()); + return ret; + } + } + + + /** + * Fires on setter methods that take a string. Replaces null arg with "". + */ + protected static class StringSetterNullReplacementAdvice extends DefaultPointcutAdvisor { + + private static MethodInterceptor cleaner = new MethodInterceptor() { + public Object invoke(MethodInvocation mi) throws Throwable { + // We know it can only be invoked if there's a single parameter of type string + mi.getArguments()[0] = ""; + return mi.proceed(); + } + }; + + public StringSetterNullReplacementAdvice() { + super(cleaner); + setPointcut(new DynamicMethodMatcherPointcut() { + public boolean matches(Method m, Class targetClass, Object[] args) { + return args[0] == null; + } + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith("set") && + m.getParameterTypes().length == 1 && + m.getParameterTypes()[0].equals(String.class); + } + }); + } + } + + + protected static class TestDynamicPointcutAdvice extends DefaultPointcutAdvisor { + + public int count; + + public TestDynamicPointcutAdvice(MethodInterceptor mi, final String pattern) { + super(mi); + setPointcut(new DynamicMethodMatcherPointcut() { + public boolean matches(Method m, Class targetClass, Object[] args) { + boolean run = m.getName().indexOf(pattern) != -1; + if (run) ++count; + return run; + } + }); + } + } + + + protected static class TestDynamicPointcutForSettersOnly extends DefaultPointcutAdvisor { + + public int count; + + public TestDynamicPointcutForSettersOnly(MethodInterceptor mi, final String pattern) { + super(mi); + setPointcut(new DynamicMethodMatcherPointcut() { + public boolean matches(Method m, Class targetClass, Object[] args) { + boolean run = m.getName().indexOf(pattern) != -1; + if (run) ++count; + return run; + } + public boolean matches(Method m, Class clazz) { + return m.getName().startsWith("set"); + } + }); + } + } + + + protected static class TestStaticPointcutAdvice extends StaticMethodMatcherPointcutAdvisor { + + private String pattern; + private int count; + + public TestStaticPointcutAdvice(MethodInterceptor mi, String pattern) { + super(mi); + this.pattern = pattern; + } + public boolean matches(Method m, Class targetClass) { + boolean run = m.getName().indexOf(pattern) != -1; + if (run) ++count; + return run; + } + } + + + /** + * Note that trapping the Invocation as in previous version of this test + * isn't safe, as invocations may be reused + * and hence cleared at the end of each invocation. + * So we trap only the targe. + */ + protected static class TrapTargetInterceptor implements MethodInterceptor { + + public Object target; + + public Object invoke(MethodInvocation invocation) throws Throwable { + this.target = invocation.getThis(); + return invocation.proceed(); + } + } + + + private static class DummyIntroductionAdviceImpl implements DynamicIntroductionAdvice { + + public boolean implementsInterface(Class intf) { + return true; + } + } + + + public static class OwnSpouse extends TestBean { + + public ITestBean getSpouse() { + return this; + } + } + + + public static class AllInstancesAreEqual implements IOther { + + public boolean equals(Object other) { + return (other instanceof AllInstancesAreEqual); + } + + public int hashCode() { + return getClass().hashCode(); + } + + public void absquatulate() { + } + } + + + public interface INeedsToSeeProxy { + + int getCount(); + + void incrementViaThis(); + + void incrementViaProxy(); + + void increment(); + } + + + public static class NeedsToSeeProxy implements INeedsToSeeProxy { + + private int count; + + public int getCount() { + return count; + } + + public void incrementViaThis() { + this.increment(); + } + + public void incrementViaProxy() { + INeedsToSeeProxy thisViaProxy = (INeedsToSeeProxy) AopContext.currentProxy(); + thisViaProxy.increment(); + Advised advised = (Advised) thisViaProxy; + checkAdvised(advised); + } + + protected void checkAdvised(Advised advised) { + } + + public void increment() { + ++count; + } + } + + + public static class TargetChecker extends NeedsToSeeProxy { + + protected void checkAdvised(Advised advised) { + // TODO replace this check: no longer possible + //assertEquals(advised.getTarget(), this); + } + } + + + public static class CountingAdvisorListener implements AdvisedSupportListener { + + public int adviceChanges; + public int activates; + private AdvisedSupport expectedSource; + + public CountingAdvisorListener(AdvisedSupport expectedSource) { + this.expectedSource = expectedSource; + } + + public void activated(AdvisedSupport advised) { + assertEquals(expectedSource, advised); + ++activates; + } + + public void adviceChanged(AdvisedSupport advised) { + assertEquals(expectedSource, advised); + ++adviceChanges; + } + } + + + public static class RefreshCountingAdvisorChainFactory implements AdvisedSupportListener { + + public int refreshes; + + public void activated(AdvisedSupport advised) { + ++refreshes; + } + + public void adviceChanged(AdvisedSupport advised) { + ++refreshes; + } + } + + + public static interface IOverloads { + + void overload(); + + int overload(int i); + + String overload(String foo); + + void noAdvice(); + } + + + public static class Overloads implements IOverloads { + + public void overload() { + } + + public int overload(int i) { + return i; + } + + public String overload(String s) { + return s; + } + + public void noAdvice() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java new file mode 100644 index 00000000000..22a9a655e36 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java @@ -0,0 +1,134 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.aop.SpringProxy; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; + +/** + * @author Rod Johnson + */ +public class AopProxyUtilsTests extends TestCase { + + public void testCompleteProxiedInterfacesWorksWithNull() { + AdvisedSupport as = new AdvisedSupport(); + Class[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as); + assertEquals(2, completedInterfaces.length); + List ifaces = Arrays.asList(completedInterfaces); + assertTrue(ifaces.contains(Advised.class)); + assertTrue(ifaces.contains(SpringProxy.class)); + } + + public void testCompleteProxiedInterfacesWorksWithNullOpaque() { + AdvisedSupport as = new AdvisedSupport(); + as.setOpaque(true); + Class[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as); + assertEquals(1, completedInterfaces.length); + } + + public void testCompleteProxiedInterfacesAdvisedNotIncluded() { + AdvisedSupport as = new AdvisedSupport(); + as.addInterface(ITestBean.class); + as.addInterface(Comparable.class); + Class[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as); + assertEquals(4, completedInterfaces.length); + + // Can't assume ordering for others, so use a list + List l = Arrays.asList(completedInterfaces); + assertTrue(l.contains(Advised.class)); + assertTrue(l.contains(ITestBean.class)); + assertTrue(l.contains(Comparable.class)); + } + + public void testCompleteProxiedInterfacesAdvisedIncluded() { + AdvisedSupport as = new AdvisedSupport(); + as.addInterface(ITestBean.class); + as.addInterface(Comparable.class); + as.addInterface(Advised.class); + Class[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as); + assertEquals(4, completedInterfaces.length); + + // Can't assume ordering for others, so use a list + List l = Arrays.asList(completedInterfaces); + assertTrue(l.contains(Advised.class)); + assertTrue(l.contains(ITestBean.class)); + assertTrue(l.contains(Comparable.class)); + } + + public void testCompleteProxiedInterfacesAdvisedNotIncludedOpaque() { + AdvisedSupport as = new AdvisedSupport(); + as.setOpaque(true); + as.addInterface(ITestBean.class); + as.addInterface(Comparable.class); + Class[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as); + assertEquals(3, completedInterfaces.length); + + // Can't assume ordering for others, so use a list + List l = Arrays.asList(completedInterfaces); + assertFalse(l.contains(Advised.class)); + assertTrue(l.contains(ITestBean.class)); + assertTrue(l.contains(Comparable.class)); + } + + public void testProxiedUserInterfacesWithSingleInterface() { + ProxyFactory pf = new ProxyFactory(); + pf.setTarget(new TestBean()); + pf.addInterface(ITestBean.class); + Object proxy = pf.getProxy(); + Class[] userInterfaces = AopProxyUtils.proxiedUserInterfaces(proxy); + assertEquals(1, userInterfaces.length); + assertEquals(ITestBean.class, userInterfaces[0]); + } + + public void testProxiedUserInterfacesWithMultipleInterfaces() { + ProxyFactory pf = new ProxyFactory(); + pf.setTarget(new TestBean()); + pf.addInterface(ITestBean.class); + pf.addInterface(Comparable.class); + Object proxy = pf.getProxy(); + Class[] userInterfaces = AopProxyUtils.proxiedUserInterfaces(proxy); + assertEquals(2, userInterfaces.length); + assertEquals(ITestBean.class, userInterfaces[0]); + assertEquals(Comparable.class, userInterfaces[1]); + } + + public void testProxiedUserInterfacesWithNoInterface() { + Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[0], + new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return null; + } + }); + try { + Class[] userInterfaces = AopProxyUtils.proxiedUserInterfaces(proxy); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibProxyTests.java new file mode 100644 index 00000000000..13c9a8f8b0b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibProxyTests.java @@ -0,0 +1,411 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.io.Serializable; +import java.lang.reflect.Modifier; + +import net.sf.cglib.core.CodeGenerationException; +import org.aopalliance.intercept.MethodInterceptor; + +import org.springframework.aop.ClassFilter; +import org.springframework.aop.MethodMatcher; +import org.springframework.aop.Pointcut; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextException; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Additional and overridden tests for the CGLIB proxy. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + * @author Ramnivas Laddad + */ +public class CglibProxyTests extends AbstractAopProxyTests { + + protected Object createProxy(ProxyCreatorSupport as) { + as.setProxyTargetClass(true); + Object proxy = as.createAopProxy().getProxy(); + assertTrue(AopUtils.isCglibProxy(proxy)); + return proxy; + } + + protected AopProxy createAopProxy(AdvisedSupport as) { + as.setProxyTargetClass(true); + return new Cglib2AopProxy(as); + } + + protected boolean requiresTarget() { + return true; + } + + public void testNullConfig() { + try { + AopProxy aop = new Cglib2AopProxy(null); + fail("Shouldn't allow null interceptors"); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testNoTarget() { + AdvisedSupport pc = new AdvisedSupport(new Class[]{ITestBean.class}); + pc.addAdvice(new NopInterceptor()); + try { + AopProxy aop = createAopProxy(pc); + aop.getProxy(); + fail("Shouldn't allow no target with CGLIB proxy"); + } + catch (AopConfigException ex) { + // Ok + } + } + + public void testProtectedMethodInvocation() { + ProtectedMethodTestBean bean = new ProtectedMethodTestBean(); + mockTargetSource.setTarget(bean); + + AdvisedSupport as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvice(new NopInterceptor()); + AopProxy aop = new Cglib2AopProxy(as); + + Object proxy = aop.getProxy(); + assertTrue(AopUtils.isCglibProxy(proxy)); + } + + public void testProxyCanBeClassNotInterface() throws Exception { + TestBean raw = new TestBean(); + raw.setAge(32); + mockTargetSource.setTarget(raw); + AdvisedSupport pc = new AdvisedSupport(); + pc.setTargetSource(mockTargetSource); + AopProxy aop = new Cglib2AopProxy(pc); + + Object proxy = aop.getProxy(); + assertTrue(AopUtils.isCglibProxy(proxy)); + assertTrue(proxy instanceof ITestBean); + assertTrue(proxy instanceof TestBean); + + TestBean tb = (TestBean) proxy; + assertEquals(32, tb.getAge()); + } + + public void testCglibProxyingGivesMeaningfulExceptionIfAskedToProxyNonvisibleClass() { + class YouCantSeeThis { + void hidden() { + } + } + YouCantSeeThis mine = new YouCantSeeThis(); + try { + ProxyFactory pf = new ProxyFactory(mine); + pf.getProxy(); + fail("Shouldn't be able to proxy non-visible class with CGLIB"); + } + catch (AopConfigException ex) { + // Check that stack trace is preserved + assertTrue(ex.getCause() instanceof CodeGenerationException || + ex.getCause() instanceof IllegalArgumentException); + // Check that error message is helpful + assertTrue(ex.getMessage().indexOf("final") != -1); + assertTrue(ex.getMessage().indexOf("visible") != -1); + } + } + + public void testMethodInvocationDuringConstructor() { + CglibTestBean bean = new CglibTestBean(); + bean.setName("Rob Harrop"); + + AdvisedSupport as = new AdvisedSupport(new Class[]{}); + as.setTarget(bean); + as.addAdvice(new NopInterceptor()); + AopProxy aop = new Cglib2AopProxy(as); + + CglibTestBean proxy = (CglibTestBean) aop.getProxy(); + + assertEquals("The name property has been overwritten by the constructor", + "Rob Harrop", proxy.getName()); + } + + public void testUnadvisedProxyCreationWithCallDuringConstructor() throws Exception { + CglibTestBean target = new CglibTestBean(); + target.setName("Rob Harrop"); + + AdvisedSupport pc = new AdvisedSupport(new Class[]{}); + pc.setFrozen(true); + pc.setTarget(target); + + Cglib2AopProxy aop = new Cglib2AopProxy(pc); + + CglibTestBean proxy = (CglibTestBean) aop.getProxy(); + + assertNotNull("Proxy should not be null", proxy); + assertEquals("Constructor overrode the value of name", "Rob Harrop", proxy.getName()); + + } + + public void testMultipleProxies() { + TestBean target = new TestBean(); + target.setAge(20); + TestBean target2 = new TestBean(); + target2.setAge(21); + + ITestBean proxy1 = getAdvisedProxy(target); + ITestBean proxy2 = getAdvisedProxy(target2); + assertTrue(proxy1.getClass() == proxy2.getClass()); + assertEquals(target.getAge(), proxy1.getAge()); + assertEquals(target2.getAge(), proxy2.getAge()); + } + + private ITestBean getAdvisedProxy(TestBean target) { + ProxyFactory pf = new ProxyFactory(new Class[]{ITestBean.class}); + pf.setProxyTargetClass(true); + + MethodInterceptor advice = new NopInterceptor(); + Pointcut pointcut = new Pointcut() { + public ClassFilter getClassFilter() { + return ClassFilter.TRUE; + } + + public MethodMatcher getMethodMatcher() { + return MethodMatcher.TRUE; + } + + public boolean equals(Object obj) { + return true; + } + }; + pf.addAdvisor(new DefaultPointcutAdvisor(pointcut, advice)); + + pf.setTarget(target); + pf.setFrozen(true); + pf.setExposeProxy(false); + + return (ITestBean) pf.getProxy(); + } + + public void testMultipleProxiesForIntroductionAdvisor() { + TestBean target = new TestBean(); + target.setAge(20); + TestBean target2 = new TestBean(); + target2.setAge(21); + + ITestBean proxy1 = getIntroductionAdvisorProxy(target); + ITestBean proxy2 = getIntroductionAdvisorProxy(target2); + assertTrue("Incorrect duplicate creation of proxy classes", proxy1.getClass() == proxy2.getClass()); + } + + private ITestBean getIntroductionAdvisorProxy(TestBean target) { + ProxyFactory pf = new ProxyFactory(new Class[]{ITestBean.class}); + pf.setProxyTargetClass(true); + + pf.addAdvisor(new LockMixinAdvisor()); + pf.setTarget(target); + pf.setFrozen(true); + pf.setExposeProxy(false); + + return (ITestBean) pf.getProxy(); + } + + public void testWithNoArgConstructor() { + NoArgCtorTestBean target = new NoArgCtorTestBean("b", 1); + target.reset(); + + mockTargetSource.setTarget(target); + AdvisedSupport pc = new AdvisedSupport(new Class[]{}); + pc.setTargetSource(mockTargetSource); + Cglib2AopProxy aop = new Cglib2AopProxy(pc); + aop.setConstructorArguments(new Object[] {"Rob Harrop", new Integer(22)}, + new Class[] {String.class, int.class}); + + NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy(); + proxy = (NoArgCtorTestBean) aop.getProxy(); + + assertNotNull("Proxy should be null", proxy); + } + + public void testProxyAProxy() { + ITestBean target = new TestBean(); + + mockTargetSource.setTarget(target); + AdvisedSupport as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvice(new NopInterceptor()); + Cglib2AopProxy cglib = new Cglib2AopProxy(as); + + ITestBean proxy1 = (ITestBean) cglib.getProxy(); + + mockTargetSource.setTarget(proxy1); + as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvice(new NopInterceptor()); + cglib = new Cglib2AopProxy(as); + + ITestBean proxy2 = (ITestBean) cglib.getProxy(); + } + + public void testProxyAProxyWithAdditionalInterface() { + ITestBean target = new TestBean(); + mockTargetSource.setTarget(target); + + AdvisedSupport as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvice(new NopInterceptor()); + as.addInterface(Serializable.class); + Cglib2AopProxy cglib = new Cglib2AopProxy(as); + + ITestBean proxy1 = (ITestBean) cglib.getProxy(); + + mockTargetSource.setTarget(proxy1); + as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvice(new NopInterceptor()); + cglib = new Cglib2AopProxy(as); + + ITestBean proxy2 = (ITestBean) cglib.getProxy(); + assertTrue(proxy2 instanceof Serializable); + } + + public void testExceptionHandling() { + ExceptionThrower bean = new ExceptionThrower(); + mockTargetSource.setTarget(bean); + + AdvisedSupport as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvice(new NopInterceptor()); + AopProxy aop = new Cglib2AopProxy(as); + + ExceptionThrower proxy = (ExceptionThrower) aop.getProxy(); + + try { + proxy.doTest(); + } + catch (Exception ex) { + assertTrue("Invalid exception class", ex instanceof ApplicationContextException); + } + + assertTrue("Catch was not invoked", proxy.isCatchInvoked()); + assertTrue("Finally was not invoked", proxy.isFinallyInvoked()); + } + + public void testWithDependencyChecking() { + ApplicationContext ctx = + new ClassPathXmlApplicationContext("org/springframework/aop/framework/withDependencyChecking.xml"); + ctx.getBean("testBean"); + } + + public void testAddAdviceAtRuntime() { + TestBean bean = new TestBean(); + + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + + ProxyFactory pf = new ProxyFactory(); + pf.setTarget(bean); + pf.setFrozen(false); + pf.setOpaque(false); + pf.setProxyTargetClass(true); + + TestBean proxy = (TestBean) pf.getProxy(); + + assertTrue(AopUtils.isCglibProxy(proxy)); + + proxy.getAge(); + + assertEquals(0, cba.getCalls()); + + ((Advised) proxy).addAdvice(cba); + + proxy.getAge(); + + assertEquals(1, cba.getCalls()); + } + + public void testProxyProtectedMethod() throws Exception { + CountingBeforeAdvice advice = new CountingBeforeAdvice(); + ProxyFactory proxyFactory = new ProxyFactory(new MyBean()); + proxyFactory.addAdvice(advice); + proxyFactory.setProxyTargetClass(true); + + MyBean proxy = (MyBean) proxyFactory.getProxy(); + + assertEquals(4, proxy.add(1, 3)); + assertEquals(1, advice.getCalls("add")); + } + + + public static class MyBean { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + protected int add(int x, int y) { + return x + y; + } + } + + + public static class ExceptionThrower { + + private boolean catchInvoked; + + private boolean finallyInvoked; + + public boolean isCatchInvoked() { + return catchInvoked; + } + + public boolean isFinallyInvoked() { + return finallyInvoked; + } + + public void doTest() throws Exception { + try { + throw new ApplicationContextException("foo"); + } + catch (Exception ex) { + catchInvoked = true; + throw ex; + } + finally { + finallyInvoked = true; + } + } + } + + + public static class HasFinalMethod { + + public final void foo() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibTestBean.java new file mode 100644 index 00000000000..690e8b097f5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CglibTestBean.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +/** + * @author Rob Harrop + */ +public class CglibTestBean { + + private String name; + + public CglibTestBean() { + setName("Some Default"); + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingAfterReturningAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingAfterReturningAdvice.java new file mode 100644 index 00000000000..d59f74800bd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingAfterReturningAdvice.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.lang.reflect.Method; + +import org.springframework.aop.AfterReturningAdvice; + +/** + * Simple before advice example that we can use for counting checks. + * + * @author Rod Johnson + */ +public class CountingAfterReturningAdvice extends MethodCounter implements AfterReturningAdvice { + + public void afterReturning(Object o, Method m, Object[] args, Object target) throws Throwable { + count(m); + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingBeforeAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingBeforeAdvice.java new file mode 100644 index 00000000000..3f391b2c68c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingBeforeAdvice.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.lang.reflect.Method; + +import org.springframework.aop.MethodBeforeAdvice; + +/** + * Simple before advice example that we can use for counting checks. + * + * @author Rod Johnson + */ +public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice { + + public void before(Method m, Object[] args, Object target) throws Throwable { + count(m); + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingMultiAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingMultiAdvice.java new file mode 100644 index 00000000000..2b27d2e7907 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingMultiAdvice.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.lang.reflect.Method; + +import javax.servlet.ServletException; + +import org.springframework.aop.AfterReturningAdvice; +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.ThrowsAdvice; +import org.springframework.dao.DataAccessException; + +/** + * Advice object that implements multiple Advice interfaces. + * + * @author Juergen Hoeller + * @since 19.05.2005 + */ +public class CountingMultiAdvice extends MethodCounter + implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice { + + public void before(Method m, Object[] args, Object target) throws Throwable { + count(m); + } + + public void afterReturning(Object o, Method m, Object[] args, Object target) throws Throwable { + count(m); + } + + public void afterThrowing(ServletException sex) throws Throwable { + count(ServletException.class.getName()); + } + + public void afterThrowing(DataAccessException ex) throws Throwable { + count(DataAccessException.class.getName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingThrowsAdvice.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingThrowsAdvice.java new file mode 100644 index 00000000000..b17153124f0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/CountingThrowsAdvice.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import javax.servlet.ServletException; + +import org.springframework.aop.ThrowsAdvice; +import org.springframework.dao.DataAccessException; + +/** + * @author Rod Johnson + */ +public class CountingThrowsAdvice extends MethodCounter implements ThrowsAdvice { + + public void afterThrowing(ServletException sex) throws Throwable { + count(ServletException.class.getName()); + } + + public void afterThrowing(DataAccessException ex) throws Throwable { + count(DataAccessException.class.getName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/DefaultLockable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/DefaultLockable.java new file mode 100644 index 00000000000..a7b4d48b39d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/DefaultLockable.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.springframework.aop.framework; + +/** + * Simple implementation of Lockable interface for use in mixins. + * + * @author Rod Johnson + */ +public class DefaultLockable implements Lockable { + + private boolean locked; + + public void lock() { + this.locked = true; + } + + public void unlock() { + this.locked = false; + } + + public boolean locked() { + return this.locked; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ExposedInvocationTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ExposedInvocationTestBean.java new file mode 100644 index 00000000000..83f56173791 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ExposedInvocationTestBean.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.aop.interceptor.ExposeInvocationInterceptor; +import org.springframework.beans.TestBean; + + +/** + * Used to test ExposeInvocationInterceptor. + * @author Rod Johnson + */ +public abstract class ExposedInvocationTestBean extends TestBean { + + public String getName() { + MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation(); + assertions(invocation); + return super.getName(); + } + + public void absquatulate() { + MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation(); + assertions(invocation); + super.absquatulate(); + } + + protected abstract void assertions(MethodInvocation invocation); +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java new file mode 100644 index 00000000000..d3383ab8f7b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import junit.framework.TestCase; + +import org.springframework.aop.support.DelegatingIntroductionInterceptor; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.util.StopWatch; + +/** + * Benchmarks for introductions. + * + * @author Rod Johnson + * @since 2.0 + */ +public class IntroductionBenchmarkTests extends TestCase { + + private static final int EXPECTED_COMPARE = 13; + + /** Increase this if you want meaningful results! */ + private static final int INVOCATIONS = 100000; + + + public void testBenchmarks() { + timeManyInvocations(); + } + + public static class SimpleCounterIntroduction extends DelegatingIntroductionInterceptor implements Counter { + + public int getCount() { + return EXPECTED_COMPARE; + } + } + + public static interface Counter { + int getCount(); + } + + protected long timeManyInvocations() { + StopWatch sw = new StopWatch(); + + TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + pf.setProxyTargetClass(false); + pf.addAdvice(new SimpleCounterIntroduction()); + ITestBean proxy = (ITestBean) pf.getProxy(); + + Counter counter = (Counter) proxy; + + sw.start(INVOCATIONS + " invocations on proxy, not hitting introduction"); + for (int i = 0; i < INVOCATIONS; i++) { + proxy.getAge(); + } + sw.stop(); + + sw.start(INVOCATIONS + " invocations on proxy, hitting introduction"); + for (int i = 0; i < INVOCATIONS; i++) { + counter.getCount(); + } + sw.stop(); + + sw.start(INVOCATIONS + " invocations on target"); + for (int i = 0; i < INVOCATIONS; i++) { + target.getAge(); + } + sw.stop(); + + System.out.println(sw.prettyPrint()); + return sw.getLastTaskTimeMillis(); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/InvocationCheckExposedInvocationTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/InvocationCheckExposedInvocationTestBean.java new file mode 100644 index 00000000000..7f6b3115469 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/InvocationCheckExposedInvocationTestBean.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import junit.framework.TestCase; + +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.beans.ITestBean; + + +/** + * + */ +public class InvocationCheckExposedInvocationTestBean extends ExposedInvocationTestBean { + protected void assertions(MethodInvocation invocation) { + TestCase.assertTrue(invocation.getThis() == this); + TestCase.assertTrue("Invocation should be on ITestBean: " + invocation.getMethod(), + ITestBean.class.isAssignableFrom(invocation.getMethod().getDeclaringClass())); + } +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java new file mode 100644 index 00000000000..a82ffa85b6e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java @@ -0,0 +1,212 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; + +import org.springframework.aop.interceptor.ExposeInvocationInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.IOther; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 13.03.2003 + */ +public class JdkDynamicProxyTests extends AbstractAopProxyTests { + + protected Object createProxy(ProxyCreatorSupport as) { + assertFalse("Not forcible CGLIB", as.isProxyTargetClass()); + Object proxy = as.createAopProxy().getProxy(); + assertTrue("Should be a JDK proxy: " + proxy.getClass(), AopUtils.isJdkDynamicProxy(proxy)); + return proxy; + } + + protected AopProxy createAopProxy(AdvisedSupport as) { + return new JdkDynamicAopProxy(as); + } + + public void testNullConfig() { + try { + JdkDynamicAopProxy aop = new JdkDynamicAopProxy(null); + fail("Shouldn't allow null interceptors"); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testProxyIsJustInterface() throws Throwable { + TestBean raw = new TestBean(); + raw.setAge(32); + AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class}); + pc.setTarget(raw); + JdkDynamicAopProxy aop = new JdkDynamicAopProxy(pc); + + Object proxy = aop.getProxy(); + assertTrue(proxy instanceof ITestBean); + assertTrue(!(proxy instanceof TestBean)); + } + + public void testInterceptorIsInvokedWithNoTarget() throws Throwable { + // Test return value + int age = 25; + MockControl miControl = MockControl.createControl(MethodInterceptor.class); + MethodInterceptor mi = (MethodInterceptor) miControl.getMock(); + + AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class }); + pc.addAdvice(mi); + AopProxy aop = createAopProxy(pc); + + // Really would like to permit null arg:can't get exact mi + mi.invoke(null); + //mi.invoke(new MethodInvocationImpl(aop, null, ITestBean.class, + // ITestBean.class.getMethod("getAge", null), + // null, l, r)); + //miControl. + //miControl.setReturnValue(new Integer(age)); + // Have disabled strong argument checking + miControl.setDefaultReturnValue(new Integer(age)); + miControl.replay(); + + ITestBean tb = (ITestBean) aop.getProxy(); + assertTrue("correct return value", tb.getAge() == age); + miControl.verify(); + } + + public void testTargetCanGetInvocationWithPrivateClass() throws Throwable { + final ExposedInvocationTestBean expectedTarget = new ExposedInvocationTestBean() { + protected void assertions(MethodInvocation invocation) { + assertTrue(invocation.getThis() == this); + assertTrue("Invocation should be on ITestBean: " + invocation.getMethod(), + invocation.getMethod().getDeclaringClass() == ITestBean.class); + } + }; + + AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class, IOther.class }); + pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); + TrapTargetInterceptor tii = new TrapTargetInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + // Assert that target matches BEFORE invocation returns + assertEquals("Target is correct", expectedTarget, invocation.getThis()); + return super.invoke(invocation); + } + }; + pc.addAdvice(tii); + pc.setTarget(expectedTarget); + AopProxy aop = createAopProxy(pc); + + ITestBean tb = (ITestBean) aop.getProxy(); + tb.getName(); + // Not safe to trap invocation + //assertTrue(tii.invocation == target.invocation); + + //assertTrue(target.invocation.getProxy() == tb); + + // ((IOther) tb).absquatulate(); + //MethodInvocation minv = tii.invocation; + //assertTrue("invoked on iother, not " + minv.getMethod().getDeclaringClass(), minv.getMethod().getDeclaringClass() == IOther.class); + //assertTrue(target.invocation == tii.invocation); + } + + public void testProxyNotWrappedIfIncompatible() { + FooBar bean = new FooBar(); + ProxyCreatorSupport as = new ProxyCreatorSupport(); + as.setInterfaces(new Class[] {Foo.class}); + as.setTarget(bean); + + Foo proxy = (Foo) createProxy(as); + assertSame("Target should be returned when return types are incompatible", bean, proxy.getBarThis()); + assertSame("Proxy should be returned when return types are compatible", proxy, proxy.getFooThis()); + + } + + public void testEqualsAndHashCodeDefined() throws Exception { + AdvisedSupport as = new AdvisedSupport(new Class[]{Named.class}); + as.setTarget(new Person()); + JdkDynamicAopProxy aopProxy = new JdkDynamicAopProxy(as); + Named proxy = (Named) aopProxy.getProxy(); + Named named = new Person(); + assertEquals("equals() returned false", proxy, named); + assertEquals("hashCode() not equal", proxy.hashCode(), named.hashCode()); + } + + + public static interface Foo { + + Bar getBarThis(); + + Foo getFooThis(); + } + + + public static interface Bar { + + } + + + public static class FooBar implements Foo, Bar { + + public Bar getBarThis() { + return this; + } + + public Foo getFooThis() { + return this; + } + } + + + public static interface Named { + + String getName(); + + boolean equals(Object other); + + int hashCode(); + } + + + public static class Person implements Named { + + private final String name = "Rob Harrop"; + + public String getName() { + return this.name; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Person person = (Person) o; + + if (!name.equals(person.name)) return false; + + return true; + } + + public int hashCode() { + return name.hashCode(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixin.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixin.java new file mode 100644 index 00000000000..635588aaaa1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixin.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.aop.support.DelegatingIntroductionInterceptor; + + +/** + * Mixin to provide stateful locking functionality. + * Test/demonstration of AOP mixin support rather than a + * useful interceptor in its own right. + * + * @author Rod Johnson + * @since 10.07.2003 + */ +public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable { + + /** This field demonstrates additional state in the mixin */ + private boolean locked; + + public void lock() { + this.locked = true; + } + + public void unlock() { + this.locked = false; + } + + /** + * @see org.springframework.aop.framework.AopProxyTests.Lockable#locked() + */ + public boolean locked() { + return this.locked; + } + + /** + * Note that we need to override around advice. + * If the method is a setter and we're locked, prevent execution. + * Otherwise let super.invoke() handle it, and do normal + * Lockable(this) then target behaviour. + * @see org.aopalliance.MethodInterceptor#invoke(org.aopalliance.MethodInvocation) + */ + public Object invoke(MethodInvocation invocation) throws Throwable { + if (locked() && invocation.getMethod().getName().indexOf("set") == 0) + throw new LockedException(); + return super.invoke(invocation); + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixinAdvisor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixinAdvisor.java new file mode 100644 index 00000000000..a3b600cc739 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockMixinAdvisor.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.springframework.aop.support.DefaultIntroductionAdvisor; + +/** + * Advisor for use with a LockMixin. Applies to all classes. + * + * @author Rod Johnson + */ +public class LockMixinAdvisor extends DefaultIntroductionAdvisor { + + public LockMixinAdvisor() { + super(new LockMixin(), Lockable.class); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/Lockable.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/Lockable.java new file mode 100644 index 00000000000..70d6b2cfa5f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/Lockable.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + + +/** + * Simple interface to use for mixins + * + * @author Rod Johnson + * + */ +public interface Lockable { + + void lock(); + + void unlock(); + + boolean locked(); +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockedException.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockedException.java new file mode 100644 index 00000000000..cbea82f2a28 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/LockedException.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + + +public class LockedException extends RuntimeException { + + public LockedException() { + } +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodCounter.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodCounter.java new file mode 100644 index 00000000000..d3030ffe8e0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodCounter.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.HashMap; + +/** + * Useful abstract superclass for counting advices etc. + * + * @author Rod Johnson + */ +public class MethodCounter implements Serializable { + + /** Method name --> count, does not understand overloading */ + private HashMap map = new HashMap(); + + private int allCount; + + protected void count(Method m) { + count(m.getName()); + } + + protected void count(String methodName) { + Integer i = (Integer) map.get(methodName); + i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1); + map.put(methodName, i); + ++allCount; + } + + public int getCalls(String methodName) { + Integer i = (Integer) map.get(methodName); + return (i != null ? i.intValue() : 0); + } + + public int getCalls() { + return allCount; + } + + /** + * A bit simplistic: just wants the same class. + * Doesn't worry about counts. + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object other) { + return (other != null && other.getClass() == this.getClass()); + } + + public int hashCode() { + return getClass().hashCode(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java new file mode 100644 index 00000000000..45d3f970e50 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.beans.TestBean; + +/** + * TODO: could refactor to be generic. + * @author Rod Johnson + * @since 14.03.2003 + */ +public class MethodInvocationTests extends TestCase { + + /* + public static MethodInvocation testInvocation(Object o, String methodName, Class[] args, Interceptor[] interceptors) throws Exception { + Method m = o.getClass().getMethod(methodName, args); + MethodInvocationImpl invocation = new MethodInvocationImpl(null, null, m.getDeclaringClass(), + m, null, interceptors, // list + new Attrib4jAttributeRegistry()); + return invocation; + }*/ + + /* + public void testNullInterceptor() throws Exception { + Method m = Object.class.getMethod("hashCode", null); + Object proxy = new Object(); + try { + MethodInvocationImpl invocation = new MethodInvocationImpl(proxy, null, m.getDeclaringClass(), //? + m, null, null // could customize here + ); + fail("Shouldn't be able to create methodInvocationImpl with null interceptors"); + } catch (AopConfigException ex) { + } + } + + public void testEmptyInterceptorList() throws Exception { + Method m = Object.class.getMethod("hashCode", null); + Object proxy = new Object(); + try { + MethodInvocationImpl invocation = new MethodInvocationImpl(proxy, null, m.getDeclaringClass(), //? + m, null, new LinkedList() // list + ); + fail("Shouldn't be able to create methodInvocationImpl with no interceptors"); + } catch (AopConfigException ex) { + } + } + */ + + public void testValidInvocation() throws Throwable { + Method m = Object.class.getMethod("hashCode", (Class[]) null); + Object proxy = new Object(); + final Object returnValue = new Object(); + List is = new LinkedList(); + is.add(new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + return returnValue; + } + }); + ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(proxy, null, //? + m, null, null, is // list + ); + Object rv = invocation.proceed(); + assertTrue("correct response", rv == returnValue); + } + + /** + * ToString on target can cause failure. + */ + public void testToStringDoesntHitTarget() throws Throwable { + Object target = new TestBean() { + public String toString() { + throw new UnsupportedOperationException("toString"); + } + }; + final Object returnValue = new Object(); + List is = new LinkedList(); + + Method m = Object.class.getMethod("hashCode", (Class[]) null); + Object proxy = new Object(); + ReflectiveMethodInvocation invocation = + new ReflectiveMethodInvocation(proxy, target, m, null, null, is); + + // If it hits target, the test will fail with the UnsupportedOpException + // in the inner class above. + invocation.toString(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodVisibilities.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodVisibilities.java new file mode 100644 index 00000000000..ad6b83463e1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MethodVisibilities.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +/** + * Test for different method visibilities to + * test AOP proxying capabilities + * @author Rod Johnson + */ +public class MethodVisibilities { + + public String publicMethod(String s) { + return s; + } + + protected String protectedMethod(String s) { + return s; + } + + private String privateMethod(String s) { + return s; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MockTargetSource.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MockTargetSource.java new file mode 100644 index 00000000000..c2761d8492a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/MockTargetSource.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.springframework.aop.TargetSource; + +/** + * + * @author Rod Johnson + */ +public class MockTargetSource implements TargetSource { + + private Object target; + + public int gets; + + public int releases; + + public void reset() { + this.target = null; + gets = releases = 0; + } + + public void setTarget(Object target) { + this.target = target; + } + + /** + * @see org.springframework.aop.TargetSource#getTargetClass() + */ + public Class getTargetClass() { + return target.getClass(); + } + + /** + * @see org.springframework.aop.TargetSource#getTarget() + */ + public Object getTarget() throws Exception { + ++gets; + return target; + } + + /** + * @see org.springframework.aop.TargetSource#releaseTarget(java.lang.Object) + */ + public void releaseTarget(Object pTarget) throws Exception { + if (pTarget != this.target) + throw new RuntimeException("Released wrong target"); + ++releases; + } + + /** + * Check that gets and releases match + * + */ + public void verify() { + if (gets != releases) + throw new RuntimeException("Expectation failed: " + gets + " gets and " + releases + " releases"); + } + + /** + * @see org.springframework.aop.TargetSource#isStatic() + */ + public boolean isStatic() { + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoArgCtorTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoArgCtorTestBean.java new file mode 100644 index 00000000000..e872f72d82d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoArgCtorTestBean.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +/** + * @author Rob Harrop + */ +public class NoArgCtorTestBean { + + private boolean called = false; + + public NoArgCtorTestBean(String x, int y) { + called = true; + } + + public boolean wasCalled() { + return called; + } + + public void reset() { + called = false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfaces.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfaces.java new file mode 100644 index 00000000000..603f14112d6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfaces.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +/** + * Used for testing CGLIB proxying. + * + * @author Rod Johnson + */ +public class NoInterfaces { + + private int age; + + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfacesConstructor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfacesConstructor.java new file mode 100644 index 00000000000..e13bf0c901c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/NoInterfacesConstructor.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +/** + * + * @author Rod Johnson + */ +public class NoInterfacesConstructor extends NoInterfaces { + + public NoInterfacesConstructor(int age) { + setAge(age); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProtectedMethodTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProtectedMethodTestBean.java new file mode 100644 index 00000000000..e4f45fe50fe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProtectedMethodTestBean.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +/** + * @author Rob Harrop + */ +public class ProtectedMethodTestBean { + + protected String getString() { + return "foo"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java new file mode 100644 index 00000000000..e8604759fd2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + * @since 03.09.2004 + */ +public class PrototypeTargetTests extends TestCase { + + public void testPrototypeProxyWithPrototypeTarget() { + TestBeanImpl.constructionCount = 0; + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("prototypeTarget.xml", getClass())); + for (int i = 0; i < 10; i++) { + TestBean tb = (TestBean) xbf.getBean("testBeanPrototype"); + tb.doSomething(); + } + TestInterceptor interceptor = (TestInterceptor) xbf.getBean("testInterceptor"); + assertEquals(10, TestBeanImpl.constructionCount); + assertEquals(10, interceptor.invocationCount); + } + + public void testSingletonProxyWithPrototypeTarget() { + TestBeanImpl.constructionCount = 0; + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("prototypeTarget.xml", getClass())); + for (int i = 0; i < 10; i++) { + TestBean tb = (TestBean) xbf.getBean("testBeanSingleton"); + tb.doSomething(); + } + TestInterceptor interceptor = (TestInterceptor) xbf.getBean("testInterceptor"); + assertEquals(1, TestBeanImpl.constructionCount); + assertEquals(10, interceptor.invocationCount); + } + + + public static interface TestBean { + + public void doSomething(); + } + + + public static class TestBeanImpl implements TestBean { + + private static int constructionCount = 0; + + public TestBeanImpl() { + constructionCount++; + } + + public void doSomething() { + } + } + + + public static class TestInterceptor implements MethodInterceptor { + + private int invocationCount = 0; + + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + invocationCount++; + return methodInvocation.proceed(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java new file mode 100644 index 00000000000..6a037a26cd7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java @@ -0,0 +1,722 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; +import org.aopalliance.aop.Advice; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.aop.ClassFilter; +import org.springframework.aop.IntroductionAdvisor; +import org.springframework.aop.IntroductionInterceptor; +import org.springframework.aop.framework.adapter.ThrowsAdviceInterceptorTests; +import org.springframework.aop.interceptor.DebugInterceptor; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.interceptor.SideEffectBean; +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.support.DefaultIntroductionAdvisor; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.DynamicMethodMatcherPointcut; +import org.springframework.beans.ITestBean; +import org.springframework.beans.Person; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.context.TestListener; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 13.03.2003 + */ +public class ProxyFactoryBeanTests extends TestCase { + + private BeanFactory factory; + + protected void setUp() throws Exception { + DefaultListableBeanFactory parent = new DefaultListableBeanFactory(); + parent.registerBeanDefinition("target2", new RootBeanDefinition(TestListener.class)); + this.factory = new XmlBeanFactory(new ClassPathResource("proxyFactoryTests.xml", getClass()), parent); + } + + public void testIsDynamicProxyWhenInterfaceSpecified() { + ITestBean test1 = (ITestBean) factory.getBean("test1"); + assertTrue("test1 is a dynamic proxy", Proxy.isProxyClass(test1.getClass())); + } + + public void testIsDynamicProxyWhenInterfaceSpecifiedForPrototype() { + ITestBean test1 = (ITestBean) factory.getBean("test2"); + assertTrue("test2 is a dynamic proxy", Proxy.isProxyClass(test1.getClass())); + } + + public void testIsDynamicProxyWhenAutodetectingInterfaces() { + ITestBean test1 = (ITestBean) factory.getBean("test3"); + assertTrue("test3 is a dynamic proxy", Proxy.isProxyClass(test1.getClass())); + } + + public void testIsDynamicProxyWhenAutodetectingInterfacesForPrototype() { + ITestBean test1 = (ITestBean) factory.getBean("test4"); + assertTrue("test4 is a dynamic proxy", Proxy.isProxyClass(test1.getClass())); + } + + /** + * Test that it's forbidden to specify TargetSource in both + * interceptor chain and targetSource property. + */ + public void testDoubleTargetSourcesAreRejected() { + testDoubleTargetSourceIsRejected("doubleTarget"); + // Now with conversion from arbitrary bean to a TargetSource + testDoubleTargetSourceIsRejected("arbitraryTarget"); + } + + private void testDoubleTargetSourceIsRejected(String name) { + try { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryDoubleTargetSourceTests.xml", getClass())); + ITestBean tb = (ITestBean) bf.getBean(name); + //assertEquals("Adam", tb.getName()); + fail("Should not allow TargetSource to be specified in interceptorNames as well as targetSource property"); + } + catch (BeanCreationException ex) { + // Root cause of the problem must be an AOP exception + AopConfigException aex = (AopConfigException) ex.getCause(); + assertTrue(aex.getMessage().indexOf("TargetSource") != -1); + } + } + + public void testTargetSourceNotAtEndOfInterceptorNamesIsRejected() { + try { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryTargetSourceNotLastTests.xml", getClass())); + bf.getBean("targetSourceNotLast"); + fail("TargetSource or non-advised object must be last in interceptorNames"); + } + catch (BeanCreationException ex) { + // Root cause of the problem must be an AOP exception + AopConfigException aex = (AopConfigException) ex.getCause(); + assertTrue(aex.getMessage().indexOf("interceptorNames") != -1); + } + } + + public void testGetObjectTypeWithDirectTarget() { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryTargetSourceTests.xml", getClass())); + + // We have a counting before advice here + CountingBeforeAdvice cba = (CountingBeforeAdvice) bf.getBean("countingBeforeAdvice"); + assertEquals(0, cba.getCalls()); + + ITestBean tb = (ITestBean) bf.getBean("directTarget"); + assertTrue(tb.getName().equals("Adam")); + assertEquals(1, cba.getCalls()); + + ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&directTarget"); + assertTrue("Has correct object type", TestBean.class.isAssignableFrom(pfb.getObjectType())); + } + + public void testGetObjectTypeWithTargetViaTargetSource() { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryTargetSourceTests.xml", getClass())); + ITestBean tb = (ITestBean) bf.getBean("viaTargetSource"); + assertTrue(tb.getName().equals("Adam")); + ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&viaTargetSource"); + assertTrue("Has correct object type", TestBean.class.isAssignableFrom(pfb.getObjectType())); + } + + public void testGetObjectTypeWithNoTargetOrTargetSource() { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryTargetSourceTests.xml", getClass())); + + ITestBean tb = (ITestBean) bf.getBean("noTarget"); + try { + tb.getName(); + fail(); + } + catch (UnsupportedOperationException ex) { + assertEquals("getName", ex.getMessage()); + } + FactoryBean pfb = (ProxyFactoryBean) bf.getBean("&noTarget"); + assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(pfb.getObjectType())); + } + + /** + * The instances are equal, but do not have object identity. + * Interceptors and interfaces and the target are the same. + */ + public void testSingletonInstancesAreEqual() { + ITestBean test1 = (ITestBean) factory.getBean("test1"); + ITestBean test1_1 = (ITestBean) factory.getBean("test1"); + //assertTrue("Singleton instances ==", test1 == test1_1); + assertEquals("Singleton instances ==", test1, test1_1); + test1.setAge(25); + assertEquals(test1.getAge(), test1_1.getAge()); + test1.setAge(250); + assertEquals(test1.getAge(), test1_1.getAge()); + Advised pc1 = (Advised) test1; + Advised pc2 = (Advised) test1_1; + assertEquals(pc1.getAdvisors(), pc2.getAdvisors()); + int oldLength = pc1.getAdvisors().length; + NopInterceptor di = new NopInterceptor(); + pc1.addAdvice(1, di); + assertEquals(pc1.getAdvisors(), pc2.getAdvisors()); + assertEquals("Now have one more advisor", oldLength + 1, pc2.getAdvisors().length); + assertEquals(di.getCount(), 0); + test1.setAge(5); + assertEquals(test1_1.getAge(), test1.getAge()); + assertEquals(di.getCount(), 3); + } + + public void testPrototypeInstancesAreNotEqual() { + assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("prototype"))); + ITestBean test2 = (ITestBean) factory.getBean("prototype"); + ITestBean test2_1 = (ITestBean) factory.getBean("prototype"); + assertTrue("Prototype instances !=", test2 != test2_1); + assertTrue("Prototype instances equal", test2.equals(test2_1)); + assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("prototype"))); + } + + /** + * Uses its own bean factory XML for clarity + * @param beanName name of the ProxyFactoryBean definition that should + * be a prototype + */ + private Object testPrototypeInstancesAreIndependent(String beanName) { + // Initial count value set in bean factory XML + int INITIAL_COUNT = 10; + + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("prototypeTests.xml", getClass())); + + // Check it works without AOP + SideEffectBean raw = (SideEffectBean) bf.getBean("prototypeTarget"); + assertEquals(INITIAL_COUNT, raw.getCount() ); + raw.doWork(); + assertEquals(INITIAL_COUNT+1, raw.getCount() ); + raw = (SideEffectBean) bf.getBean("prototypeTarget"); + assertEquals(INITIAL_COUNT, raw.getCount() ); + + // Now try with advised instances + SideEffectBean prototype2FirstInstance = (SideEffectBean) bf.getBean(beanName); + assertEquals(INITIAL_COUNT, prototype2FirstInstance.getCount() ); + prototype2FirstInstance.doWork(); + assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount() ); + + SideEffectBean prototype2SecondInstance = (SideEffectBean) bf.getBean(beanName); + assertFalse("Prototypes are not ==", prototype2FirstInstance == prototype2SecondInstance); + assertEquals(INITIAL_COUNT, prototype2SecondInstance.getCount() ); + assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount() ); + + return prototype2FirstInstance; + } + + public void testCglibPrototypeInstance() { + Object prototype = testPrototypeInstancesAreIndependent("cglibPrototype"); + assertTrue("It's a cglib proxy", AopUtils.isCglibProxy(prototype)); + assertFalse("It's not a dynamic proxy", AopUtils.isJdkDynamicProxy(prototype)); + } + + /** + * Test invoker is automatically added to manipulate target. + */ + public void testAutoInvoker() { + String name = "Hieronymous"; + TestBean target = (TestBean) factory.getBean("test"); + target.setName(name); + ITestBean autoInvoker = (ITestBean) factory.getBean("autoInvoker"); + assertTrue(autoInvoker.getName().equals(name)); + } + + public void testCanGetFactoryReferenceAndManipulate() { + ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test1"); + assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(config.getObjectType())); + assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("test1"))); + // Trigger lazy initialization. + config.getObject(); + assertEquals("Have one advisors", 1, config.getAdvisors().length); + assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(config.getObjectType())); + assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("test1"))); + + ITestBean tb = (ITestBean) factory.getBean("test1"); + // no exception + tb.hashCode(); + + final Exception ex = new UnsupportedOperationException("invoke"); + // Add evil interceptor to head of list + config.addAdvice(0, new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + throw ex; + } + }); + assertEquals("Have correct advisor count", 2, config.getAdvisors().length); + + tb = (ITestBean) factory.getBean("test1"); + try { + // Will fail now + tb.toString(); + fail("Evil interceptor added programmatically should fail all method calls"); + } + catch (Exception thrown) { + assertTrue(thrown == ex); + } + } + + public static class DependsOnITestBean { + public final ITestBean tb; + public DependsOnITestBean(ITestBean tb) { + this.tb = tb; + } + } + + /** + * Test that inner bean for target means that we can use + * autowire without ambiguity from target and proxy + */ + public void testTargetAsInnerBean() { + ListableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("innerBeanTarget.xml", getClass())); + ITestBean itb = (ITestBean) bf.getBean("testBean"); + assertEquals("innerBeanTarget", itb.getName()); + assertEquals("Only have proxy and interceptor: no target", 3, bf.getBeanDefinitionCount()); + DependsOnITestBean doit = (DependsOnITestBean) bf.getBean("autowireCheck"); + assertSame(itb, doit.tb); + } + + /** + * Try adding and removing interfaces and interceptors on prototype. + * Changes will only affect future references obtained from the factory. + * Each instance will be independent. + */ + public void testCanAddAndRemoveAspectInterfacesOnPrototype() { + try { + TimeStamped ts = (TimeStamped) factory.getBean("test2"); + fail("Shouldn't implement TimeStamped before manipulation"); + } + catch (ClassCastException ex) { + } + + ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test2"); + long time = 666L; + TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); + ti.setTime(time); + // Add to head of interceptor chain + int oldCount = config.getAdvisors().length; + config.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class)); + assertTrue(config.getAdvisors().length == oldCount + 1); + + TimeStamped ts = (TimeStamped) factory.getBean("test2"); + assertEquals(time, ts.getTimeStamp()); + + // Can remove + config.removeAdvice(ti); + assertTrue(config.getAdvisors().length == oldCount); + + // Check no change on existing object reference + assertTrue(ts.getTimeStamp() == time); + + try { + ts = (TimeStamped) factory.getBean("test2"); + fail("Should no longer implement TimeStamped"); + } + catch (ClassCastException ex) { + } + + // Now check non-effect of removing interceptor that isn't there + config.removeAdvice(new DebugInterceptor()); + assertTrue(config.getAdvisors().length == oldCount); + + ITestBean it = (ITestBean) ts; + DebugInterceptor debugInterceptor = new DebugInterceptor(); + config.addAdvice(0, debugInterceptor); + it.getSpouse(); + // Won't affect existing reference + assertTrue(debugInterceptor.getCount() == 0); + it = (ITestBean) factory.getBean("test2"); + it.getSpouse(); + assertEquals(1, debugInterceptor.getCount()); + config.removeAdvice(debugInterceptor); + it.getSpouse(); + + // Still invoked wiht old reference + assertEquals(2, debugInterceptor.getCount()); + + // not invoked with new object + it = (ITestBean) factory.getBean("test2"); + it.getSpouse(); + assertEquals(2, debugInterceptor.getCount()); + + // Our own timestamped reference should still work + assertEquals(time, ts.getTimeStamp()); + } + + /** + * Note that we can't add or remove interfaces without reconfiguring the + * singleton. + */ + public void testCanAddAndRemoveAdvicesOnSingleton() { + ITestBean it = (ITestBean) factory.getBean("test1"); + Advised pc = (Advised) it; + it.getAge(); + NopInterceptor di = new NopInterceptor(); + pc.addAdvice(0, di); + assertEquals(0, di.getCount()); + it.setAge(25); + assertEquals(25, it.getAge()); + assertEquals(2, di.getCount()); + } + + public void testMethodPointcuts() { + ITestBean tb = (ITestBean) factory.getBean("pointcuts"); + PointcutForVoid.reset(); + assertTrue("No methods intercepted", PointcutForVoid.methodNames.isEmpty()); + tb.getAge(); + assertTrue("Not void: shouldn't have intercepted", PointcutForVoid.methodNames.isEmpty()); + tb.setAge(1); + tb.getAge(); + tb.setName("Tristan"); + tb.toString(); + assertEquals("Recorded wrong number of invocations", 2, PointcutForVoid.methodNames.size()); + assertTrue(PointcutForVoid.methodNames.get(0).equals("setAge")); + assertTrue(PointcutForVoid.methodNames.get(1).equals("setName")); + } + + public void testCanAddThrowsAdviceWithoutAdvisor() throws Throwable { + BeanFactory f = new XmlBeanFactory(new ClassPathResource("throwsAdvice.xml", getClass())); + ThrowsAdviceInterceptorTests.MyThrowsHandler th = (ThrowsAdviceInterceptorTests.MyThrowsHandler) f.getBean("throwsAdvice"); + CountingBeforeAdvice cba = (CountingBeforeAdvice) f.getBean("countingBeforeAdvice"); + assertEquals(0, cba.getCalls()); + assertEquals(0, th.getCalls()); + ThrowsAdviceInterceptorTests.IEcho echo = (ThrowsAdviceInterceptorTests.IEcho) f.getBean("throwsAdvised"); + int i = 12; + echo.setA(i); + assertEquals(i, echo.getA()); + assertEquals(2, cba.getCalls()); + assertEquals(0, th.getCalls()); + Exception expected = new Exception(); + try { + echo.echoException(1, expected); + fail(); + } + catch (Exception ex) { + assertEquals(expected, ex); + } + // No throws handler method: count should still be 0 + assertEquals(0, th.getCalls()); + + // Handler knows how to handle this exception + expected = new ServletException(); + try { + echo.echoException(1, expected); + fail(); + } + catch (ServletException ex) { + assertEquals(expected, ex); + } + // One match + assertEquals(1, th.getCalls("servletException")); + } + + // These two fail the whole bean factory + // TODO put in sep file to check quality of error message + /* + public void testNoInterceptorNamesWithoutTarget() { + try { + ITestBean tb = (ITestBean) factory.getBean("noInterceptorNamesWithoutTarget"); + fail("Should require interceptor names"); + } + catch (AopConfigException ex) { + // Ok + } + } + + public void testNoInterceptorNamesWithTarget() { + ITestBean tb = (ITestBean) factory.getBean("noInterceptorNamesWithoutTarget"); + } + */ + + public void testEmptyInterceptorNames() { + XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("invalidProxyFactory.xml", getClass())); + try { + ITestBean tb = (ITestBean) factory.getBean("emptyInterceptorNames"); + fail("Interceptor names cannot be empty"); + } + catch (BeanCreationException ex) { + // Ok + } + } + + /** + * Globals must be followed by a target. + */ + public void testGlobalsWithoutTarget() { + XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("invalidProxyFactory.xml", getClass())); + try { + ITestBean tb = (ITestBean) factory.getBean("globalsWithoutTarget"); + fail("Should require target name"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getCause() instanceof AopConfigException); + } + } + + /** + * Checks that globals get invoked, + * and that they can add aspect interfaces unavailable + * to other beans. These interfaces don't need + * to be included in proxiedInterface []. + */ + public void testGlobalsCanAddAspectInterfaces() { + AddedGlobalInterface agi = (AddedGlobalInterface) factory.getBean("autoInvoker"); + assertTrue(agi.globalsAdded() == -1); + + ProxyFactoryBean pfb = (ProxyFactoryBean) factory.getBean("&validGlobals"); + // Trigger lazy initialization. + pfb.getObject(); + // 2 globals + 2 explicit + assertEquals("Have 2 globals and 2 explicit advisors", 3, pfb.getAdvisors().length); + + ApplicationListener l = (ApplicationListener) factory.getBean("validGlobals"); + agi = (AddedGlobalInterface) l; + assertTrue(agi.globalsAdded() == -1); + + try { + agi = (AddedGlobalInterface) factory.getBean("test1"); + fail("Aspect interface should't be implemeneted without globals"); + } + catch (ClassCastException ex) { + } + } + + public void testSerializableSingletonProxy() throws Exception { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("serializationTests.xml", getClass())); + Person p = (Person) bf.getBean("serializableSingleton"); + assertSame("Should be a Singleton", p, bf.getBean("serializableSingleton")); + Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p); + assertEquals(p, p2); + assertNotSame(p, p2); + assertEquals("serializableSingleton", p2.getName()); + + // Add unserializable advice + Advice nop = new NopInterceptor(); + ((Advised) p).addAdvice(nop); + // Check it still works + assertEquals(p2.getName(), p2.getName()); + assertFalse("Not serializable because an interceptor isn't serializable", SerializationTestUtils.isSerializable(p)); + + // Remove offending interceptor... + assertTrue(((Advised) p).removeAdvice(nop)); + assertTrue("Serializable again because offending interceptor was removed", SerializationTestUtils.isSerializable(p)); + } + + public void testSerializablePrototypeProxy() throws Exception { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("serializationTests.xml", getClass())); + Person p = (Person) bf.getBean("serializablePrototype"); + assertNotSame("Should not be a Singleton", p, bf.getBean("serializablePrototype")); + Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p); + assertEquals(p, p2); + assertNotSame(p, p2); + assertEquals("serializablePrototype", p2.getName()); + } + + public void testSerializableSingletonProxyFactoryBean() throws Exception { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("serializationTests.xml", getClass())); + Person p = (Person) bf.getBean("serializableSingleton"); + ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&serializableSingleton"); + ProxyFactoryBean pfb2 = (ProxyFactoryBean) SerializationTestUtils.serializeAndDeserialize(pfb); + Person p2 = (Person) pfb2.getObject(); + assertEquals(p, p2); + assertNotSame(p, p2); + assertEquals("serializableSingleton", p2.getName()); + } + + public void testProxyNotSerializableBecauseOfAdvice() throws Exception { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("serializationTests.xml", getClass())); + Person p = (Person) bf.getBean("interceptorNotSerializableSingleton"); + assertFalse("Not serializable because an interceptor isn't serializable", SerializationTestUtils.isSerializable(p)); + } + + public void testPrototypeAdvisor() { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryTests.xml", getClass())); + + ITestBean bean1 = (ITestBean) bf.getBean("prototypeTestBeanProxy"); + ITestBean bean2 = (ITestBean) bf.getBean("prototypeTestBeanProxy"); + + bean1.setAge(3); + bean2.setAge(4); + + assertEquals(3, bean1.getAge()); + assertEquals(4, bean2.getAge()); + + ((Lockable) bean1).lock(); + + try { + bean1.setAge(5); + fail("expected LockedException"); + } + catch (LockedException ex) { + // expected + } + + try { + bean2.setAge(6); + } + catch (LockedException ex) { + fail("did not expect LockedException"); + } + } + + public void testPrototypeInterceptorSingletonTarget() { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryTests.xml", getClass())); + + ITestBean bean1 = (ITestBean) bf.getBean("prototypeTestBeanProxySingletonTarget"); + ITestBean bean2 = (ITestBean) bf.getBean("prototypeTestBeanProxySingletonTarget"); + + bean1.setAge(1); + bean2.setAge(2); + + assertEquals(2, bean1.getAge()); + + ((Lockable) bean1).lock(); + + try { + bean1.setAge(5); + fail("expected LockedException"); + } + catch (LockedException ex) { + // expected + } + + try { + bean2.setAge(6); + } + catch (LockedException ex) { + fail("did not expect LockedException"); + } + } + + /** + * Simple test of a ProxyFactoryBean that has an inner bean as target that specifies autowiring. + * Checks for correct use of getType() by bean factory. + */ + public void testInnerBeanTargetUsingAutowiring() { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryBeanAutowiringTests.xml", getClass())); + bf.getBean("testBean"); + } + + public void testFrozenFactoryBean() { + BeanFactory bf = new XmlBeanFactory(new ClassPathResource("frozenProxyFactoryBean.xml", getClass())); + + Advised advised = (Advised)bf.getBean("frozen"); + assertTrue("The proxy should be frozen", advised.isFrozen()); + } + + public void testDetectsInterfaces() throws Exception { + ProxyFactoryBean fb = new ProxyFactoryBean(); + fb.setTarget(new TestBean()); + fb.addAdvice(new DebugInterceptor()); + fb.setBeanFactory(new DefaultListableBeanFactory()); + ITestBean proxy = (ITestBean) fb.getObject(); + assertTrue(AopUtils.isJdkDynamicProxy(proxy)); + } + /** + * Fires only on void methods. Saves list of methods intercepted. + */ + public static class PointcutForVoid extends DefaultPointcutAdvisor { + + public static List methodNames = new LinkedList(); + + public static void reset() { + methodNames.clear(); + } + + public PointcutForVoid() { + setAdvice(new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + methodNames.add(invocation.getMethod().getName()); + return invocation.proceed(); + } + }); + setPointcut(new DynamicMethodMatcherPointcut() { + public boolean matches(Method m, Class targetClass, Object[] args) { + return m.getReturnType() == Void.TYPE; + } + }); + } + } + + + /** + * Aspect interface + */ + public interface AddedGlobalInterface { + int globalsAdded(); + } + + + /** + * Use as a global interceptor. Checks that + * global interceptors can add aspect interfaces. + * NB: Add only via global interceptors in XML file. + */ + public static class GlobalAspectInterfaceInterceptor implements IntroductionInterceptor { + + public boolean implementsInterface(Class intf) { + return intf.equals(AddedGlobalInterface.class); + } + + public Object invoke(MethodInvocation mi) throws Throwable { + if (mi.getMethod().getDeclaringClass().equals(AddedGlobalInterface.class)) { + return new Integer(-1); + } + return mi.proceed(); + } + } + + + public static class GlobalIntroductionAdvice implements IntroductionAdvisor { + + private IntroductionInterceptor gi = new GlobalAspectInterfaceInterceptor(); + + public ClassFilter getClassFilter() { + return ClassFilter.TRUE; + } + + public Advice getAdvice() { + return this.gi; + } + + public Class[] getInterfaces() { + return new Class[] { AddedGlobalInterface.class }; + } + + public boolean isPerInstance() { + return false; + } + + public void validateInterfaces() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java new file mode 100644 index 00000000000..af956815d59 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java @@ -0,0 +1,292 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import junit.framework.TestCase; + +import org.springframework.aop.Advisor; +import org.springframework.aop.interceptor.DebugInterceptor; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.support.DefaultIntroductionAdvisor; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.beans.IOther; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.transaction.interceptor.TransactionInterceptor; + +/** + * Also tests AdvisedSupport and ProxyCreatorSupport superclasses. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 14.05.2003 + */ +public class ProxyFactoryTests extends TestCase { + + public void testIndexOfMethods() { + TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + Advisor advisor = new DefaultPointcutAdvisor(new CountingBeforeAdvice()); + Advised advised = (Advised) pf.getProxy(); + // Can use advised and ProxyFactory interchangeably + advised.addAdvice(nop); + pf.addAdvisor(advisor); + assertEquals(-1, pf.indexOf(new NopInterceptor())); + assertEquals(0, pf.indexOf(nop)); + assertEquals(1, pf.indexOf(advisor)); + assertEquals(-1, advised.indexOf(new DefaultPointcutAdvisor(null))); + } + + public void testRemoveAdvisorByReference() { + TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + Advisor advisor = new DefaultPointcutAdvisor(cba); + pf.addAdvice(nop); + pf.addAdvisor(advisor); + ITestBean proxied = (ITestBean) pf.getProxy(); + proxied.setAge(5); + assertEquals(1, cba.getCalls()); + assertEquals(1, nop.getCount()); + assertTrue(pf.removeAdvisor(advisor)); + assertEquals(5, proxied.getAge()); + assertEquals(1, cba.getCalls()); + assertEquals(2, nop.getCount()); + assertFalse(pf.removeAdvisor(new DefaultPointcutAdvisor(null))); + } + + public void testRemoveAdvisorByIndex() { + TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + CountingBeforeAdvice cba = new CountingBeforeAdvice(); + Advisor advisor = new DefaultPointcutAdvisor(cba); + pf.addAdvice(nop); + pf.addAdvisor(advisor); + NopInterceptor nop2 = new NopInterceptor(); + pf.addAdvice(nop2); + ITestBean proxied = (ITestBean) pf.getProxy(); + proxied.setAge(5); + assertEquals(1, cba.getCalls()); + assertEquals(1, nop.getCount()); + assertEquals(1, nop2.getCount()); + // Removes counting before advisor + pf.removeAdvisor(1); + assertEquals(5, proxied.getAge()); + assertEquals(1, cba.getCalls()); + assertEquals(2, nop.getCount()); + assertEquals(2, nop2.getCount()); + // Removes Nop1 + pf.removeAdvisor(0); + assertEquals(5, proxied.getAge()); + assertEquals(1, cba.getCalls()); + assertEquals(2, nop.getCount()); + assertEquals(3, nop2.getCount()); + + // Check out of bounds + try { + pf.removeAdvisor(-1); + } + catch (AopConfigException ex) { + // Ok + } + + try { + pf.removeAdvisor(2); + } + catch (AopConfigException ex) { + // Ok + } + + assertEquals(5, proxied.getAge()); + assertEquals(4, nop2.getCount()); + } + + public void testReplaceAdvisor() { + TestBean target = new TestBean(); + ProxyFactory pf = new ProxyFactory(target); + NopInterceptor nop = new NopInterceptor(); + CountingBeforeAdvice cba1 = new CountingBeforeAdvice(); + CountingBeforeAdvice cba2 = new CountingBeforeAdvice(); + Advisor advisor1 = new DefaultPointcutAdvisor(cba1); + Advisor advisor2 = new DefaultPointcutAdvisor(cba2); + pf.addAdvisor(advisor1); + pf.addAdvice(nop); + ITestBean proxied = (ITestBean) pf.getProxy(); + // Use the type cast feature + // Replace etc methods on advised should be same as on ProxyFactory + Advised advised = (Advised) proxied; + proxied.setAge(5); + assertEquals(1, cba1.getCalls()); + assertEquals(0, cba2.getCalls()); + assertEquals(1, nop.getCount()); + assertFalse(advised.replaceAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()), advisor2)); + assertTrue(advised.replaceAdvisor(advisor1, advisor2)); + assertEquals(advisor2, pf.getAdvisors()[0]); + assertEquals(5, proxied.getAge()); + assertEquals(1, cba1.getCalls()); + assertEquals(2, nop.getCount()); + assertEquals(1, cba2.getCalls()); + assertFalse(pf.replaceAdvisor(new DefaultPointcutAdvisor(null), advisor1)); + } + + public void testAddRepeatedInterface() { + TimeStamped tst = new TimeStamped() { + public long getTimeStamp() { + throw new UnsupportedOperationException("getTimeStamp"); + } + }; + ProxyFactory pf = new ProxyFactory(tst); + // We've already implicitly added this interface. + // This call should be ignored without error + pf.addInterface(TimeStamped.class); + // All cool + TimeStamped ts = (TimeStamped) pf.getProxy(); + } + + public void testGetsAllInterfaces() throws Exception { + // Extend to get new interface + class TestBeanSubclass extends TestBean implements Comparable { + public int compareTo(Object arg0) { + throw new UnsupportedOperationException("compareTo"); + } + } + TestBeanSubclass raw = new TestBeanSubclass(); + ProxyFactory factory = new ProxyFactory(raw); + assertEquals("Found correct number of interfaces", 5, factory.getProxiedInterfaces().length); + //System.out.println("Proxied interfaces are " + StringUtils.arrayToDelimitedString(factory.getProxiedInterfaces(), ",")); + ITestBean tb = (ITestBean) factory.getProxy(); + assertTrue("Picked up secondary interface", tb instanceof IOther); + + raw.setAge(25); + assertTrue(tb.getAge() == raw.getAge()); + + long t = 555555L; + TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t); + + Class[] oldProxiedInterfaces = factory.getProxiedInterfaces(); + + factory.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class)); + + Class[] newProxiedInterfaces = factory.getProxiedInterfaces(); + assertEquals("Advisor proxies one more interface after introduction", oldProxiedInterfaces.length + 1, newProxiedInterfaces.length); + + TimeStamped ts = (TimeStamped) factory.getProxy(); + assertTrue(ts.getTimeStamp() == t); + // Shouldn't fail; + ((IOther) ts).absquatulate(); + } + + public void testInterceptorInclusionMethods() { + NopInterceptor di = new NopInterceptor(); + NopInterceptor diUnused = new NopInterceptor(); + ProxyFactory factory = new ProxyFactory(new TestBean()); + factory.addAdvice(0, di); + ITestBean tb = (ITestBean) factory.getProxy(); + assertTrue(factory.adviceIncluded(di)); + assertTrue(!factory.adviceIncluded(diUnused)); + assertTrue(factory.countAdvicesOfType(NopInterceptor.class) == 1); + assertTrue(factory.countAdvicesOfType(TransactionInterceptor.class) == 0); + + factory.addAdvice(0, diUnused); + assertTrue(factory.adviceIncluded(diUnused)); + assertTrue(factory.countAdvicesOfType(NopInterceptor.class) == 2); + } + + /** + * Should see effect immediately on behavior. + */ + public void testCanAddAndRemoveAspectInterfacesOnSingleton() { + ProxyFactory config = new ProxyFactory(new TestBean()); + + assertFalse("Shouldn't implement TimeStamped before manipulation", + config.getProxy() instanceof TimeStamped); + + long time = 666L; + TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); + ti.setTime(time); + + // Add to front of interceptor chain + int oldCount = config.getAdvisors().length; + config.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class)); + + assertTrue(config.getAdvisors().length == oldCount + 1); + + TimeStamped ts = (TimeStamped) config.getProxy(); + assertTrue(ts.getTimeStamp() == time); + + // Can remove + config.removeAdvice(ti); + + assertTrue(config.getAdvisors().length == oldCount); + + try { + // Existing reference will fail + ts.getTimeStamp(); + fail("Existing object won't implement this interface any more"); + } + catch (RuntimeException ex) { + } + + assertFalse("Should no longer implement TimeStamped", + config.getProxy() instanceof TimeStamped); + + // Now check non-effect of removing interceptor that isn't there + config.removeAdvice(new DebugInterceptor()); + + assertTrue(config.getAdvisors().length == oldCount); + + ITestBean it = (ITestBean) ts; + DebugInterceptor debugInterceptor = new DebugInterceptor(); + config.addAdvice(0, debugInterceptor); + it.getSpouse(); + assertEquals(1, debugInterceptor.getCount()); + config.removeAdvice(debugInterceptor); + it.getSpouse(); + // not invoked again + assertTrue(debugInterceptor.getCount() == 1); + } + + public void testProxyTargetClassWithInterfaceAsTarget() { + ProxyFactory pf = new ProxyFactory(); + pf.setTargetClass(ITestBean.class); + + Object proxy = pf.getProxy(); + assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy)); + assertTrue(proxy instanceof ITestBean); + } + + public void testProxyTargetClassWithConcreteClassAsTarget() { + ProxyFactory pf = new ProxyFactory(); + pf.setTargetClass(TestBean.class); + + Object proxy = pf.getProxy(); + assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy)); + assertTrue(proxy instanceof TestBean); + } + + + public static class Concrete { + + public void foo() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimeStamped.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimeStamped.java new file mode 100644 index 00000000000..e514210ec17 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimeStamped.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +/** + * This interface can be implemented by cacheable objects or cache entries, + * to enable the freshness of objects to be checked. + * + * @author Rod Johnson + */ +public interface TimeStamped { + + /** + * Return the timestamp for this object. + * @return long the timestamp for this object, + * as returned by System.currentTimeMillis() + */ + long getTimeStamp(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionAdvisor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionAdvisor.java new file mode 100644 index 00000000000..387d3818d36 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionAdvisor.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.springframework.aop.support.DelegatingIntroductionInterceptor; +import org.springframework.aop.support.DefaultIntroductionAdvisor; + +/** + * + * @author Rod Johnson + */ +public class TimestampIntroductionAdvisor extends DefaultIntroductionAdvisor { + + /** + * @param dii + */ + public TimestampIntroductionAdvisor() { + super(new DelegatingIntroductionInterceptor(new TimestampIntroductionInterceptor())); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionInterceptor.java new file mode 100644 index 00000000000..2584d2575c5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/TimestampIntroductionInterceptor.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.springframework.aop.support.DelegatingIntroductionInterceptor; + +public class TimestampIntroductionInterceptor extends DelegatingIntroductionInterceptor + implements TimeStamped { + + private long ts; + + public TimestampIntroductionInterceptor() { + } + + public TimestampIntroductionInterceptor(long ts) { + this.ts = ts; + } + + public void setTime(long ts) { + this.ts = ts; + } + + public long getTimeStamp() { + return ts; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/UnsupportedInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/UnsupportedInterceptor.java new file mode 100644 index 00000000000..7f3817c663c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/UnsupportedInterceptor.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * + * @author Rod Johnson + */ +public class UnsupportedInterceptor implements MethodInterceptor { + + /** + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + public Object invoke(MethodInvocation mi) throws Throwable { + throw new UnsupportedOperationException(mi.getMethod().getName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistrationTests.java new file mode 100644 index 00000000000..63bdb88bed4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistrationTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.adapter; + +import junit.framework.*; + +import org.springframework.aop.*; +import org.springframework.aop.support.*; +import org.springframework.aop.framework.Advised; +import org.springframework.beans.ITestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * TestCase for AdvisorAdapterRegistrationManager mechanism. + * + * @author Dmitriy Kopylenko + */ +public class AdvisorAdapterRegistrationTests extends TestCase { + + public AdvisorAdapterRegistrationTests(String name) { + super(name); + } + + public void testAdvisorAdapterRegistrationManagerNotPresentInContext() { + ApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/framework/adapter/withoutBPPContext.xml"); + ITestBean tb = (ITestBean) ctx.getBean("testBean"); + // just invoke any method to see if advice fired + try { + tb.getName(); + fail("Should throw UnknownAdviceTypeException"); + } + catch (UnknownAdviceTypeException ex) { + // expected + assertEquals(0, getAdviceImpl(tb).getInvocationCounter()); + } + } + + public void testAdvisorAdapterRegistrationManagerPresentInContext() { + ApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/framework/adapter/withBPPContext.xml"); + ITestBean tb = (ITestBean) ctx.getBean("testBean"); + // just invoke any method to see if advice fired + try { + tb.getName(); + assertEquals(1, getAdviceImpl(tb).getInvocationCounter()); + } + catch (UnknownAdviceTypeException ex) { + fail("Should not throw UnknownAdviceTypeException"); + } + } + + private SimpleBeforeAdviceImpl getAdviceImpl(ITestBean tb) { + Advised advised = (Advised) tb; + Advisor advisor = advised.getAdvisors()[0]; + return (SimpleBeforeAdviceImpl) advisor.getAdvice(); + } + + // temporary suite method to make tests work on JRockit! + // Alef knows more about this. + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new AdvisorAdapterRegistrationTests("testAdvisorAdapterRegistrationManagerNotPresentInContext")); + suite.addTest(new AdvisorAdapterRegistrationTests("testAdvisorAdapterRegistrationManagerPresentInContext")); + return suite; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java new file mode 100644 index 00000000000..176da331750 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java @@ -0,0 +1,197 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.adapter; + +import java.lang.reflect.Method; +import java.rmi.RemoteException; + +import javax.servlet.ServletException; +import javax.transaction.TransactionRolledbackException; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; + +import org.springframework.aop.ThrowsAdvice; +import org.springframework.aop.framework.MethodCounter; + +/** + * @author Rod Johnson + */ +public class ThrowsAdviceInterceptorTests extends TestCase { + + public void testNoHandlerMethods() { + Object o = new Object(); + try { + new ThrowsAdviceInterceptor(o); + fail("Should require one handler method at least"); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testNotInvoked() throws Throwable { + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + Object ret = new Object(); + MockControl mc = MockControl.createControl(MethodInvocation.class); + MethodInvocation mi = (MethodInvocation) mc.getMock(); + mi.proceed(); + mc.setReturnValue(ret, 1); + mc.replay(); + assertEquals(ret, ti.invoke(mi)); + assertEquals(0, th.getCalls()); + mc.verify(); + } + + public void testNoHandlerMethodForThrowable() throws Throwable { + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + assertEquals(2, ti.getHandlerMethodCount()); + Exception ex = new Exception(); + MockControl mc = MockControl.createControl(MethodInvocation.class); + MethodInvocation mi = (MethodInvocation) mc.getMock(); + mi.proceed(); + mc.setThrowable(ex); + mc.replay(); + try { + ti.invoke(mi); + fail(); + } + catch (Exception caught) { + assertEquals(ex, caught); + } + assertEquals(0, th.getCalls()); + mc.verify(); + } + + public void testCorrectHandlerUsed() throws Throwable { + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + ServletException ex = new ServletException(); + MockControl mc = MockControl.createControl(MethodInvocation.class); + MethodInvocation mi = (MethodInvocation) mc.getMock(); + mi.getMethod(); + mc.setReturnValue(Object.class.getMethod("hashCode", (Class[]) null), 1); + mi.getArguments(); + mc.setReturnValue(null); + mi.getThis(); + mc.setReturnValue(new Object()); + mi.proceed(); + mc.setThrowable(ex); + mc.replay(); + try { + ti.invoke(mi); + fail(); + } + catch (Exception caught) { + assertEquals(ex, caught); + } + assertEquals(1, th.getCalls()); + assertEquals(1, th.getCalls("servletException")); + mc.verify(); + } + + public void testCorrectHandlerUsedForSubclass() throws Throwable { + MyThrowsHandler th = new MyThrowsHandler(); + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + // Extends RemoteException + TransactionRolledbackException ex = new TransactionRolledbackException(); + MockControl mc = MockControl.createControl(MethodInvocation.class); + MethodInvocation mi = (MethodInvocation) mc.getMock(); + mi.proceed(); + mc.setThrowable(ex); + mc.replay(); + try { + ti.invoke(mi); + fail(); + } + catch (Exception caught) { + assertEquals(ex, caught); + } + assertEquals(1, th.getCalls()); + assertEquals(1, th.getCalls("remoteException")); + mc.verify(); + } + + public void testHandlerMethodThrowsException() throws Throwable { + final Throwable t = new Throwable(); + MyThrowsHandler th = new MyThrowsHandler() { + public void afterThrowing(RemoteException ex) throws Throwable { + super.afterThrowing(ex); + throw t; + } + }; + ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th); + // Extends RemoteException + TransactionRolledbackException ex = new TransactionRolledbackException(); + MockControl mc = MockControl.createControl(MethodInvocation.class); + MethodInvocation mi = (MethodInvocation) mc.getMock(); + mi.proceed(); + mc.setThrowable(ex); + mc.replay(); + try { + ti.invoke(mi); + fail(); + } + catch (Throwable caught) { + assertEquals(t, caught); + } + assertEquals(1, th.getCalls()); + assertEquals(1, th.getCalls("remoteException")); + mc.verify(); + } + + public static class MyThrowsHandler extends MethodCounter implements ThrowsAdvice { + // Full method signature + public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { + count("servletException"); + } + public void afterThrowing(RemoteException ex) throws Throwable { + count("remoteException"); + } + + /** Not valid, wrong number of arguments */ + public void afterThrowing(Method m, Exception ex) throws Throwable { + throw new UnsupportedOperationException("Shouldn't be called"); + } + } + + public interface IEcho { + int echoException(int i, Throwable t) throws Throwable; + int getA(); + void setA(int a); + } + + public static class Echo implements IEcho { + private int a; + + public int echoException(int i, Throwable t) throws Throwable { + if (t != null) + throw t; + return i; + } + public void setA(int a) { + this.a = a; + } + public int getA() { + return a; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withBPPContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withBPPContext.xml new file mode 100644 index 00000000000..df51623facd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withBPPContext.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + org.springframework.beans.ITestBean + simpleBeforeAdviceAdvisor,testBeanTarget + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withoutBPPContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withoutBPPContext.xml new file mode 100644 index 00000000000..d977ac4ee73 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/adapter/withoutBPPContext.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + org.springframework.beans.ITestBean + simpleBeforeAdviceAdvisor,testBeanTarget + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java new file mode 100644 index 00000000000..731d1e7fc07 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java @@ -0,0 +1,343 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import java.io.IOException; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.CountingBeforeAdvice; +import org.springframework.aop.framework.Lockable; +import org.springframework.aop.framework.MethodCounter; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.target.CommonsPoolTargetSource; +import org.springframework.aop.target.LazyInitTargetSource; +import org.springframework.aop.target.PrototypeTargetSource; +import org.springframework.aop.target.ThreadLocalTargetSource; +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.transaction.CallCountingTransactionManager; + +/** + * Tests for auto proxy creation by advisor recognition. + * + * @author Rod Johnson + */ +public class AdvisorAutoProxyCreatorTests extends TestCase { + + private static final String ADVISOR_APC_BEAN_NAME = "aapc"; + + private static final String TXMANAGER_BEAN_NAME = "txManager"; + + /** + * Return a bean factory with attributes and EnterpriseServices configured. + */ + protected BeanFactory getBeanFactory() throws IOException { + return new ClassPathXmlApplicationContext("/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreator.xml"); + } + + public void testDefaultExclusionPrefix() throws Exception { + DefaultAdvisorAutoProxyCreator aapc = (DefaultAdvisorAutoProxyCreator) getBeanFactory().getBean(ADVISOR_APC_BEAN_NAME); + assertEquals(ADVISOR_APC_BEAN_NAME + DefaultAdvisorAutoProxyCreator.SEPARATOR, aapc.getAdvisorBeanNamePrefix()); + assertFalse(aapc.isUsePrefix()); + } + + /** + * If no pointcuts match (no attrs) there should be proxying. + */ + public void testNoProxy() throws Exception { + BeanFactory bf = getBeanFactory(); + Object o = bf.getBean("noSetters"); + assertFalse(AopUtils.isAopProxy(o)); + } + + public void testTxIsProxied() throws Exception { + BeanFactory bf = getBeanFactory(); + ITestBean test = (ITestBean) bf.getBean("test"); + assertTrue(AopUtils.isAopProxy(test)); + } + + public void testRegexpApplied() throws Exception { + BeanFactory bf = getBeanFactory(); + ITestBean test = (ITestBean) bf.getBean("test"); + MethodCounter counter = (MethodCounter) bf.getBean("countingAdvice"); + assertEquals(0, counter.getCalls()); + test.getName(); + assertEquals(1, counter.getCalls()); + } + + /** + * Check that we can provide a common interceptor that will + * appear in the chain before "specific" interceptors, + * which are sourced from matching advisors + */ + public void testCommonInterceptorAndAdvisor() throws Exception { + BeanFactory bf = new ClassPathXmlApplicationContext("/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreatorWithCommonInterceptors.xml"); + ITestBean test1 = (ITestBean) bf.getBean("test1"); + assertTrue(AopUtils.isAopProxy(test1)); + + Lockable lockable1 = (Lockable) test1; + NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor"); + assertEquals(0, nop.getCount()); + + ITestBean test2 = (ITestBean) bf.getBean("test2"); + Lockable lockable2 = (Lockable) test2; + + // Locking should be independent; nop is shared + assertFalse(lockable1.locked()); + assertFalse(lockable2.locked()); + // equals 2 calls on shared nop, because it's first + // and sees calls against the Lockable interface introduced + // by the specific advisor + assertEquals(2, nop.getCount()); + lockable1.lock(); + assertTrue(lockable1.locked()); + assertFalse(lockable2.locked()); + assertEquals(5, nop.getCount()); + } + + /** + * We have custom TargetSourceCreators but there's no match, and + * hence no proxying, for this bean + */ + public void testCustomTargetSourceNoMatch() throws Exception { + BeanFactory bf = new ClassPathXmlApplicationContext("/org/springframework/aop/framework/autoproxy/customTargetSource.xml"); + ITestBean test = (ITestBean) bf.getBean("test"); + assertFalse(AopUtils.isAopProxy(test)); + assertEquals("Rod", test.getName()); + assertEquals("Kerry", test.getSpouse().getName()); + } + + public void testCustomPrototypeTargetSource() throws Exception { + CountingTestBean.count = 0; + BeanFactory bf = new ClassPathXmlApplicationContext("/org/springframework/aop/framework/autoproxy/customTargetSource.xml"); + ITestBean test = (ITestBean) bf.getBean("prototypeTest"); + assertTrue(AopUtils.isAopProxy(test)); + Advised advised = (Advised) test; + assertTrue(advised.getTargetSource() instanceof PrototypeTargetSource); + assertEquals("Rod", test.getName()); + // Check that references survived prototype creation + assertEquals("Kerry", test.getSpouse().getName()); + assertEquals("Only 2 CountingTestBeans instantiated", 2, CountingTestBean.count); + CountingTestBean.count = 0; + } + + public void testLazyInitTargetSource() throws Exception { + CountingTestBean.count = 0; + BeanFactory bf = new ClassPathXmlApplicationContext("/org/springframework/aop/framework/autoproxy/customTargetSource.xml"); + ITestBean test = (ITestBean) bf.getBean("lazyInitTest"); + assertTrue(AopUtils.isAopProxy(test)); + Advised advised = (Advised) test; + assertTrue(advised.getTargetSource() instanceof LazyInitTargetSource); + assertEquals("No CountingTestBean instantiated yet", 0, CountingTestBean.count); + assertEquals("Rod", test.getName()); + assertEquals("Kerry", test.getSpouse().getName()); + assertEquals("Only 1 CountingTestBean instantiated", 1, CountingTestBean.count); + CountingTestBean.count = 0; + } + + public void testQuickTargetSourceCreator() throws Exception { + ClassPathXmlApplicationContext bf = + new ClassPathXmlApplicationContext("/org/springframework/aop/framework/autoproxy/quickTargetSource.xml"); + ITestBean test = (ITestBean) bf.getBean("test"); + assertFalse(AopUtils.isAopProxy(test)); + assertEquals("Rod", test.getName()); + // Check that references survived pooling + assertEquals("Kerry", test.getSpouse().getName()); + + // Now test the pooled one + test = (ITestBean) bf.getBean(":test"); + assertTrue(AopUtils.isAopProxy(test)); + Advised advised = (Advised) test; + assertTrue(advised.getTargetSource() instanceof CommonsPoolTargetSource); + assertEquals("Rod", test.getName()); + // Check that references survived pooling + assertEquals("Kerry", test.getSpouse().getName()); + + // Now test the ThreadLocal one + test = (ITestBean) bf.getBean("%test"); + assertTrue(AopUtils.isAopProxy(test)); + advised = (Advised) test; + assertTrue(advised.getTargetSource() instanceof ThreadLocalTargetSource); + assertEquals("Rod", test.getName()); + // Check that references survived pooling + assertEquals("Kerry", test.getSpouse().getName()); + + // Now test the Prototype TargetSource + test = (ITestBean) bf.getBean("!test"); + assertTrue(AopUtils.isAopProxy(test)); + advised = (Advised) test; + assertTrue(advised.getTargetSource() instanceof PrototypeTargetSource); + assertEquals("Rod", test.getName()); + // Check that references survived pooling + assertEquals("Kerry", test.getSpouse().getName()); + + + ITestBean test2 = (ITestBean) bf.getBean("!test"); + assertFalse("Prototypes cannot be the same object", test == test2); + assertEquals("Rod", test2.getName()); + assertEquals("Kerry", test2.getSpouse().getName()); + bf.close(); + } + + /* + public void testIntroductionIsProxied() throws Exception { + BeanFactory bf = getBeanFactory(); + Object modifiable = bf.getBean("modifiable1"); + // We can tell it's a CGLIB proxy by looking at the class name + System.out.println(modifiable.getClass().getName()); + assertFalse(modifiable.getClass().getName().equals(ModifiableTestBean.class.getName())); + } + */ + + public void testTransactionAttributeOnMethod() throws Exception { + BeanFactory bf = getBeanFactory(); + ITestBean test = (ITestBean) bf.getBean("test"); + + CallCountingTransactionManager txMan = (CallCountingTransactionManager) bf.getBean(TXMANAGER_BEAN_NAME); + OrderedTxCheckAdvisor txc = (OrderedTxCheckAdvisor) bf.getBean("orderedBeforeTransaction"); + assertEquals(0, txc.getCountingBeforeAdvice().getCalls()); + + assertEquals(0, txMan.commits); + assertEquals("Initial value was correct", 4, test.getAge()); + int newAge = 5; + test.setAge(newAge); + assertEquals(1, txc.getCountingBeforeAdvice().getCalls()); + + assertEquals("New value set correctly", newAge, test.getAge()); + assertEquals("Transaction counts match", 1, txMan.commits); + } + + /** + * Should not roll back on servlet exception. + */ + public void testRollbackRulesOnMethodCauseRollback() throws Exception { + BeanFactory bf = getBeanFactory(); + Rollback rb = (Rollback) bf.getBean("rollback"); + + CallCountingTransactionManager txMan = (CallCountingTransactionManager) bf.getBean(TXMANAGER_BEAN_NAME); + OrderedTxCheckAdvisor txc = (OrderedTxCheckAdvisor) bf.getBean("orderedBeforeTransaction"); + assertEquals(0, txc.getCountingBeforeAdvice().getCalls()); + + assertEquals(0, txMan.commits); + rb.echoException(null); + // Fires only on setters + assertEquals(0, txc.getCountingBeforeAdvice().getCalls()); + assertEquals("Transaction counts match", 1, txMan.commits); + + assertEquals(0, txMan.rollbacks); + Exception ex = new Exception(); + try { + rb.echoException(ex); + } + catch (Exception actual) { + assertEquals(ex, actual); + } + assertEquals("Transaction counts match", 1, txMan.rollbacks); + } + + public void testRollbackRulesOnMethodPreventRollback() throws Exception { + BeanFactory bf = getBeanFactory(); + Rollback rb = (Rollback) bf.getBean("rollback"); + + CallCountingTransactionManager txMan = (CallCountingTransactionManager) bf.getBean(TXMANAGER_BEAN_NAME); + + assertEquals(0, txMan.commits); + // Should NOT roll back on ServletException + try { + rb.echoException(new ServletException()); + } + catch (ServletException ex) { + + } + assertEquals("Transaction counts match", 1, txMan.commits); + } + + public void testProgrammaticRollback() throws Exception { + BeanFactory bf = getBeanFactory(); + + Object bean = bf.getBean(TXMANAGER_BEAN_NAME); + assertTrue(bean instanceof CallCountingTransactionManager); + CallCountingTransactionManager txMan = (CallCountingTransactionManager) bf.getBean(TXMANAGER_BEAN_NAME); + + Rollback rb = (Rollback) bf.getBean("rollback"); + assertEquals(0, txMan.commits); + rb.rollbackOnly(false); + assertEquals("Transaction counts match", 1, txMan.commits); + assertEquals(0, txMan.rollbacks); + // Will cause rollback only + rb.rollbackOnly(true); + assertEquals(1, txMan.rollbacks); + } + + public void testWithOptimizedProxy() throws Exception { + BeanFactory beanFactory = new ClassPathXmlApplicationContext("org/springframework/aop/framework/autoproxy/optimizedAutoProxyCreator.xml"); + + ITestBean testBean = (ITestBean) beanFactory.getBean("optimizedTestBean"); + assertTrue(AopUtils.isAopProxy(testBean)); + + CountingBeforeAdvice beforeAdvice = (CountingBeforeAdvice) beanFactory.getBean("countingAdvice"); + + testBean.setAge(23); + testBean.getAge(); + + assertEquals("Incorrect number of calls to proxy", 2, beforeAdvice.getCalls()); + } + + + /** + * Tests an introduction pointcut. This is a prototype, so that it can add + * a Modifiable mixin. Tests that the autoproxy infrastructure can create + * advised objects with independent interceptor instances. + * The Modifiable behaviour of each instance of TestBean should be distinct. + */ + /* + public void testIntroductionViaPrototype() throws Exception { + BeanFactory bf = getBeanFactory(); + + Object o = bf.getBean("modifiable1"); + ITestBean modifiable1 = (ITestBean) bf.getBean("modifiable1"); + ITestBean modifiable2 = (ITestBean) bf.getBean("modifiable2"); + + Advised pc = (Advised) modifiable1; + System.err.println(pc.toProxyConfigString()); + + // For convenience only + Modifiable mod1 = (Modifiable) modifiable1; + Modifiable mod2 = (Modifiable) modifiable2; + + assertFalse(mod1.isModified()); + assertFalse(mod2.isModified()); + + int newAge = 33; + modifiable1.setAge(newAge); + assertTrue(mod1.isModified()); + // Changes to one shouldn't have affected the other + assertFalse("Instances of prototype introduction pointcut don't seem distinct", mod2.isModified()); + mod1.acceptChanges(); + assertFalse(mod1.isModified()); + assertEquals(modifiable1.getAge(), newAge); + assertFalse(mod1.isModified()); + } + */ + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java new file mode 100644 index 00000000000..8c98a02adea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java @@ -0,0 +1,308 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import java.lang.reflect.Proxy; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.aop.TargetSource; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.DummyFactory; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.MessageSource; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.context.support.StaticMessageSource; + +/** + * @author Juergen Hoeller + * @since 09.12.2003 + */ +public class AutoProxyCreatorTests extends TestCase { + + public void testBeanNameAutoProxyCreator() { + StaticApplicationContext sac = new StaticApplicationContext(); + sac.registerSingleton("testInterceptor", TestInterceptor.class); + + RootBeanDefinition proxyCreator = new RootBeanDefinition(BeanNameAutoProxyCreator.class); + proxyCreator.getPropertyValues().addPropertyValue("interceptorNames", "testInterceptor"); + proxyCreator.getPropertyValues().addPropertyValue("beanNames", "singletonToBeProxied,innerBean,singletonFactoryToBeProxied"); + sac.getDefaultListableBeanFactory().registerBeanDefinition("beanNameAutoProxyCreator", proxyCreator); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + RootBeanDefinition innerBean = new RootBeanDefinition(TestBean.class); + bd.getPropertyValues().addPropertyValue("spouse", new BeanDefinitionHolder(innerBean, "innerBean")); + sac.getDefaultListableBeanFactory().registerBeanDefinition("singletonToBeProxied", bd); + + sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class); + sac.registerSingleton("autowiredIndexedTestBean", IndexedTestBean.class); + + sac.refresh(); + + MessageSource messageSource = (MessageSource) sac.getBean("messageSource"); + ITestBean singletonToBeProxied = (ITestBean) sac.getBean("singletonToBeProxied"); + assertFalse(Proxy.isProxyClass(messageSource.getClass())); + assertTrue(Proxy.isProxyClass(singletonToBeProxied.getClass())); + assertTrue(Proxy.isProxyClass(singletonToBeProxied.getSpouse().getClass())); + + // test whether autowiring succeeded with auto proxy creation + assertEquals(sac.getBean("autowiredIndexedTestBean"), singletonToBeProxied.getNestedIndexedBean()); + + TestInterceptor ti = (TestInterceptor) sac.getBean("testInterceptor"); + // already 2: getSpouse + getNestedIndexedBean calls above + assertEquals(2, ti.nrOfInvocations); + singletonToBeProxied.getName(); + singletonToBeProxied.getSpouse().getName(); + assertEquals(5, ti.nrOfInvocations); + + ITestBean tb = (ITestBean) sac.getBean("singletonFactoryToBeProxied"); + assertTrue(AopUtils.isJdkDynamicProxy(tb)); + assertEquals(5, ti.nrOfInvocations); + tb.getAge(); + assertEquals(6, ti.nrOfInvocations); + + ITestBean tb2 = (ITestBean) sac.getBean("singletonFactoryToBeProxied"); + assertSame(tb, tb2); + assertEquals(6, ti.nrOfInvocations); + tb2.getAge(); + assertEquals(7, ti.nrOfInvocations); + } + + public void testBeanNameAutoProxyCreatorWithFactoryBeanProxy() { + StaticApplicationContext sac = new StaticApplicationContext(); + sac.registerSingleton("testInterceptor", TestInterceptor.class); + + RootBeanDefinition proxyCreator = new RootBeanDefinition(BeanNameAutoProxyCreator.class); + proxyCreator.getPropertyValues().addPropertyValue("interceptorNames", "testInterceptor"); + proxyCreator.getPropertyValues().addPropertyValue("beanNames", "singletonToBeProxied,&singletonFactoryToBeProxied"); + sac.getDefaultListableBeanFactory().registerBeanDefinition("beanNameAutoProxyCreator", proxyCreator); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + sac.getDefaultListableBeanFactory().registerBeanDefinition("singletonToBeProxied", bd); + + sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class); + + sac.refresh(); + + ITestBean singletonToBeProxied = (ITestBean) sac.getBean("singletonToBeProxied"); + assertTrue(Proxy.isProxyClass(singletonToBeProxied.getClass())); + + TestInterceptor ti = (TestInterceptor) sac.getBean("testInterceptor"); + assertEquals(0, ti.nrOfInvocations); + singletonToBeProxied.getName(); + assertEquals(1, ti.nrOfInvocations); + + FactoryBean factory = (FactoryBean) sac.getBean("&singletonFactoryToBeProxied"); + assertTrue(Proxy.isProxyClass(factory.getClass())); + TestBean tb = (TestBean) sac.getBean("singletonFactoryToBeProxied"); + assertFalse(AopUtils.isAopProxy(tb)); + assertEquals(3, ti.nrOfInvocations); + tb.getAge(); + assertEquals(3, ti.nrOfInvocations); + } + + public void testCustomAutoProxyCreator() { + StaticApplicationContext sac = new StaticApplicationContext(); + sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class); + sac.registerSingleton("singletonNoInterceptor", TestBean.class); + sac.registerSingleton("singletonToBeProxied", TestBean.class); + sac.registerPrototype("prototypeToBeProxied", TestBean.class); + sac.refresh(); + + MessageSource messageSource = (MessageSource) sac.getBean("messageSource"); + ITestBean singletonNoInterceptor = (ITestBean) sac.getBean("singletonNoInterceptor"); + ITestBean singletonToBeProxied = (ITestBean) sac.getBean("singletonToBeProxied"); + ITestBean prototypeToBeProxied = (ITestBean) sac.getBean("prototypeToBeProxied"); + assertFalse(AopUtils.isCglibProxy(messageSource)); + assertTrue(AopUtils.isCglibProxy(singletonNoInterceptor)); + assertTrue(AopUtils.isCglibProxy(singletonToBeProxied)); + assertTrue(AopUtils.isCglibProxy(prototypeToBeProxied)); + + TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator"); + assertEquals(0, tapc.testInterceptor.nrOfInvocations); + singletonNoInterceptor.getName(); + assertEquals(0, tapc.testInterceptor.nrOfInvocations); + singletonToBeProxied.getAge(); + assertEquals(1, tapc.testInterceptor.nrOfInvocations); + prototypeToBeProxied.getSpouse(); + assertEquals(2, tapc.testInterceptor.nrOfInvocations); + } + + public void testAutoProxyCreatorWithFactoryBean() { + StaticApplicationContext sac = new StaticApplicationContext(); + sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class); + sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class); + sac.refresh(); + + TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator"); + tapc.testInterceptor.nrOfInvocations = 0; + + FactoryBean factory = (FactoryBean) sac.getBean("&singletonFactoryToBeProxied"); + assertTrue(AopUtils.isCglibProxy(factory)); + + TestBean tb = (TestBean) sac.getBean("singletonFactoryToBeProxied"); + assertTrue(AopUtils.isCglibProxy(tb)); + assertEquals(2, tapc.testInterceptor.nrOfInvocations); + tb.getAge(); + assertEquals(3, tapc.testInterceptor.nrOfInvocations); + } + + public void testAutoProxyCreatorWithFactoryBeanAndPrototype() { + StaticApplicationContext sac = new StaticApplicationContext(); + sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("singleton", "false"); + sac.registerSingleton("prototypeFactoryToBeProxied", DummyFactory.class, pvs); + + sac.refresh(); + + TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator"); + tapc.testInterceptor.nrOfInvocations = 0; + + FactoryBean prototypeFactory = (FactoryBean) sac.getBean("&prototypeFactoryToBeProxied"); + assertTrue(AopUtils.isCglibProxy(prototypeFactory)); + TestBean tb = (TestBean) sac.getBean("prototypeFactoryToBeProxied"); + assertTrue(AopUtils.isCglibProxy(tb)); + + assertEquals(2, tapc.testInterceptor.nrOfInvocations); + tb.getAge(); + assertEquals(3, tapc.testInterceptor.nrOfInvocations); + } + + public void testAutoProxyCreatorWithFactoryBeanAndProxyObjectOnly() { + StaticApplicationContext sac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("proxyFactoryBean", "false"); + sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs); + + sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class); + + sac.refresh(); + + TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator"); + tapc.testInterceptor.nrOfInvocations = 0; + + FactoryBean factory = (FactoryBean) sac.getBean("&singletonFactoryToBeProxied"); + assertFalse(AopUtils.isAopProxy(factory)); + + TestBean tb = (TestBean) sac.getBean("singletonFactoryToBeProxied"); + assertTrue(AopUtils.isCglibProxy(tb)); + assertEquals(0, tapc.testInterceptor.nrOfInvocations); + tb.getAge(); + assertEquals(1, tapc.testInterceptor.nrOfInvocations); + + TestBean tb2 = (TestBean) sac.getBean("singletonFactoryToBeProxied"); + assertSame(tb, tb2); + assertEquals(1, tapc.testInterceptor.nrOfInvocations); + tb2.getAge(); + assertEquals(2, tapc.testInterceptor.nrOfInvocations); + } + + public void testAutoProxyCreatorWithFactoryBeanAndProxyFactoryBeanOnly() { + StaticApplicationContext sac = new StaticApplicationContext(); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("proxyObject", "false"); + sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("singleton", "false"); + sac.registerSingleton("prototypeFactoryToBeProxied", DummyFactory.class, pvs); + + sac.refresh(); + + TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator"); + tapc.testInterceptor.nrOfInvocations = 0; + + FactoryBean prototypeFactory = (FactoryBean) sac.getBean("&prototypeFactoryToBeProxied"); + assertTrue(AopUtils.isCglibProxy(prototypeFactory)); + TestBean tb = (TestBean) sac.getBean("prototypeFactoryToBeProxied"); + assertFalse(AopUtils.isCglibProxy(tb)); + + assertEquals(2, tapc.testInterceptor.nrOfInvocations); + tb.getAge(); + assertEquals(2, tapc.testInterceptor.nrOfInvocations); + } + + + public static class TestAutoProxyCreator extends AbstractAutoProxyCreator { + + private boolean proxyFactoryBean = true; + + private boolean proxyObject = true; + + public TestInterceptor testInterceptor = new TestInterceptor(); + + public TestAutoProxyCreator() { + setProxyTargetClass(true); + setOrder(0); + } + + public void setProxyFactoryBean(boolean proxyFactoryBean) { + this.proxyFactoryBean = proxyFactoryBean; + } + + public void setProxyObject(boolean proxyObject) { + this.proxyObject = proxyObject; + } + + protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String name, TargetSource customTargetSource) { + if (StaticMessageSource.class.equals(beanClass)) { + return DO_NOT_PROXY; + } + else if (name.endsWith("ToBeProxied")) { + boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass); + if ((this.proxyFactoryBean && isFactoryBean) || (this.proxyObject && !isFactoryBean)) { + return new Object[] {this.testInterceptor}; + } + else { + return DO_NOT_PROXY; + } + } + else { + return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; + } + } + } + + + /** + * Interceptor that counts the number of non-finalize method calls. + */ + public static class TestInterceptor implements MethodInterceptor { + + public int nrOfInvocations = 0; + + public Object invoke(MethodInvocation invocation) throws Throwable { + if (!invocation.getMethod().getName().equals("finalize")) { + this.nrOfInvocations++; + } + return invocation.proceed(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorInitTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorInitTests.java new file mode 100644 index 00000000000..8553eefd363 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorInitTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Juergen Hoeller + * @author Dave Syer + */ +public class BeanNameAutoProxyCreatorInitTests extends TestCase { + + public void testIgnoreAdvisorThatIsCurrentlyCreation() { + ClassPathXmlApplicationContext ctx = + new ClassPathXmlApplicationContext("beanNameAutoProxyCreatorInitTests.xml", getClass()); + TestBean bean = (TestBean) ctx.getBean("bean"); + bean.setName("foo"); + assertEquals("foo", bean.getName()); + try { + bean.setName(null); + fail("Expected IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java new file mode 100644 index 00000000000..7bb145c73b7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreatorTests.java @@ -0,0 +1,185 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.CountingBeforeAdvice; +import org.springframework.aop.framework.Lockable; +import org.springframework.aop.framework.LockedException; +import org.springframework.aop.framework.TimeStamped; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Rod Johnson + * @author Rob Harrop + */ +public class BeanNameAutoProxyCreatorTests extends TestCase { + + private BeanFactory beanFactory; + + protected void setUp() throws IOException { + // Note that we need an ApplicationContext, not just a BeanFactory, + // for post-processing and hence auto-proxying to work. + this.beanFactory = new ClassPathXmlApplicationContext("beanNameAutoProxyCreatorTests.xml", getClass()); + } + + public void testNoProxy() { + TestBean tb = (TestBean) beanFactory.getBean("noproxy"); + assertFalse(AopUtils.isAopProxy(tb)); + assertEquals("noproxy", tb.getName()); + } + + public void testJdkProxyWithExactNameMatch() { + ITestBean tb = (ITestBean) beanFactory.getBean("onlyJdk"); + jdkAssertions(tb, 1); + assertEquals("onlyJdk", tb.getName()); + } + + public void testJdkProxyWithDoubleProxying() { + ITestBean tb = (ITestBean) beanFactory.getBean("doubleJdk"); + jdkAssertions(tb, 2); + assertEquals("doubleJdk", tb.getName()); + } + + public void testJdkIntroduction() { + ITestBean tb = (ITestBean) beanFactory.getBean("introductionUsingJdk"); + NopInterceptor nop = (NopInterceptor) beanFactory.getBean("introductionNopInterceptor"); + assertEquals(0, nop.getCount()); + assertTrue(AopUtils.isJdkDynamicProxy(tb)); + int age = 5; + tb.setAge(age); + assertEquals(age, tb.getAge()); + assertTrue("Introduction was made", tb instanceof TimeStamped); + assertEquals(0, ((TimeStamped) tb).getTimeStamp()); + assertEquals(3, nop.getCount()); + assertEquals("introductionUsingJdk", tb.getName()); + + ITestBean tb2 = (ITestBean) beanFactory.getBean("second-introductionUsingJdk"); + + // Check two per-instance mixins were distinct + Lockable lockable1 = (Lockable) tb; + Lockable lockable2 = (Lockable) tb2; + assertFalse(lockable1.locked()); + assertFalse(lockable2.locked()); + tb.setAge(65); + assertEquals(65, tb.getAge()); + lockable1.lock(); + assertTrue(lockable1.locked()); + // Shouldn't affect second + assertFalse(lockable2.locked()); + // Can still mod second object + tb2.setAge(12); + // But can't mod first + try { + tb.setAge(6); + fail("Mixin should have locked this object"); + } + catch (LockedException ex) { + // Ok + } + } + + public void testJdkIntroductionAppliesToCreatedObjectsNotFactoryBean() { + ITestBean tb = (ITestBean) beanFactory.getBean("factory-introductionUsingJdk"); + NopInterceptor nop = (NopInterceptor) beanFactory.getBean("introductionNopInterceptor"); + assertEquals("NOP should not have done any work yet", 0, nop.getCount()); + assertTrue(AopUtils.isJdkDynamicProxy(tb)); + int age = 5; + tb.setAge(age); + assertEquals(age, tb.getAge()); + assertTrue("Introduction was made", tb instanceof TimeStamped); + assertEquals(0, ((TimeStamped) tb).getTimeStamp()); + assertEquals(3, nop.getCount()); + + ITestBean tb2 = (ITestBean) beanFactory.getBean("second-introductionUsingJdk"); + + // Check two per-instance mixins were distinct + Lockable lockable1 = (Lockable) tb; + Lockable lockable2 = (Lockable) tb2; + assertFalse(lockable1.locked()); + assertFalse(lockable2.locked()); + tb.setAge(65); + assertEquals(65, tb.getAge()); + lockable1.lock(); + assertTrue(lockable1.locked()); + // Shouldn't affect second + assertFalse(lockable2.locked()); + // Can still mod second object + tb2.setAge(12); + // But can't mod first + try { + tb.setAge(6); + fail("Mixin should have locked this object"); + } + catch (LockedException ex) { + // Ok + } + } + + public void testJdkProxyWithWildcardMatch() { + ITestBean tb = (ITestBean) beanFactory.getBean("jdk1"); + jdkAssertions(tb, 1); + assertEquals("jdk1", tb.getName()); + } + + public void testCglibProxyWithWildcardMatch() { + TestBean tb = (TestBean) beanFactory.getBean("cglib1"); + cglibAssertions(tb); + assertEquals("cglib1", tb.getName()); + } + + public void testWithFrozenProxy() { + ITestBean testBean = (ITestBean) beanFactory.getBean("frozenBean"); + assertTrue(((Advised)testBean).isFrozen()); + } + + private void jdkAssertions(ITestBean tb, int nopInterceptorCount) { + NopInterceptor nop = (NopInterceptor) beanFactory.getBean("nopInterceptor"); + assertEquals(0, nop.getCount()); + assertTrue(AopUtils.isJdkDynamicProxy(tb)); + int age = 5; + tb.setAge(age); + assertEquals(age, tb.getAge()); + assertEquals(2 * nopInterceptorCount, nop.getCount()); + } + + /** + * Also has counting before advice. + */ + private void cglibAssertions(TestBean tb) { + CountingBeforeAdvice cba = (CountingBeforeAdvice) beanFactory.getBean("countingBeforeAdvice"); + NopInterceptor nop = (NopInterceptor) beanFactory.getBean("nopInterceptor"); + assertEquals(0, cba.getCalls()); + assertEquals(0, nop.getCount()); + assertTrue(AopUtils.isCglibProxy(tb)); + int age = 5; + tb.setAge(age); + assertEquals(age, tb.getAge()); + assertEquals(2, nop.getCount()); + assertEquals(2, cba.getCalls()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CountingTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CountingTestBean.java new file mode 100644 index 00000000000..bd377aed847 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CountingTestBean.java @@ -0,0 +1,37 @@ +/* + * $Id: CountingTestBean.java,v 1.2 2005/03/25 09:28:17 jhoeller Exp $ + */ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import org.springframework.beans.TestBean; + +/** + * @author Juergen Hoeller + * @since 15.03.2005 + */ +public class CountingTestBean extends TestBean { + + public static int count = 0; + + public CountingTestBean() { + count++; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CreatesTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CreatesTestBean.java new file mode 100644 index 00000000000..f95da4b0620 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/CreatesTestBean.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.FactoryBean; + +/** + * + * @author Rod Johnson + */ +public class CreatesTestBean implements FactoryBean { + + /** + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + public Object getObject() throws Exception { + return new TestBean(); + } + + /** + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + public Class getObjectType() { + return TestBean.class; + } + + /** + * @see org.springframework.beans.factory.FactoryBean#isSingleton() + */ + public boolean isSingleton() { + return true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NeverMatchAdvisor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NeverMatchAdvisor.java new file mode 100644 index 00000000000..83377a8b712 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NeverMatchAdvisor.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import java.lang.reflect.Method; +import java.util.List; + +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; + +/** + * + * @author Rod Johnson + */ +public class NeverMatchAdvisor extends StaticMethodMatcherPointcutAdvisor { + + public NeverMatchAdvisor() { + super(new NopInterceptor()); + } + + /** + * This method is solely to allow us to create a mixture of dependencies in + * the bean definitions. The dependencies don't have any meaning, and don't + * do anything. + */ + public void setDependencies(List l) { + + } + + /** + * @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, java.lang.Class) + */ + public boolean matches(Method m, Class targetClass) { + //System.err.println("NeverMAtch test"); + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NoSetters.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NoSetters.java new file mode 100644 index 00000000000..5ecd63cc928 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NoSetters.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +/** + * + * @author Rod Johnson + */ +public class NoSetters { + + public void A() { + + } + + public int getB() { + return -1; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NullChecker.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NullChecker.java new file mode 100644 index 00000000000..343bf82b224 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/NullChecker.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import java.lang.reflect.Method; + +import org.springframework.aop.MethodBeforeAdvice; + +/** + * @author Dave Syer + */ +public class NullChecker implements MethodBeforeAdvice { + + public void before(Method method, Object[] args, Object target) throws Throwable { + check(args); + } + + private void check(Object[] args) { + for (int i = 0; i < args.length; i++) { + if (args[i] == null) { + throw new IllegalArgumentException("Null argument at position " + i); + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/OrderedTxCheckAdvisor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/OrderedTxCheckAdvisor.java new file mode 100644 index 00000000000..aa0c134ceb0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/OrderedTxCheckAdvisor.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import java.lang.reflect.Method; + +import org.springframework.aop.framework.CountingBeforeAdvice; +import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.transaction.NoTransactionException; +import org.springframework.transaction.interceptor.TransactionInterceptor; + +/** + * Before advisor that allow us to manipulate ordering to check + * that superclass sorting works correctly. + * + *

It doesn't actually do anything except count + * method invocations and check for presence of transaction context. + *
Matches setters. + * + * @author Rod Johnson + */ +public class OrderedTxCheckAdvisor extends StaticMethodMatcherPointcutAdvisor implements InitializingBean { + + /** + * Should we insist on the presence of a transaction attribute or refuse to accept one? + */ + private boolean requireTransactionContext = false; + + + public void setRequireTransactionContext(boolean requireTransactionContext) { + this.requireTransactionContext = requireTransactionContext; + } + + public boolean isRequireTransactionContext() { + return requireTransactionContext; + } + + + public CountingBeforeAdvice getCountingBeforeAdvice() { + return (CountingBeforeAdvice) getAdvice(); + } + + public void afterPropertiesSet() throws Exception { + setAdvice(new TxCountingBeforeAdvice()); + } + + public boolean matches(Method method, Class targetClass) { + return method.getName().startsWith("setAge"); + } + + + private class TxCountingBeforeAdvice extends CountingBeforeAdvice { + + public void before(Method method, Object[] args, Object target) throws Throwable { + // do transaction checks + if (requireTransactionContext) { + TransactionInterceptor.currentTransactionStatus(); + } + else { + try { + TransactionInterceptor.currentTransactionStatus(); + throw new RuntimeException("Shouldn't have a transaction"); + } + catch (NoTransactionException ex) { + // this is Ok + } + } + super.before(method, args, target); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/Rollback.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/Rollback.java new file mode 100644 index 00000000000..3b9caa59d80 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/Rollback.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import org.springframework.transaction.interceptor.TransactionInterceptor; + + + +/** + * @org.springframework.enterpriseservices.Pooling (size=10) + * @org.springframework.transaction.interceptor.DefaultTransaction ( timeout=-1 ) + */ +public class Rollback { + + /** + * Inherits transaction attribute. + * Illustrates programmatic rollback. + * @param rollbackOnly + */ + public void rollbackOnly(boolean rollbackOnly) { + if (rollbackOnly) { + setRollbackOnly(); + } + } + + /** + * Extracted in a protected method to facilitate testing + */ + protected void setRollbackOnly() { + TransactionInterceptor.currentTransactionStatus().setRollbackOnly(); + } + + /** + * @org.springframework.transaction.interceptor.RuleBasedTransaction ( timeout=-1 ) + * @org.springframework.transaction.interceptor.RollbackRule ( "java.lang.Exception" ) + * @org.springframework.transaction.interceptor.NoRollbackRule ( "ServletException" ) + */ + public void echoException(Exception ex) throws Exception { + if (ex != null) + throw ex; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/SelectivePrototypeTargetSourceCreator.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/SelectivePrototypeTargetSourceCreator.java new file mode 100644 index 00000000000..cf8b2ddc63e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/SelectivePrototypeTargetSourceCreator.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework.autoproxy; + +import org.springframework.aop.framework.autoproxy.target.AbstractBeanFactoryBasedTargetSourceCreator; +import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource; +import org.springframework.aop.target.PrototypeTargetSource; + +/** + * Overrides generic PrototypeTargetSourceCreator to create a prototype only for beans + * with names beginning with "prototype". + * + * @author Rod Johnson + */ +public class SelectivePrototypeTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator { + + protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource( + Class beanClass, String beanName) { + if (!beanName.startsWith("prototype")) { + return null; + } + return new PrototypeTargetSource(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreator.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreator.xml new file mode 100644 index 00000000000..a685b944529 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreator.xml @@ -0,0 +1,107 @@ + + + + + + + + Matches all Advisors in the factory: we don't use a prefix + + + + + + + 9 + false + + + + 11 + true + + + + + true + + + + + + + + + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED,+javax.servlet.ServletException,-java.lang.Exception + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + + + + + + + org.springframework.beans.ITestBean.getName + + + + + + 4 + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreatorWithCommonInterceptors.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreatorWithCommonInterceptors.xml new file mode 100644 index 00000000000..d24029bbf4b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/advisorAutoProxyCreatorWithCommonInterceptors.xml @@ -0,0 +1,47 @@ + + + + + + + + Matches all Advisors in the factory: we don't use a prefix + + + + + + + nopInterceptor + + + + + + + + + + 4 + + + + 4 + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorInitTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorInitTests.xml new file mode 100644 index 00000000000..53d945697e8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorInitTests.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + .*\.set[a-zA-Z]*(.*) + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorTests.xml new file mode 100644 index 00000000000..0eb5a4e870e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/beanNameAutoProxyCreatorTests.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + Automatically proxies using JDK dynamic proxies + + jdk*,onlyJdk,doubleJdk + + + nopInterceptor + + + + + + + + + + + + + cglib* + + + + Use the inherited ProxyConfig property to force CGLIB proxying + true + + + Interceptors and Advisors to apply automatically + + nopInterceptor + countingBeforeAdvice + + + + + + + Illustrates a JDK introduction + + *introductionUsingJdk + + + introductionNopInterceptor + timestampIntroduction + lockableAdvisor + + + + + + + + + + + + + + + + + introductionUsingJdk + + + + second-introductionUsingJdk + + + + + + + + jdk1 + + + + + + + + cglib1 + + + + onlyJdk + + + + doubleJdk + + + + noproxy + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/customTargetSource.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/customTargetSource.xml new file mode 100644 index 00000000000..2585661234f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/customTargetSource.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + Rod + + + + + Rod + + + + + Rod + + + + + Kerry + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/optimizedAutoProxyCreator.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/optimizedAutoProxyCreator.xml new file mode 100644 index 00000000000..aa771d402f0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/optimizedAutoProxyCreator.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + .*beans.I?TestBean.* + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/quickTargetSource.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/quickTargetSource.xml new file mode 100644 index 00000000000..949ad7cab9e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/autoproxy/quickTargetSource.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + Rod + + + + + Kerry + + + + + Rod + + + + + + Rod + + + + + + Rod + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/frozenProxyFactoryBean.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/frozenProxyFactoryBean.xml new file mode 100644 index 00000000000..8b5b7bf70e7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/frozenProxyFactoryBean.xml @@ -0,0 +1,28 @@ + + + + + + + + custom + 666 + + + + + + + + org.springframework.beans.ITestBean + + + debugInterceptor + true + true + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/innerBeanTarget.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/innerBeanTarget.xml new file mode 100644 index 00000000000..f36964b41a0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/innerBeanTarget.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + innerBeanTarget + + + + + nopInterceptor + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/invalidProxyFactory.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/invalidProxyFactory.xml new file mode 100644 index 00000000000..de65fec0fe1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/invalidProxyFactory.xml @@ -0,0 +1,21 @@ + + + + + + + + org.springframework.beans.ITestBean + + + + + + org.springframework.beans.ITestBean + global* + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTarget.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTarget.xml new file mode 100644 index 00000000000..21d1eedb408 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTarget.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + org.springframework.aop.framework.PrototypeTargetTests$TestBean + + + false + + + + testInterceptor + testBeanTarget + + + + + + + org.springframework.aop.framework.PrototypeTargetTests$TestBean + + + true + + + + testInterceptor + testBeanTarget + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTests.xml new file mode 100644 index 00000000000..33332243157 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/prototypeTests.xml @@ -0,0 +1,37 @@ + + + + + + + + + 10 + + + + 10 + + + + + + debugInterceptor,test + + + + debugInterceptor,prototypeTarget + false + + + + debugInterceptor,prototypeTarget + false + + true + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryBeanAutowiringTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryBeanAutowiringTests.xml new file mode 100644 index 00000000000..b732d7af434 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryBeanAutowiringTests.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryDoubleTargetSourceTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryDoubleTargetSourceTests.xml new file mode 100644 index 00000000000..0784675bb99 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryDoubleTargetSourceTests.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + Eve + + + + + + Adam + + + + + + + + + + + + org.springframework.beans.ITestBean + + countingBeforeAdvice,adamTargetSource + + + + + + + org.springframework.beans.ITestBean + + adam + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceNotLastTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceNotLastTests.xml new file mode 100644 index 00000000000..b1b19721255 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceNotLastTests.xml @@ -0,0 +1,34 @@ + + + + + + + + + + Adam + + + + + + + org.springframework.beans.ITestBean + + adam,countingBeforeAdvice + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceTests.xml new file mode 100644 index 00000000000..c5e48cbbbae --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTargetSourceTests.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + Adam + + + + + + + + + + + + + + + + + + + nopInterceptor,targetSource + + + + + + + + org.springframework.beans.ITestBean + nopInterceptor,unsupportedInterceptor + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTests.xml new file mode 100644 index 00000000000..09e68277731 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/proxyFactoryTests.xml @@ -0,0 +1,171 @@ + + + + + + + + custom + 666 + + + + + + org.springframework.beans.ITestBean + + debugInterceptor + + + + + + + org.springframework.beans.ITestBean + + + global*,test + + + + + + + org.springframework.beans.ITestBean + + + false + test + + + + + + org.springframework.beans.ITestBean + + + false + test + + + + true + + debugInterceptor + + + + true + false + test + + + + true + testCircleTarget1 + + + + custom + 666 + + + + + true + testCircleTarget2 + + + + custom + 666 + + + + + org.springframework.beans.ITestBean + pointcutForVoid + test + + + + + + + + + org.springframework.context.ApplicationListener + debugInterceptor,global*,target2 + + + + + + + + + + + + + + org.springframework.beans.ITestBean + false + + + prototypeLockMixinAdvisor + prototypeTestBean + + + + + + + + + + org.springframework.beans.ITestBean + org.springframework.aop.framework.Lockable + + + false + + + + prototypeLockMixinInterceptor + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/serializationTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/serializationTests.xml new file mode 100644 index 00000000000..aa12d497b12 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/serializationTests.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + serializableNopInterceptor + org.springframework.beans.Person + + + serializableSingleton + + + + + + serializablePrototype + + + + serializableNopInterceptor,prototypeTarget + org.springframework.beans.Person + false + + + + nopInterceptor + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/throwsAdvice.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/throwsAdvice.xml new file mode 100644 index 00000000000..5185ae39299 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/throwsAdvice.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + countingBeforeAdvice,nopInterceptor,throwsAdvice,target + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/withDependencyChecking.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/withDependencyChecking.xml new file mode 100644 index 00000000000..1994ce20287 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/withDependencyChecking.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java new file mode 100644 index 00000000000..bcb15ce6654 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Juergen Hoeller + * @since 06.04.2004 + */ +public class ConcurrencyThrottleInterceptorTests extends TestCase { + + protected static final Log logger = LogFactory.getLog(ConcurrencyThrottleInterceptorTests.class); + + public static final int NR_OF_THREADS = 100; + + public static final int NR_OF_ITERATIONS = 1000; + + + public void testSerializable() throws Exception { + DerivedTestBean tb = new DerivedTestBean(); + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setInterfaces(new Class[] {ITestBean.class}); + ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor(); + proxyFactory.addAdvice(cti); + proxyFactory.setTarget(tb); + ITestBean proxy = (ITestBean) proxyFactory.getProxy(); + proxy.getAge(); + + ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy); + Advised advised = (Advised) serializedProxy; + ConcurrencyThrottleInterceptor serializedCti = + (ConcurrencyThrottleInterceptor) advised.getAdvisors()[0].getAdvice(); + assertEquals(cti.getConcurrencyLimit(), serializedCti.getConcurrencyLimit()); + serializedProxy.getAge(); + } + + public void testMultipleThreadsWithLimit1() { + testMultipleThreads(1); + } + + public void testMultipleThreadsWithLimit10() { + testMultipleThreads(10); + } + + private void testMultipleThreads(int concurrencyLimit) { + TestBean tb = new TestBean(); + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setInterfaces(new Class[] {ITestBean.class}); + ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor(); + cti.setConcurrencyLimit(concurrencyLimit); + proxyFactory.addAdvice(cti); + proxyFactory.setTarget(tb); + ITestBean proxy = (ITestBean) proxyFactory.getProxy(); + + Thread[] threads = new Thread[NR_OF_THREADS]; + for (int i = 0; i < NR_OF_THREADS; i++) { + threads[i] = new ConcurrencyThread(proxy, null); + threads[i].start(); + } + for (int i = 0; i < NR_OF_THREADS / 10; i++) { + try { + Thread.sleep(5); + } + catch (InterruptedException ex) { + ex.printStackTrace(); + } + threads[i] = new ConcurrencyThread(proxy, + i % 2 == 0 ? (Throwable) new OutOfMemoryError() : (Throwable) new IllegalStateException()); + threads[i].start(); + } + for (int i = 0; i < NR_OF_THREADS; i++) { + try { + threads[i].join(); + } + catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + } + + + private static class ConcurrencyThread extends Thread { + + private ITestBean proxy; + private Throwable ex; + + public ConcurrencyThread(ITestBean proxy, Throwable ex) { + this.proxy = proxy; + this.ex = ex; + } + + public void run() { + if (this.ex != null) { + try { + this.proxy.exceptional(this.ex); + } + catch (RuntimeException ex) { + if (ex == this.ex) { + logger.debug("Expected exception thrown", ex); + } + else { + // should never happen + ex.printStackTrace(); + } + } + catch (Error err) { + if (err == this.ex) { + logger.debug("Expected exception thrown", err); + } + else { + // should never happen + ex.printStackTrace(); + } + } + catch (Throwable ex) { + // should never happen + ex.printStackTrace(); + } + } + else { + for (int i = 0; i < NR_OF_ITERATIONS; i++) { + this.proxy.getName(); + } + } + logger.debug("finished"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/CustomizableTraceInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/CustomizableTraceInterceptorTests.java new file mode 100644 index 00000000000..9ad18025fc8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/CustomizableTraceInterceptorTests.java @@ -0,0 +1,224 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.easymock.MockControl; + +import org.springframework.test.AssertThrows; + +/** + * @author Rob Harrop + * @author Rick Evans + * @author Juergen Hoeller + */ +public class CustomizableTraceInterceptorTests extends TestCase { + + public void testSetEmptyEnterMessage() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set empty enter message") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setEnterMessage(""); + } + }.runTest(); + } + + public void testSetEnterMessageWithReturnValuePlaceholder() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set enter message with return value placeholder") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setEnterMessage(CustomizableTraceInterceptor.PLACEHOLDER_RETURN_VALUE); + } + }.runTest(); + } + + public void testSetEnterMessageWithExceptionPlaceholder() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set enter message with exception placeholder") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setEnterMessage(CustomizableTraceInterceptor.PLACEHOLDER_EXCEPTION); + } + }.runTest(); + } + + public void testSetEnterMessageWithInvocationTimePlaceholder() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set enter message with invocation time placeholder") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setEnterMessage(CustomizableTraceInterceptor.PLACEHOLDER_INVOCATION_TIME); + } + }.runTest(); + } + + public void testSetEmptyExitMessage() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set empty exit message") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setExitMessage(""); + } + }.runTest(); + } + + public void testSetExitMessageWithExceptionPlaceholder() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set exit message with exception placeholder") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setExitMessage(CustomizableTraceInterceptor.PLACEHOLDER_EXCEPTION); + } + }.runTest(); + } + + public void testSetEmptyExceptionMessage() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set empty exception message") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setExceptionMessage(""); + } + }.runTest(); + } + + public void testSetExceptionMethodWithReturnValuePlaceholder() { + new AssertThrows(IllegalArgumentException.class, "Must not be able to set exception message with return value placeholder") { + public void test() throws Exception { + new CustomizableTraceInterceptor().setExceptionMessage(CustomizableTraceInterceptor.PLACEHOLDER_RETURN_VALUE); + } + }.runTest(); + } + + public void testSunnyDayPathLogsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + Method toString = String.class.getMethod("toString", new Class[]{}); + + log.isTraceEnabled(); + mockLog.setReturnValue(true); + methodInvocation.getMethod(); + mockMethodInvocation.setReturnValue(toString, 4); + methodInvocation.getThis(); + mockMethodInvocation.setReturnValue(this, 2); + log.trace("Some tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + methodInvocation.proceed(); + mockMethodInvocation.setReturnValue(null); + log.trace("Some more tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + CustomizableTraceInterceptor interceptor = new StubCustomizableTraceInterceptor(log); + interceptor.invoke(methodInvocation); + + mockLog.verify(); + mockMethodInvocation.verify(); + } + + public void testExceptionPathLogsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + Method toString = String.class.getMethod("toString", new Class[]{}); + + log.isTraceEnabled(); + mockLog.setReturnValue(true); + methodInvocation.getMethod(); + mockMethodInvocation.setReturnValue(toString, 4); + methodInvocation.getThis(); + mockMethodInvocation.setReturnValue(this, 2); + log.trace("Some tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + methodInvocation.proceed(); + IllegalArgumentException exception = new IllegalArgumentException(); + mockMethodInvocation.setThrowable(exception); + log.trace("Some more tracing output", exception); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + CustomizableTraceInterceptor interceptor = new StubCustomizableTraceInterceptor(log); + try { + interceptor.invoke(methodInvocation); + fail("Must have propagated the IllegalArgumentException."); + } + catch (IllegalArgumentException expected) { + } + + mockLog.verify(); + mockMethodInvocation.verify(); + } + + public void testSunnyDayPathLogsCorrectlyWithPrettyMuchAllPlaceholdersMatching() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + Method toString = String.class.getMethod("toString", new Class[0]); + Object[] arguments = new Object[]{"$ One \\$", new Long(2)}; + + log.isTraceEnabled(); + mockLog.setReturnValue(true); + methodInvocation.getMethod(); + mockMethodInvocation.setReturnValue(toString, 7); + methodInvocation.getThis(); + mockMethodInvocation.setReturnValue(this, 2); + methodInvocation.getArguments(); + mockMethodInvocation.setReturnValue(arguments, 2); + log.trace("Some tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + methodInvocation.proceed(); + mockMethodInvocation.setReturnValue("Hello!"); + log.trace("Some more tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + CustomizableTraceInterceptor interceptor = new StubCustomizableTraceInterceptor(log); + interceptor.setEnterMessage(new StringBuffer().append("Entering the '").append(CustomizableTraceInterceptor.PLACEHOLDER_METHOD_NAME).append("' method of the [").append(CustomizableTraceInterceptor.PLACEHOLDER_TARGET_CLASS_NAME).append("] class with the following args (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENTS).append(") and arg types (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENT_TYPES).append(").").toString()); + interceptor.setExitMessage(new StringBuffer().append("Exiting the '").append(CustomizableTraceInterceptor.PLACEHOLDER_METHOD_NAME).append("' method of the [").append(CustomizableTraceInterceptor.PLACEHOLDER_TARGET_CLASS_SHORT_NAME).append("] class with the following args (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENTS).append(") and arg types (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENT_TYPES).append("), returning '").append(CustomizableTraceInterceptor.PLACEHOLDER_RETURN_VALUE).append("' and taking '").append(CustomizableTraceInterceptor.PLACEHOLDER_INVOCATION_TIME).append("' this long.").toString()); + interceptor.invoke(methodInvocation); + + mockLog.verify(); + mockMethodInvocation.verify(); + } + + + private static class StubCustomizableTraceInterceptor extends CustomizableTraceInterceptor { + + private final Log log; + + public StubCustomizableTraceInterceptor(Log log) { + super.setUseDynamicLogger(false); + this.log = log; + } + + protected Log getLoggerForInvocation(MethodInvocation invocation) { + return this.log; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java new file mode 100644 index 00000000000..596602a17f8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.easymock.MockControl; + +/** + * Unit tests for the {@link DebugInterceptor} class. + * + * @author Rick Evans + */ +public final class DebugInterceptorTests extends TestCase { + + public void testSunnyDayPathLogsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + final Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + log.isTraceEnabled(); + mockLog.setReturnValue(true); + log.trace("Some tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + methodInvocation.proceed(); + mockMethodInvocation.setReturnValue(null); + log.trace("Some more tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + DebugInterceptor interceptor = new StubDebugInterceptor(log); + interceptor.invoke(methodInvocation); + checkCallCountTotal(interceptor); + + mockLog.verify(); + mockMethodInvocation.verify(); + } + + public void testExceptionPathStillLogsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + final Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + final MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + log.isTraceEnabled(); + mockLog.setReturnValue(true); + log.trace("Some tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + methodInvocation.proceed(); + IllegalArgumentException exception = new IllegalArgumentException(); + mockMethodInvocation.setThrowable(exception); + log.trace("Some more tracing output", exception); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + DebugInterceptor interceptor = new StubDebugInterceptor(log); + try { + interceptor.invoke(methodInvocation); + fail("Must have propagated the IllegalArgumentException."); + } catch (IllegalArgumentException expected) { + } + checkCallCountTotal(interceptor); + + mockLog.verify(); + mockMethodInvocation.verify(); + } + + private void checkCallCountTotal(DebugInterceptor interceptor) { + assertEquals("Intercepted call count not being incremented correctly", 1, interceptor.getCount()); + } + + + private static final class StubDebugInterceptor extends DebugInterceptor { + + private final Log log; + + + public StubDebugInterceptor(Log log) { + super(true); + this.log = log; + } + + + protected Log getLoggerForInvocation(MethodInvocation invocation) { + return log; + } + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java new file mode 100644 index 00000000000..f635917cfda --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.NamedBean; + +/** + * + * @author Rod Johnson + * + */ +public class ExposeBeanNameAdvisorsTests extends TestCase { + + private class RequiresBeanNameBoundTestBean extends TestBean { + private final String beanName; + + public RequiresBeanNameBoundTestBean(String beanName) { + this.beanName = beanName; + } + + public int getAge() { + assertEquals(beanName, ExposeBeanNameAdvisors.getBeanName()); + return super.getAge(); + } + } + + public void testNoIntroduction() { + String beanName = "foo"; + TestBean target = new RequiresBeanNameBoundTestBean(beanName); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR); + pf.addAdvisor(ExposeBeanNameAdvisors.createAdvisorWithoutIntroduction(beanName)); + ITestBean proxy = (ITestBean) pf.getProxy(); + + assertFalse("No introduction", proxy instanceof NamedBean); + // Requires binding + proxy.getAge(); + } + + public void testWithIntroduction() { + String beanName = "foo"; + TestBean target = new RequiresBeanNameBoundTestBean(beanName); + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR); + pf.addAdvisor(ExposeBeanNameAdvisors.createAdvisorIntroducingNamedBean(beanName)); + ITestBean proxy = (ITestBean) pf.getProxy(); + + assertTrue("Introduction was made", proxy instanceof NamedBean); + // Requires binding + proxy.getAge(); + + NamedBean nb = (NamedBean) proxy; + assertEquals("Name returned correctly", beanName, nb.getBeanName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java new file mode 100644 index 00000000000..ca0f294a4fa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Non-XML tests are in AbstractAopProxyTests + * @author Rod Johnson + */ +public class ExposeInvocationInterceptorTests extends TestCase { + + public void testXmlConfig() { + ClassPathXmlApplicationContext xac = new ClassPathXmlApplicationContext("org/springframework/aop/interceptor/exposeInvocation.xml"); + ITestBean tb = (ITestBean) xac.getBean("proxy"); + String name= "tony"; + tb.setName(name); + // Fires context checks + assertEquals(name, tb.getName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/NopInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/NopInterceptor.java new file mode 100644 index 00000000000..6bbbc4ff174 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/NopInterceptor.java @@ -0,0 +1,58 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * Trivial interceptor that can be introduced in a chain to display it. + * + * @author Rod Johnson + */ +public class NopInterceptor implements MethodInterceptor { + + private int count; + + /** + * @see org.aopalliance.intercept.MethodInterceptor#invoke(MethodInvocation) + */ + public Object invoke(MethodInvocation invocation) throws Throwable { + increment(); + return invocation.proceed(); + } + + public int getCount() { + return this.count; + } + + protected void increment() { + ++count; + } + + public boolean equals(Object other) { + if (!(other instanceof NopInterceptor)) { + return false; + } + if (this == other) { + return true; + } + return this.count == ((NopInterceptor) other).count; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/PerformanceMonitorInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/PerformanceMonitorInterceptorTests.java new file mode 100644 index 00000000000..352aa345c48 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/PerformanceMonitorInterceptorTests.java @@ -0,0 +1,104 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.easymock.MockControl; + +/** + * @author Rob Harrop + * @author Rick Evans + */ +public class PerformanceMonitorInterceptorTests extends TestCase { + + public void testSuffixAndPrefixAssignment() { + PerformanceMonitorInterceptor interceptor = new PerformanceMonitorInterceptor(); + + assertNotNull(interceptor.getPrefix()); + assertNotNull(interceptor.getSuffix()); + + interceptor.setPrefix(null); + interceptor.setSuffix(null); + + assertNotNull(interceptor.getPrefix()); + assertNotNull(interceptor.getSuffix()); + } + + public void testSunnyDayPathLogsPerformanceMetricsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + Method toString = String.class.getMethod("toString", new Class[0]); + + methodInvocation.getMethod(); + mockMethodInvocation.setReturnValue(toString); + methodInvocation.proceed(); + mockMethodInvocation.setReturnValue(null); + log.trace("Some performance metric"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + PerformanceMonitorInterceptor interceptor = new PerformanceMonitorInterceptor(true); + interceptor.invokeUnderTrace(methodInvocation, log); + + mockLog.verify(); + mockMethodInvocation.verify(); + } + + public void testExceptionPathStillLogsPerformanceMetricsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + Method toString = String.class.getMethod("toString", new Class[0]); + + methodInvocation.getMethod(); + mockMethodInvocation.setReturnValue(toString); + methodInvocation.proceed(); + mockMethodInvocation.setThrowable(new IllegalArgumentException()); + log.trace("Some performance metric"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + PerformanceMonitorInterceptor interceptor = new PerformanceMonitorInterceptor(true); + try { + interceptor.invokeUnderTrace(methodInvocation, log); + fail("Must have propagated the IllegalArgumentException."); + } + catch (IllegalArgumentException expected) { + } + + mockLog.verify(); + mockMethodInvocation.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SerializableNopInterceptor.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SerializableNopInterceptor.java new file mode 100644 index 00000000000..328f6cf9b2f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SerializableNopInterceptor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import java.io.Serializable; + + +/** + * Subclass of NopInterceptor that is serializable and + * can be used to test proxy serialization. + * + * @author Rod Johnson + */ +public class SerializableNopInterceptor extends NopInterceptor implements Serializable { + + /** + * We must override this field and the related methods as + * otherwise count won't be serialized from the non-serializable + * NopInterceptor superclass. + */ + private int count; + + public int getCount() { + return this.count; + } + + protected void increment() { + ++count; + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SideEffectBean.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SideEffectBean.java new file mode 100644 index 00000000000..ee6c95a658b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SideEffectBean.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +/** + * Bean that changes state on a business invocation, so that + * we can check whether it's been invoked + * @author Rod Johnson + */ +public class SideEffectBean { + + private int count; + + public void setCount(int count) { + this.count = count; + } + + public int getCount() { + return this.count; + } + + public void doWork() { + ++count; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java new file mode 100644 index 00000000000..8a963bfc65e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.easymock.MockControl; + +import java.lang.reflect.Method; + +/** + * Unit tests for the {@link SimpleTraceInterceptor} class. + * + * @author Rick Evans + */ +public final class SimpleTraceInterceptorTests extends TestCase { + + public void testSunnyDayPathLogsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + Method toString = String.class.getMethod("toString", new Class[]{}); + + methodInvocation.getMethod(); + mockMethodInvocation.setReturnValue(toString); + methodInvocation.getThis(); + mockMethodInvocation.setReturnValue(this); + log.trace("Some tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + methodInvocation.proceed(); + mockMethodInvocation.setReturnValue(null); + log.trace("Some more tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + SimpleTraceInterceptor interceptor = new SimpleTraceInterceptor(true); + interceptor.invokeUnderTrace(methodInvocation, log); + + mockLog.verify(); + mockMethodInvocation.verify(); + } + + public void testExceptionPathStillLogsCorrectly() throws Throwable { + MockControl mockLog = MockControl.createControl(Log.class); + final Log log = (Log) mockLog.getMock(); + + MockControl mockMethodInvocation = MockControl.createControl(MethodInvocation.class); + final MethodInvocation methodInvocation = (MethodInvocation) mockMethodInvocation.getMock(); + + Method toString = String.class.getMethod("toString", new Class[]{}); + + methodInvocation.getMethod(); + mockMethodInvocation.setReturnValue(toString); + methodInvocation.getThis(); + mockMethodInvocation.setReturnValue(this); + log.trace("Some tracing output"); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + methodInvocation.proceed(); + IllegalArgumentException exception = new IllegalArgumentException(); + mockMethodInvocation.setThrowable(exception); + log.trace("Some more tracing output", exception); + mockLog.setMatcher(MockControl.ALWAYS_MATCHER); + mockLog.setVoidCallable(); + + mockMethodInvocation.replay(); + mockLog.replay(); + + final SimpleTraceInterceptor interceptor = new SimpleTraceInterceptor(true); + + try { + interceptor.invokeUnderTrace(methodInvocation, log); + fail("Must have propagated the IllegalArgumentException."); + } catch (IllegalArgumentException expected) { + } + + mockLog.verify(); + mockMethodInvocation.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/exposeInvocation.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/exposeInvocation.xml new file mode 100644 index 00000000000..a44795f043a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/interceptor/exposeInvocation.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + org.springframework.aop.interceptor.ExposeInvocationInterceptor + + INSTANCE + + + + + + + + + + exposeInvocation,countingBeforeAdvice,nopInterceptor + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/DefaultScopedObjectTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/DefaultScopedObjectTests.java new file mode 100644 index 00000000000..c05fa15dc97 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/DefaultScopedObjectTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.scope; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link DefaultScopedObject} class. + * + * @author Rick Evans + */ +public final class DefaultScopedObjectTests extends TestCase { + + private static final String GOOD_BEAN_NAME = "foo"; + + + public void testCtorWithNullBeanFactory() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new DefaultScopedObject(null, GOOD_BEAN_NAME); + } + }.runTest(); + } + + public void testCtorWithNullTargetBeanName() throws Exception { + testBadTargetBeanName(null); + } + + public void testCtorWithEmptyTargetBeanName() throws Exception { + testBadTargetBeanName(""); + } + + public void testCtorWithJustWhitespacedTargetBeanName() throws Exception { + testBadTargetBeanName(" "); + } + + + private static void testBadTargetBeanName(final String badTargetBeanName) { + MockControl mock = MockControl.createControl(ConfigurableBeanFactory.class); + final ConfigurableBeanFactory factory = (ConfigurableBeanFactory) mock.getMock(); + mock.replay(); + + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new DefaultScopedObject(factory, badTargetBeanName); + } + }.runTest(); + + mock.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java new file mode 100644 index 00000000000..925ddcc3f7a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.scope; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Mark Fisher + */ +public class ScopedProxyAutowireTests extends TestCase { + + public void testScopedProxyInheritsAutowireCandidateFalse() { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("scopedAutowireFalse.xml", getClass())); + TestBean autowired = (TestBean) bf.getBean("autowired"); + TestBean unscoped = (TestBean) bf.getBean("unscoped"); + assertSame(unscoped, autowired.getChild()); + } + + public void testScopedProxyReplacesAutowireCandidateTrue() { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("scopedAutowireTrue.xml", getClass())); + TestBean autowired = (TestBean) bf.getBean("autowired"); + TestBean scoped = (TestBean) bf.getBean("scoped"); + assertSame(scoped, autowired.getChild()); + } + + + public static class TestBean { + + private TestBean child; + + public void setChild(TestBean child) { + this.child = child; + } + + public TestBean getChild() { + return this.child; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyTests.java new file mode 100644 index 00000000000..54515872534 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/ScopedProxyTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.scope; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.SimpleMapScope; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class ScopedProxyTests extends TestCase { + + /* SPR-2108 */ + public void testProxyAssignable() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("scopedMap.xml", getClass())); + Object baseMap = bf.getBean("singletonMap"); + assertTrue(baseMap instanceof Map); + } + + public void testSimpleProxy() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("scopedMap.xml", getClass())); + Object simpleMap = bf.getBean("simpleMap"); + assertTrue(simpleMap instanceof Map); + assertTrue(simpleMap instanceof HashMap); + } + + public void testScopedOverride() throws Exception { + GenericApplicationContext ctx = new GenericApplicationContext(); + new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(new ClassPathResource("scopedOverride.xml", getClass())); + SimpleMapScope scope = new SimpleMapScope(); + ctx.getBeanFactory().registerScope("request", scope); + ctx.refresh(); + + ITestBean bean = (ITestBean) ctx.getBean("testBean"); + assertEquals("male", bean.getName()); + assertEquals(99, bean.getAge()); + + assertTrue(scope.getMap().containsKey("scopedTarget.testBean")); + assertEquals(TestBean.class, scope.getMap().get("scopedTarget.testBean").getClass()); + } + + public void testJdkScopedProxy() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("scopedTestBean.xml", getClass())); + SimpleMapScope scope = new SimpleMapScope(); + bf.registerScope("request", scope); + + ITestBean bean = (ITestBean) bf.getBean("testBean"); + assertNotNull(bean); + assertTrue(AopUtils.isJdkDynamicProxy(bean)); + assertTrue(bean instanceof ScopedObject); + ScopedObject scoped = (ScopedObject) bean; + assertEquals(TestBean.class, scoped.getTargetObject().getClass()); + + assertTrue(scope.getMap().containsKey("testBeanTarget")); + assertEquals(TestBean.class, scope.getMap().get("testBeanTarget").getClass()); + } + + public void testCglibScopedProxy() { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("scopedList.xml", getClass())); + SimpleMapScope scope = new SimpleMapScope(); + bf.registerScope("request", scope); + + TestBean tb = (TestBean) bf.getBean("testBean"); + assertTrue(AopUtils.isCglibProxy(tb.getFriends())); + assertTrue(tb.getFriends() instanceof ScopedObject); + ScopedObject scoped = (ScopedObject) tb.getFriends(); + assertEquals(ArrayList.class, scoped.getTargetObject().getClass()); + + assertTrue(scope.getMap().containsKey("scopedTarget.scopedList")); + assertEquals(ArrayList.class, scope.getMap().get("scopedTarget.scopedList").getClass()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireFalse.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireFalse.xml new file mode 100644 index 00000000000..feecab3e9cf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireFalse.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireTrue.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireTrue.xml new file mode 100644 index 00000000000..445b50d064b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedAutowireTrue.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedList.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedList.xml new file mode 100644 index 00000000000..5ff806cb6f0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedList.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedMap.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedMap.xml new file mode 100644 index 00000000000..0c69a3f9cc1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedMap.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedOverride.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedOverride.xml new file mode 100644 index 00000000000..63f19fe2637 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedOverride.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedTestBean.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedTestBean.xml new file mode 100644 index 00000000000..0560e78b721 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/scope/scopedTestBean.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java new file mode 100644 index 00000000000..75d4af6d2e4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rod Johnson + * @author Dmitriy Kopylenko + */ +public abstract class AbstractRegexpMethodPointcutTests extends TestCase { + + private AbstractRegexpMethodPointcut rpc; + + protected void setUp() { + rpc = getRegexpMethodPointcut(); + } + + protected abstract AbstractRegexpMethodPointcut getRegexpMethodPointcut(); + + public void testNoPatternSupplied() throws Exception { + noPatternSuppliedTests(rpc); + } + + public void testSerializationWithNoPatternSupplied() throws Exception { + rpc = (AbstractRegexpMethodPointcut) SerializationTestUtils.serializeAndDeserialize(rpc); + noPatternSuppliedTests(rpc); + } + + protected void noPatternSuppliedTests(AbstractRegexpMethodPointcut rpc) throws Exception { + assertFalse(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class)); + assertFalse(rpc.matches(Object.class.getMethod("wait", (Class[]) null), Object.class)); + assertEquals(0, rpc.getPatterns().length); + } + + public void testExactMatch() throws Exception { + rpc.setPattern("java.lang.Object.hashCode"); + exactMatchTests(rpc); + rpc = (AbstractRegexpMethodPointcut) SerializationTestUtils.serializeAndDeserialize(rpc); + exactMatchTests(rpc); + } + + protected void exactMatchTests(AbstractRegexpMethodPointcut rpc) throws Exception { + // assumes rpc.setPattern("java.lang.Object.hashCode"); + assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class)); + assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), Object.class)); + assertFalse(rpc.matches(Object.class.getMethod("wait", (Class[]) null), Object.class)); + } + + public void testSpecificMatch() throws Exception { + rpc.setPattern("java.lang.String.hashCode"); + assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class)); + assertFalse(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), Object.class)); + } + + public void testWildcard() throws Exception { + rpc.setPattern(".*Object.hashCode"); + assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), Object.class)); + assertFalse(rpc.matches(Object.class.getMethod("wait", (Class[]) null), Object.class)); + } + + public void testWildcardForOneClass() throws Exception { + rpc.setPattern("java.lang.Object.*"); + assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class)); + assertTrue(rpc.matches(Object.class.getMethod("wait", (Class[]) null), String.class)); + } + + public void testMatchesObjectClass() throws Exception { + rpc.setPattern("java.lang.Object.*"); + assertTrue(rpc.matches(Exception.class.getMethod("hashCode", (Class[]) null), ServletException.class)); + // Doesn't match a method from Throwable + assertFalse(rpc.matches(Exception.class.getMethod("getMessage", (Class[]) null), Exception.class)); + } + + public void testWithExclusion() throws Exception { + this.rpc.setPattern(".*get.*"); + this.rpc.setExcludedPattern(".*Age.*"); + assertTrue(this.rpc.matches(TestBean.class.getMethod("getName", null), TestBean.class)); + assertFalse(this.rpc.matches(TestBean.class.getMethod("getAge", null), TestBean.class)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/AopUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/AopUtilsTests.java new file mode 100644 index 00000000000..f8130f465d1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/AopUtilsTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.aop.ClassFilter; +import org.springframework.aop.MethodMatcher; +import org.springframework.aop.Pointcut; +import org.springframework.aop.interceptor.ExposeInvocationInterceptor; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.target.EmptyTargetSource; +import org.springframework.beans.TestBean; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rod Johnson + */ +public class AopUtilsTests extends TestCase { + + public void testPointcutCanNeverApply() { + class TestPointcut extends StaticMethodMatcherPointcut { + public boolean matches(Method method, Class clazzy) { + return false; + } + } + + Pointcut no = new TestPointcut(); + assertFalse(AopUtils.canApply(no, Object.class)); + } + + public void testPointcutAlwaysApplies() { + assertTrue(AopUtils.canApply(new DefaultPointcutAdvisor(new NopInterceptor()), Object.class)); + assertTrue(AopUtils.canApply(new DefaultPointcutAdvisor(new NopInterceptor()), TestBean.class)); + } + + public void testPointcutAppliesToOneMethodOnObject() { + class TestPointcut extends StaticMethodMatcherPointcut { + public boolean matches(Method method, Class clazz) { + return method.getName().equals("hashCode"); + } + } + + Pointcut pc = new TestPointcut(); + + // will return true if we're not proxying interfaces + assertTrue(AopUtils.canApply(pc, Object.class)); + } + + /** + * Test that when we serialize and deserialize various canonical instances + * of AOP classes, they return the same instance, not a new instance + * that's subverted the singleton construction limitation. + */ + public void testCanonicalFrameworkClassesStillCanonicalOnDeserialization() throws Exception { + assertSame(MethodMatcher.TRUE, SerializationTestUtils.serializeAndDeserialize(MethodMatcher.TRUE)); + assertSame(ClassFilter.TRUE, SerializationTestUtils.serializeAndDeserialize(ClassFilter.TRUE)); + assertSame(Pointcut.TRUE, SerializationTestUtils.serializeAndDeserialize(Pointcut.TRUE)); + assertSame(EmptyTargetSource.INSTANCE, SerializationTestUtils.serializeAndDeserialize(EmptyTargetSource.INSTANCE)); + assertSame(Pointcuts.SETTERS, SerializationTestUtils.serializeAndDeserialize(Pointcuts.SETTERS)); + assertSame(Pointcuts.GETTERS, SerializationTestUtils.serializeAndDeserialize(Pointcuts.GETTERS)); + assertSame(ExposeInvocationInterceptor.INSTANCE, + SerializationTestUtils.serializeAndDeserialize(ExposeInvocationInterceptor.INSTANCE)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ClassFiltersTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ClassFiltersTests.java new file mode 100644 index 00000000000..a6d61f85439 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ClassFiltersTests.java @@ -0,0 +1,57 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import junit.framework.TestCase; + +import org.springframework.aop.ClassFilter; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.core.NestedRuntimeException; + +/** + * @author Rod Johnson + */ +public class ClassFiltersTests extends TestCase { + + private ClassFilter exceptionFilter = new RootClassFilter(Exception.class); + + private ClassFilter itbFilter = new RootClassFilter(ITestBean.class); + + private ClassFilter hasRootCauseFilter = new RootClassFilter(NestedRuntimeException.class); + + public void testUnion() { + assertTrue(exceptionFilter.matches(RuntimeException.class)); + assertFalse(exceptionFilter.matches(TestBean.class)); + assertFalse(itbFilter.matches(Exception.class)); + assertTrue(itbFilter.matches(TestBean.class)); + ClassFilter union = ClassFilters.union(exceptionFilter, itbFilter); + assertTrue(union.matches(RuntimeException.class)); + assertTrue(union.matches(TestBean.class)); + } + + public void testIntersection() { + assertTrue(exceptionFilter.matches(RuntimeException.class)); + assertTrue(hasRootCauseFilter.matches(NestedRuntimeException.class)); + ClassFilter intersection = ClassFilters.intersection(exceptionFilter, hasRootCauseFilter); + assertFalse(intersection.matches(RuntimeException.class)); + assertFalse(intersection.matches(TestBean.class)); + assertTrue(intersection.matches(NestedRuntimeException.class)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java new file mode 100644 index 00000000000..d73d642bcae --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java @@ -0,0 +1,145 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.aop.ClassFilter; +import org.springframework.aop.MethodMatcher; +import org.springframework.aop.Pointcut; +import org.springframework.beans.TestBean; +import org.springframework.core.NestedRuntimeException; + +/** + * @author Rod Johnson + */ +public class ComposablePointcutTests extends TestCase { + + public static MethodMatcher GETTER_METHOD_MATCHER = new StaticMethodMatcher() { + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith("get"); + } + }; + + public static MethodMatcher GET_AGE_METHOD_MATCHER = new StaticMethodMatcher() { + public boolean matches(Method m, Class targetClass) { + return m.getName().equals("getAge"); + } + }; + + public static MethodMatcher ABSQUATULATE_METHOD_MATCHER = new StaticMethodMatcher() { + public boolean matches(Method m, Class targetClass) { + return m.getName().equals("absquatulate"); + } + }; + + public static MethodMatcher SETTER_METHOD_MATCHER = new StaticMethodMatcher() { + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith("set"); + } + }; + + public void testMatchAll() throws NoSuchMethodException { + Pointcut pc = new ComposablePointcut(); + assertTrue(pc.getClassFilter().matches(Object.class)); + assertTrue(pc.getMethodMatcher().matches(Object.class.getMethod("hashCode", (Class[]) null), Exception.class)); + } + + public void testFilterByClass() throws NoSuchMethodException { + ComposablePointcut pc = new ComposablePointcut(); + + assertTrue(pc.getClassFilter().matches(Object.class)); + + ClassFilter cf = new RootClassFilter(Exception.class); + pc.intersection(cf); + assertFalse(pc.getClassFilter().matches(Object.class)); + assertTrue(pc.getClassFilter().matches(Exception.class)); + pc.intersection(new RootClassFilter(NestedRuntimeException.class)); + assertFalse(pc.getClassFilter().matches(Exception.class)); + assertTrue(pc.getClassFilter().matches(NestedRuntimeException.class)); + assertFalse(pc.getClassFilter().matches(String.class)); + pc.union(new RootClassFilter(String.class)); + assertFalse(pc.getClassFilter().matches(Exception.class)); + assertTrue(pc.getClassFilter().matches(String.class)); + assertTrue(pc.getClassFilter().matches(NestedRuntimeException.class)); + } + + public void testUnionMethodMatcher() { + // Matches the getAge() method in any class + ComposablePointcut pc = new ComposablePointcut(ClassFilter.TRUE, GET_AGE_METHOD_MATCHER); + assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null)); + + pc.union(GETTER_METHOD_MATCHER); + // Should now match all getter methods + assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null)); + assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null)); + + pc.union(ABSQUATULATE_METHOD_MATCHER); + // Should now match absquatulate() as well + assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null)); + assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null)); + // But it doesn't match everything + assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_SET_AGE, TestBean.class, null)); + } + + public void testIntersectionMethodMatcher() { + ComposablePointcut pc = new ComposablePointcut(); + assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class)); + assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class)); + assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class)); + pc.intersection(GETTER_METHOD_MATCHER); + assertFalse(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class)); + assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class)); + assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class)); + pc.intersection(GET_AGE_METHOD_MATCHER); + // Use the Pointcuts matches method + assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null)); + } + + public void testEqualsAndHashCode() throws Exception { + ComposablePointcut pc1 = new ComposablePointcut(); + ComposablePointcut pc2 = new ComposablePointcut(); + + assertEquals(pc1, pc2); + assertEquals(pc1.hashCode(), pc2.hashCode()); + + pc1.intersection(GETTER_METHOD_MATCHER); + + assertFalse(pc1.equals(pc2)); + assertFalse(pc1.hashCode() == pc2.hashCode()); + + pc2.intersection(GETTER_METHOD_MATCHER); + + assertEquals(pc1, pc2); + assertEquals(pc1.hashCode(), pc2.hashCode()); + + pc1.union(GET_AGE_METHOD_MATCHER); + pc2.union(GET_AGE_METHOD_MATCHER); + + assertEquals(pc1, pc2); + assertEquals(pc1.hashCode(), pc2.hashCode()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java new file mode 100644 index 00000000000..100cab23725 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import junit.framework.TestCase; + +import org.springframework.aop.Pointcut; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; + +/** + * + * @author Rod Johnson + */ +public class ControlFlowPointcutTests extends TestCase { + + public ControlFlowPointcutTests(String s) { + super(s); + } + + public void testMatches() { + TestBean target = new TestBean(); + target.setAge(27); + NopInterceptor nop = new NopInterceptor(); + ControlFlowPointcut cflow = new ControlFlowPointcut(One.class, "getAge"); + ProxyFactory pf = new ProxyFactory(target); + ITestBean proxied = (ITestBean) pf.getProxy(); + pf.addAdvisor(new DefaultPointcutAdvisor(cflow, nop)); + + // Not advised, not under One + assertEquals(target.getAge(), proxied.getAge()); + assertEquals(0, nop.getCount()); + + // Will be advised + assertEquals(target.getAge(), new One().getAge(proxied)); + assertEquals(1, nop.getCount()); + + // Won't be advised + assertEquals(target.getAge(), new One().nomatch(proxied)); + assertEquals(1, nop.getCount()); + assertEquals(3, cflow.getEvaluations()); + } + + /** + * Check that we can use a cflow pointcut only in conjunction with + * a static pointcut: e.g. all setter methods that are invoked under + * a particular class. This greatly reduces the number of calls + * to the cflow pointcut, meaning that it's not so prohibitively + * expensive. + */ + public void testSelectiveApplication() { + TestBean target = new TestBean(); + target.setAge(27); + NopInterceptor nop = new NopInterceptor(); + ControlFlowPointcut cflow = new ControlFlowPointcut(One.class); + Pointcut settersUnderOne = Pointcuts.intersection(Pointcuts.SETTERS, cflow); + ProxyFactory pf = new ProxyFactory(target); + ITestBean proxied = (ITestBean) pf.getProxy(); + pf.addAdvisor(new DefaultPointcutAdvisor(settersUnderOne, nop)); + + // Not advised, not under One + target.setAge(16); + assertEquals(0, nop.getCount()); + + // Not advised; under One but not a setter + assertEquals(16, new One().getAge(proxied)); + assertEquals(0, nop.getCount()); + + // Won't be advised + new One().set(proxied); + assertEquals(1, nop.getCount()); + + // We saved most evaluations + assertEquals(1, cflow.getEvaluations()); + } + + public void testEqualsAndHashCode() throws Exception { + assertEquals(new ControlFlowPointcut(One.class), new ControlFlowPointcut(One.class)); + assertEquals(new ControlFlowPointcut(One.class, "getAge"), new ControlFlowPointcut(One.class, "getAge")); + assertFalse(new ControlFlowPointcut(One.class, "getAge").equals(new ControlFlowPointcut(One.class))); + assertEquals(new ControlFlowPointcut(One.class).hashCode(), new ControlFlowPointcut(One.class).hashCode()); + assertEquals(new ControlFlowPointcut(One.class, "getAge").hashCode(), new ControlFlowPointcut(One.class, "getAge").hashCode()); + assertFalse(new ControlFlowPointcut(One.class, "getAge").hashCode() == new ControlFlowPointcut(One.class).hashCode()); + } + + public class One { + int getAge(ITestBean proxied) { + return proxied.getAge(); + } + int nomatch(ITestBean proxied) { + return proxied.getAge(); + } + void set(ITestBean proxied) { + proxied.setAge(5); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java new file mode 100644 index 00000000000..8b042bf6426 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java @@ -0,0 +1,318 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import java.io.Serializable; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInterceptor; +import org.easymock.MockControl; + +import org.springframework.aop.IntroductionAdvisor; +import org.springframework.aop.IntroductionInterceptor; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.framework.TimeStamped; +import org.springframework.aop.interceptor.SerializableNopInterceptor; +import org.springframework.beans.INestedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.NestedTestBean; +import org.springframework.beans.Person; +import org.springframework.beans.SerializablePerson; +import org.springframework.beans.TestBean; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rod Johnson + * @since 13.05.2003 + */ +public class DelegatingIntroductionInterceptorTests extends TestCase { + + public void testNullTarget() throws Exception { + try { + IntroductionInterceptor ii = new DelegatingIntroductionInterceptor(null); + fail("Shouldn't accept null target"); + } + catch (IllegalArgumentException ex) { + // OK + } + } + + public void testIntroductionInterceptorWithDelegation() throws Exception { + TestBean raw = new TestBean(); + assertTrue(! (raw instanceof TimeStamped)); + ProxyFactory factory = new ProxyFactory(raw); + + MockControl tsControl = MockControl.createControl(TimeStamped.class); + TimeStamped ts = (TimeStamped) tsControl.getMock(); + ts.getTimeStamp(); + long timestamp = 111L; + tsControl.setReturnValue(timestamp, 1); + tsControl.replay(); + + factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts))); + + TimeStamped tsp = (TimeStamped) factory.getProxy(); + assertTrue(tsp.getTimeStamp() == timestamp); + + tsControl.verify(); + } + + public void testIntroductionInterceptorWithInterfaceHierarchy() throws Exception { + TestBean raw = new TestBean(); + assertTrue(! (raw instanceof SubTimeStamped)); + ProxyFactory factory = new ProxyFactory(raw); + + MockControl tsControl = MockControl.createControl(SubTimeStamped.class); + SubTimeStamped ts = (SubTimeStamped) tsControl.getMock(); + ts.getTimeStamp(); + long timestamp = 111L; + tsControl.setReturnValue(timestamp, 1); + tsControl.replay(); + + factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), SubTimeStamped.class)); + + SubTimeStamped tsp = (SubTimeStamped) factory.getProxy(); + assertTrue(tsp.getTimeStamp() == timestamp); + + tsControl.verify(); + } + + public void testIntroductionInterceptorWithSuperInterface() throws Exception { + TestBean raw = new TestBean(); + assertTrue(! (raw instanceof TimeStamped)); + ProxyFactory factory = new ProxyFactory(raw); + + MockControl tsControl = MockControl.createControl(SubTimeStamped.class); + SubTimeStamped ts = (SubTimeStamped) tsControl.getMock(); + ts.getTimeStamp(); + long timestamp = 111L; + tsControl.setReturnValue(timestamp, 1); + tsControl.replay(); + + factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), TimeStamped.class)); + + TimeStamped tsp = (TimeStamped) factory.getProxy(); + assertTrue(!(tsp instanceof SubTimeStamped)); + assertTrue(tsp.getTimeStamp() == timestamp); + + tsControl.verify(); + } + + public void testAutomaticInterfaceRecognitionInDelegate() throws Exception { + final long t = 1001L; + class Tester implements TimeStamped, ITester { + public void foo() throws Exception { + } + public long getTimeStamp() { + return t; + } + } + + DelegatingIntroductionInterceptor ii = new DelegatingIntroductionInterceptor(new Tester()); + + TestBean target = new TestBean(); + + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii)); + + //assertTrue(Arrays.binarySearch(pf.getProxiedInterfaces(), TimeStamped.class) != -1); + TimeStamped ts = (TimeStamped) pf.getProxy(); + + assertTrue(ts.getTimeStamp() == t); + ((ITester) ts).foo(); + + ((ITestBean) ts).getAge(); + } + + + public void testAutomaticInterfaceRecognitionInSubclass() throws Exception { + final long t = 1001L; + class TestII extends DelegatingIntroductionInterceptor implements TimeStamped, ITester { + public void foo() throws Exception { + } + public long getTimeStamp() { + return t; + } + } + + DelegatingIntroductionInterceptor ii = new TestII(); + + TestBean target = new TestBean(); + + ProxyFactory pf = new ProxyFactory(target); + IntroductionAdvisor ia = new DefaultIntroductionAdvisor(ii); + assertTrue(ia.isPerInstance()); + pf.addAdvisor(0, ia); + + //assertTrue(Arrays.binarySearch(pf.getProxiedInterfaces(), TimeStamped.class) != -1); + TimeStamped ts = (TimeStamped) pf.getProxy(); + + assertTrue(ts instanceof TimeStamped); + // Shoulnd't proxy framework interfaces + assertTrue(!(ts instanceof MethodInterceptor)); + assertTrue(!(ts instanceof IntroductionInterceptor)); + + assertTrue(ts.getTimeStamp() == t); + ((ITester) ts).foo(); + ((ITestBean) ts).getAge(); + + // Test removal + ii.suppressInterface(TimeStamped.class); + // Note that we need to construct a new proxy factory, + // or suppress the interface on the proxy factory + pf = new ProxyFactory(target); + pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii)); + Object o = pf.getProxy(); + assertTrue(!(o instanceof TimeStamped)); + } + + public void testIntroductionInterceptorDoesntReplaceToString() throws Exception { + TestBean raw = new TestBean(); + assertTrue(! (raw instanceof TimeStamped)); + ProxyFactory factory = new ProxyFactory(raw); + + TimeStamped ts = new SerializableTimeStamped(0); + + factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts) { + public String toString() { + throw new UnsupportedOperationException("Shouldn't be invoked"); + } + })); + + TimeStamped tsp = (TimeStamped) factory.getProxy(); + assertEquals(0, tsp.getTimeStamp()); + + assertEquals(raw.toString(), tsp.toString()); + } + + public void testDelegateReturnsThisIsMassagedToReturnProxy() { + NestedTestBean target = new NestedTestBean(); + String company = "Interface21"; + target.setCompany(company); + TestBean delegate = new TestBean() { + public ITestBean getSpouse() { + return this; + } + }; + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(new DelegatingIntroductionInterceptor(delegate)); + INestedTestBean proxy = (INestedTestBean) pf.getProxy(); + + assertEquals(company, proxy.getCompany()); + ITestBean introduction = (ITestBean) proxy; + assertSame("Introduced method returning delegate returns proxy", introduction, introduction.getSpouse()); + assertTrue("Introduced method returning delegate returns proxy", AopUtils.isAopProxy(introduction.getSpouse())); + } + + public void testSerializableDelegatingIntroductionInterceptorSerializable() throws Exception { + SerializablePerson serializableTarget = new SerializablePerson(); + String name = "Tony"; + serializableTarget.setName("Tony"); + + ProxyFactory factory = new ProxyFactory(serializableTarget); + factory.addInterface(Person.class); + long time = 1000; + TimeStamped ts = new SerializableTimeStamped(time); + + factory.addAdvisor(new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts))); + factory.addAdvice(new SerializableNopInterceptor()); + + Person p = (Person) factory.getProxy(); + + assertEquals(name, p.getName()); + assertEquals(time, ((TimeStamped) p).getTimeStamp()); + + Person p1 = (Person) SerializationTestUtils.serializeAndDeserialize(p); + assertEquals(name, p1.getName()); + assertEquals(time, ((TimeStamped) p1).getTimeStamp()); + } + +// public void testDelegatingIntroductionInterceptorDoesntMakeNonserializableSerializable() throws Exception { +// // Target is NOT serialiable +// TestBean raw = new TestBean(); +// ProxyFactory factory = new ProxyFactory(raw); +// factory.addInterface(Person.class); +// long time = 1000; +// TimeStamped ts = new SerializableTimeStamped(time); +// +// factory.addAdvisor(new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts))); +// Object proxy = factory.getProxy(); +// +// assertFalse(proxy instanceof Serializable); +// } + + // Test when target implements the interface: should get interceptor by preference. + public void testIntroductionMasksTargetImplementation() throws Exception { + final long t = 1001L; + class TestII extends DelegatingIntroductionInterceptor implements TimeStamped { + public long getTimeStamp() { + return t; + } + } + + DelegatingIntroductionInterceptor ii = new TestII(); + + // != t + TestBean target = new TargetClass(t + 1); + + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii)); + + TimeStamped ts = (TimeStamped) pf.getProxy(); + // From introduction interceptor, not target + assertTrue(ts.getTimeStamp() == t); + } + + + private static class SerializableTimeStamped implements TimeStamped, Serializable { + + private final long ts; + + public SerializableTimeStamped(long ts) { + this.ts = ts; + } + + public long getTimeStamp() { + return ts; + } + } + + + public static class TargetClass extends TestBean implements TimeStamped { + + long t; + + public TargetClass(long t) { + this.t = t; + } + + public long getTimeStamp() { + return t; + } + } + + + public interface ITester { + + void foo() throws Exception; + } + + + private static interface SubTimeStamped extends TimeStamped { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/JdkRegexpMethodPointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/JdkRegexpMethodPointcutTests.java new file mode 100644 index 00000000000..a8d9aa20f2f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/JdkRegexpMethodPointcutTests.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +/** + * @author Dmitriy Kopylenko + */ +public class JdkRegexpMethodPointcutTests extends AbstractRegexpMethodPointcutTests { + + protected AbstractRegexpMethodPointcut getRegexpMethodPointcut() { + return new JdkRegexpMethodPointcut(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/MethodMatchersTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/MethodMatchersTests.java new file mode 100644 index 00000000000..8693653cad1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/MethodMatchersTests.java @@ -0,0 +1,120 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.aop.MethodMatcher; +import org.springframework.beans.IOther; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.util.SerializationTestUtils; + +/** + * $Id: MethodMatchersTests.java,v 1.7 2005/03/25 09:28:18 jhoeller Exp $ + */ +public class MethodMatchersTests extends TestCase { + + private final Method EXCEPTION_GETMESSAGE; + + private final Method ITESTBEAN_SETAGE; + + private final Method ITESTBEAN_GETAGE; + + private final Method IOTHER_ABSQUATULATE; + + public MethodMatchersTests() throws Exception { + EXCEPTION_GETMESSAGE = Exception.class.getMethod("getMessage", (Class[]) null); + ITESTBEAN_GETAGE = ITestBean.class.getMethod("getAge", (Class[]) null); + ITESTBEAN_SETAGE = ITestBean.class.getMethod("setAge", new Class[] { int.class }); + IOTHER_ABSQUATULATE = IOther.class.getMethod("absquatulate", (Class[]) null); + } + + public void testDefaultMatchesAll() throws Exception { + MethodMatcher defaultMm = MethodMatcher.TRUE; + assertTrue(defaultMm.matches(EXCEPTION_GETMESSAGE, Exception.class)); + assertTrue(defaultMm.matches(ITESTBEAN_SETAGE, TestBean.class)); + } + + public void testMethodMatcherTrueSerializable() throws Exception { + assertSame(SerializationTestUtils.serializeAndDeserialize(MethodMatcher.TRUE), MethodMatcher.TRUE); + } + + public void testSingle() throws Exception { + MethodMatcher defaultMm = MethodMatcher.TRUE; + assertTrue(defaultMm.matches(EXCEPTION_GETMESSAGE, Exception.class)); + assertTrue(defaultMm.matches(ITESTBEAN_SETAGE, TestBean.class)); + defaultMm = MethodMatchers.intersection(defaultMm, new StartsWithMatcher("get")); + + assertTrue(defaultMm.matches(EXCEPTION_GETMESSAGE, Exception.class)); + assertFalse(defaultMm.matches(ITESTBEAN_SETAGE, TestBean.class)); + } + + + public void testDynamicAndStaticMethodMatcherIntersection() throws Exception { + MethodMatcher mm1 = MethodMatcher.TRUE; + MethodMatcher mm2 = new TestDynamicMethodMatcherWhichMatches(); + MethodMatcher intersection = MethodMatchers.intersection(mm1, mm2); + assertTrue("Intersection is a dynamic matcher", intersection.isRuntime()); + assertTrue("2Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class)); + assertTrue("3Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Object[] { new Integer(5) })); + // Knock out dynamic part + intersection = MethodMatchers.intersection(intersection, new TestDynamicMethodMatcherWhichDoesNotMatch()); + assertTrue("Intersection is a dynamic matcher", intersection.isRuntime()); + assertTrue("2Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class)); + assertFalse("3 - not Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Object[] { new Integer(5) })); + } + + public void testStaticMethodMatcherUnion() throws Exception { + MethodMatcher getterMatcher = new StartsWithMatcher("get"); + MethodMatcher setterMatcher = new StartsWithMatcher("set"); + MethodMatcher union = MethodMatchers.union(getterMatcher, setterMatcher); + + assertFalse("Union is a static matcher", union.isRuntime()); + assertTrue("Matched setAge method", union.matches(ITESTBEAN_SETAGE, TestBean.class)); + assertTrue("Matched getAge method", union.matches(ITESTBEAN_GETAGE, TestBean.class)); + assertFalse("Didn't matched absquatulate method", union.matches(IOTHER_ABSQUATULATE, TestBean.class)); + + } + + + public static class StartsWithMatcher extends StaticMethodMatcher { + private String prefix; + public StartsWithMatcher(String s) { + this.prefix = s; + } + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith(prefix); + } + } + + + private static class TestDynamicMethodMatcherWhichMatches extends DynamicMethodMatcher { + public boolean matches(Method m, Class targetClass, Object[] args) { + return true; + } + } + + private static class TestDynamicMethodMatcherWhichDoesNotMatch extends DynamicMethodMatcher { + public boolean matches(Method m, Class targetClass, Object[] args) { + return false; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java new file mode 100644 index 00000000000..409fda76759 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java @@ -0,0 +1,132 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.interceptor.SerializableNopInterceptor; +import org.springframework.beans.Person; +import org.springframework.beans.SerializablePerson; +import org.springframework.util.SerializationTestUtils; + +/** + * + * @author Rod Johnson + */ +public class NameMatchMethodPointcutTests extends TestCase { + + protected NameMatchMethodPointcut pc; + + protected Person proxied; + + protected SerializableNopInterceptor nop; + + public NameMatchMethodPointcutTests(String s) { + super(s); + } + + /** + * Create an empty pointcut, populating instance variables. + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() { + ProxyFactory pf = new ProxyFactory(new SerializablePerson()); + nop = new SerializableNopInterceptor(); + pc = new NameMatchMethodPointcut(); + pf.addAdvisor(new DefaultPointcutAdvisor(pc, nop)); + proxied = (Person) pf.getProxy(); + } + + public void testMatchingOnly() { + // Can't do exact matching through isMatch + assertTrue(pc.isMatch("echo", "ech*")); + assertTrue(pc.isMatch("setName", "setN*")); + assertTrue(pc.isMatch("setName", "set*")); + assertFalse(pc.isMatch("getName", "set*")); + assertFalse(pc.isMatch("setName", "set")); + assertTrue(pc.isMatch("testing", "*ing")); + } + + public void testEmpty() throws Throwable { + assertEquals(0, nop.getCount()); + proxied.getName(); + proxied.setName(""); + proxied.echo(null); + assertEquals(0, nop.getCount()); + } + + + public void testMatchOneMethod() throws Throwable { + pc.addMethodName("echo"); + pc.addMethodName("set*"); + assertEquals(0, nop.getCount()); + proxied.getName(); + proxied.getName(); + assertEquals(0, nop.getCount()); + proxied.echo(null); + assertEquals(1, nop.getCount()); + + proxied.setName(""); + assertEquals(2, nop.getCount()); + proxied.setAge(25); + assertEquals(25, proxied.getAge()); + assertEquals(3, nop.getCount()); + } + + public void testSets() throws Throwable { + pc.setMappedNames(new String[] { "set*", "echo" }); + assertEquals(0, nop.getCount()); + proxied.getName(); + proxied.setName(""); + assertEquals(1, nop.getCount()); + proxied.echo(null); + assertEquals(2, nop.getCount()); + } + + public void testSerializable() throws Throwable { + testSets(); + // Count is now 2 + Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(proxied); + NopInterceptor nop2 = (NopInterceptor) ((Advised) p2).getAdvisors()[0].getAdvice(); + p2.getName(); + assertEquals(2, nop2.getCount()); + p2.echo(null); + assertEquals(3, nop2.getCount()); + } + + public void testEqualsAndHashCode() throws Exception { + NameMatchMethodPointcut pc1 = new NameMatchMethodPointcut(); + NameMatchMethodPointcut pc2 = new NameMatchMethodPointcut(); + + String foo = "foo"; + + assertEquals(pc1, pc2); + assertEquals(pc1.hashCode(), pc2.hashCode()); + + pc1.setMappedName(foo); + assertFalse(pc1.equals(pc2)); + assertTrue(pc1.hashCode() != pc2.hashCode()); + + pc2.setMappedName(foo); + assertEquals(pc1, pc2); + assertEquals(pc1.hashCode(), pc2.hashCode()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/PointcutsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/PointcutsTests.java new file mode 100644 index 00000000000..115903240c6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/PointcutsTests.java @@ -0,0 +1,239 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import java.lang.reflect.Method; + +import org.springframework.aop.ClassFilter; +import org.springframework.aop.Pointcut; +import org.springframework.beans.TestBean; + +import junit.framework.TestCase; + +/** + * + * @author Rod Johnson + */ +public class PointcutsTests extends TestCase { + + public static Method TEST_BEAN_SET_AGE; + public static Method TEST_BEAN_GET_AGE; + public static Method TEST_BEAN_GET_NAME; + public static Method TEST_BEAN_ABSQUATULATE; + + static { + try { + TEST_BEAN_SET_AGE = TestBean.class.getMethod("setAge", new Class[] { int.class }); + TEST_BEAN_GET_AGE = TestBean.class.getMethod("getAge", (Class[]) null); + TEST_BEAN_GET_NAME = TestBean.class.getMethod("getName", (Class[]) null); + TEST_BEAN_ABSQUATULATE = TestBean.class.getMethod("absquatulate", (Class[]) null); + } + catch (Exception ex) { + throw new RuntimeException("Shouldn't happen: error in test suite"); + } + } + + /** + * Matches only TestBean class, not subclasses + */ + public static Pointcut allTestBeanMethodsPointcut = new StaticMethodMatcherPointcut() { + public ClassFilter getClassFilter() { + return new ClassFilter() { + public boolean matches(Class clazz) { + return clazz.equals(TestBean.class); + } + }; + } + + public boolean matches(Method m, Class targetClass) { + return true; + } + }; + + public static Pointcut allClassSetterPointcut = Pointcuts.SETTERS; + + // Subclass used for matching + public static class MyTestBean extends TestBean { + } + + public static Pointcut myTestBeanSetterPointcut = new StaticMethodMatcherPointcut() { + public ClassFilter getClassFilter() { + return new RootClassFilter(MyTestBean.class); + } + + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith("set"); + } + }; + + // Will match MyTestBeanSubclass + public static Pointcut myTestBeanGetterPointcut = new StaticMethodMatcherPointcut() { + public ClassFilter getClassFilter() { + return new RootClassFilter(MyTestBean.class); + } + + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith("get"); + } + }; + + // Still more specific class + public static class MyTestBeanSubclass extends MyTestBean { + } + + public static Pointcut myTestBeanSubclassGetterPointcut = new StaticMethodMatcherPointcut() { + public ClassFilter getClassFilter() { + return new RootClassFilter(MyTestBeanSubclass.class); + } + + public boolean matches(Method m, Class targetClass) { + return m.getName().startsWith("get"); + } + }; + + public static Pointcut allClassGetterPointcut = Pointcuts.GETTERS; + + public static Pointcut allClassGetAgePointcut = new NameMatchMethodPointcut().addMethodName("getAge"); + + public static Pointcut allClassGetNamePointcut = new NameMatchMethodPointcut().addMethodName("getName"); + + + public PointcutsTests(String s) { + super(s); + } + + public void testTrue() { + assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + } + + public void testMatches() { + assertTrue(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertFalse(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + assertFalse(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertTrue(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + } + + /** + * Should match all setters and getters on any class + */ + public void testUnionOfSettersAndGetters() { + Pointcut union = Pointcuts.union(allClassGetterPointcut, allClassSetterPointcut); + assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + } + + public void testUnionOfSpecificGetters() { + Pointcut union = Pointcuts.union(allClassGetAgePointcut, allClassGetNamePointcut); + assertFalse(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + + // Union with all setters + union = Pointcuts.union(union, allClassSetterPointcut); + assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + + assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + } + + /** + * Tests vertical composition. First pointcut matches all setters. + * Second one matches all getters in the MyTestBean class. TestBean getters shouldn't pass. + */ + public void testUnionOfAllSettersAndSubclassSetters() { + assertFalse(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertTrue(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, MyTestBean.class, new Object[] { new Integer(6)})); + assertFalse(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null)); + + Pointcut union = Pointcuts.union(myTestBeanSetterPointcut, allClassGetterPointcut); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBean.class, null)); + // Still doesn't match superclass setter + assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, MyTestBean.class, new Object[] { new Integer(6)})); + assertFalse(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + } + + /** + * Intersection should be MyTestBean getAge() only: + * it's the union of allClassGetAge and subclass getters + */ + public void testIntersectionOfSpecificGettersAndSubclassGetters() { + assertTrue(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertTrue(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_AGE, MyTestBean.class, null)); + assertFalse(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertFalse(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertTrue(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_NAME, MyTestBean.class, null)); + assertTrue(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_AGE, MyTestBean.class, null)); + + Pointcut intersection = Pointcuts.intersection(allClassGetAgePointcut, myTestBeanGetterPointcut); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBean.class, null)); + assertTrue(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBean.class, null)); + // Matches subclass of MyTestBean + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBeanSubclass.class, null)); + assertTrue(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBeanSubclass.class, null)); + + // Now intersection with MyTestBeanSubclass getters should eliminate MyTestBean target + intersection = Pointcuts.intersection(intersection, myTestBeanSubclassGetterPointcut); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBean.class, null)); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBean.class, null)); + // Still matches subclass of MyTestBean + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBeanSubclass.class, null)); + assertTrue(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBeanSubclass.class, null)); + + // Now union with all TestBean methods + Pointcut union = Pointcuts.union(intersection, allTestBeanMethodsPointcut); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class, null)); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(union, TEST_BEAN_GET_NAME, MyTestBean.class, null)); + assertFalse(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBean.class, null)); + // Still matches subclass of MyTestBean + assertFalse(Pointcuts.matches(union, TEST_BEAN_GET_NAME, MyTestBeanSubclass.class, null)); + assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBeanSubclass.class, null)); + + assertTrue(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, MyTestBean.class, null)); + } + + + /** + * The intersection of these two pointcuts leaves nothing. + */ + public void testSimpleIntersection() { + Pointcut intersection = Pointcuts.intersection(allClassGetterPointcut, allClassSetterPointcut); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)})); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class, null)); + assertFalse(Pointcuts.matches(intersection, TEST_BEAN_ABSQUATULATE, TestBean.class, null)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java new file mode 100644 index 00000000000..08b86911375 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.interceptor.SerializableNopInterceptor; +import org.springframework.beans.ITestBean; +import org.springframework.beans.Person; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rod Johnson + */ +public class RegexpMethodPointcutAdvisorIntegrationTests extends TestCase { + + public void testSinglePattern() throws Throwable { + BeanFactory bf = new ClassPathXmlApplicationContext("org/springframework/aop/support/regexpSetterTests.xml"); + ITestBean advised = (ITestBean) bf.getBean("settersAdvised"); + // Interceptor behind regexp advisor + NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor"); + assertEquals(0, nop.getCount()); + + int newAge = 12; + // Not advised + advised.exceptional(null); + assertEquals(0, nop.getCount()); + advised.setAge(newAge); + assertEquals(newAge, advised.getAge()); + // Only setter fired + assertEquals(1, nop.getCount()); + } + + public void testMultiplePatterns() throws Throwable { + BeanFactory bf = new ClassPathXmlApplicationContext("org/springframework/aop/support/regexpSetterTests.xml"); + // This is a CGLIB proxy, so we can proxy it to the target class + TestBean advised = (TestBean) bf.getBean("settersAndAbsquatulateAdvised"); + // Interceptor behind regexp advisor + NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor"); + assertEquals(0, nop.getCount()); + + int newAge = 12; + // Not advised + advised.exceptional(null); + assertEquals(0, nop.getCount()); + + // This is proxied + advised.absquatulate(); + assertEquals(1, nop.getCount()); + advised.setAge(newAge); + assertEquals(newAge, advised.getAge()); + // Only setter fired + assertEquals(2, nop.getCount()); + } + + public void testSerialization() throws Throwable { + BeanFactory bf = new ClassPathXmlApplicationContext("org/springframework/aop/support/regexpSetterTests.xml"); + // This is a CGLIB proxy, so we can proxy it to the target class + Person p = (Person) bf.getBean("serializableSettersAdvised"); + // Interceptor behind regexp advisor + NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor"); + assertEquals(0, nop.getCount()); + + int newAge = 12; + // Not advised + assertEquals(0, p.getAge()); + assertEquals(0, nop.getCount()); + + // This is proxied + p.setAge(newAge); + assertEquals(1, nop.getCount()); + p.setAge(newAge); + assertEquals(newAge, p.getAge()); + // Only setter fired + assertEquals(2, nop.getCount()); + + // Serialize and continue... + p = (Person) SerializationTestUtils.serializeAndDeserialize(p); + assertEquals(newAge, p.getAge()); + // Remembers count, but we need to get a new reference to nop... + nop = (SerializableNopInterceptor) ((Advised) p).getAdvisors()[0].getAdvice(); + assertEquals(2, nop.getCount()); + assertEquals("serializableSettersAdvised", p.getName()); + p.setAge(newAge + 1); + assertEquals(3, nop.getCount()); + assertEquals(newAge + 1, p.getAge()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/support/regexpSetterTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/regexpSetterTests.xml new file mode 100644 index 00000000000..2d14f2dc0cd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/support/regexpSetterTests.xml @@ -0,0 +1,58 @@ + + + + + + + + custom + 666 + + + + + + + + + .*set.* + + + + + + org.springframework.beans.ITestBean + + settersAdvisor + + + + org.springframework.beans.Person + + + serializableSettersAdvised + + + settersAdvisor + + + + + + + + .*get.* + .*absquatulate + + + + + + org.springframework.beans.ITestBean + + true + + settersAndAbsquatulateAdvisor + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceProxyTests.java new file mode 100644 index 00000000000..8675a3ab8b3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceProxyTests.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import junit.framework.TestCase; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.ITestBean; +import org.springframework.core.io.ClassPathResource; +import org.springframework.aop.support.AopUtils; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class CommonsPoolTargetSourceProxyTests extends TestCase { + + public void testProxy() throws Exception { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + reader.loadBeanDefinitions(new ClassPathResource("commonsPoolProxyTests.xml", getClass())); + beanFactory.preInstantiateSingletons(); + ITestBean bean = (ITestBean)beanFactory.getBean("testBean"); + assertTrue(AopUtils.isAopProxy(bean)); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests.java new file mode 100644 index 00000000000..68b47605feb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests.java @@ -0,0 +1,201 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import java.util.NoSuchElementException; + +import junit.framework.TestCase; +import org.apache.commons.pool.impl.GenericObjectPool; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.interceptor.SideEffectBean; +import org.springframework.beans.Person; +import org.springframework.beans.SerializablePerson; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.SerializationTestUtils; + +/** + * Tests for pooling invoker interceptor. + * TODO: need to make these tests stronger: it's hard to + * make too many assumptions about a pool. + * + * @author Rod Johnson + * @author Rob Harrop + */ +public class CommonsPoolTargetSourceTests extends TestCase { + + /** + * Initial count value set in bean factory XML + */ + private static final int INITIAL_COUNT = 10; + + private XmlBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource("commonsPoolTests.xml", getClass())); + } + + /** + * We must simulate container shutdown, which should clear threads. + */ + protected void tearDown() { + // Will call pool.close() + this.beanFactory.destroySingletons(); + } + + private void testFunctionality(String name) { + SideEffectBean pooled = (SideEffectBean) beanFactory.getBean(name); + assertEquals(INITIAL_COUNT, pooled.getCount()); + pooled.doWork(); + assertEquals(INITIAL_COUNT + 1, pooled.getCount()); + + pooled = (SideEffectBean) beanFactory.getBean(name); + // Just check that it works--we can't make assumptions + // about the count + pooled.doWork(); + //assertEquals(INITIAL_COUNT + 1, apartment.getCount() ); + } + + public void testFunctionality() { + testFunctionality("pooled"); + } + + public void testFunctionalityWithNoInterceptors() { + testFunctionality("pooledNoInterceptors"); + } + + public void testConfigMixin() { + SideEffectBean pooled = (SideEffectBean) beanFactory.getBean("pooledWithMixin"); + assertEquals(INITIAL_COUNT, pooled.getCount()); + PoolingConfig conf = (PoolingConfig) beanFactory.getBean("pooledWithMixin"); + // TODO one invocation from setup + //assertEquals(1, conf.getInvocations()); + pooled.doWork(); + // assertEquals("No objects active", 0, conf.getActive()); + assertEquals("Correct target source", 25, conf.getMaxSize()); +// assertTrue("Some free", conf.getFree() > 0); + //assertEquals(2, conf.getInvocations()); + assertEquals(25, conf.getMaxSize()); + } + + public void testTargetSourceSerializableWithoutConfigMixin() throws Exception { + CommonsPoolTargetSource cpts = (CommonsPoolTargetSource) beanFactory.getBean("personPoolTargetSource"); + + SingletonTargetSource serialized = (SingletonTargetSource) SerializationTestUtils.serializeAndDeserialize(cpts); + assertTrue(serialized.getTarget() instanceof Person); + } + + + public void testProxySerializableWithoutConfigMixin() throws Exception { + Person pooled = (Person) beanFactory.getBean("pooledPerson"); + + //System.out.println(((Advised) pooled).toProxyConfigString()); + assertTrue(((Advised) pooled).getTargetSource() instanceof CommonsPoolTargetSource); + + //((Advised) pooled).setTargetSource(new SingletonTargetSource(new SerializablePerson())); + Person serialized = (Person) SerializationTestUtils.serializeAndDeserialize(pooled); + assertTrue(((Advised) serialized).getTargetSource() instanceof SingletonTargetSource); + serialized.setAge(25); + assertEquals(25, serialized.getAge()); + } + + public void testHitMaxSize() throws Exception { + int maxSize = 10; + + CommonsPoolTargetSource targetSource = new CommonsPoolTargetSource(); + targetSource.setMaxSize(maxSize); + targetSource.setMaxWait(1); + prepareTargetSource(targetSource); + + Object[] pooledInstances = new Object[maxSize]; + + for (int x = 0; x < maxSize; x++) { + Object instance = targetSource.getTarget(); + assertNotNull(instance); + pooledInstances[x] = instance; + } + + // should be at maximum now + try { + targetSource.getTarget(); + fail("Should throw NoSuchElementException"); + } + catch (NoSuchElementException ex) { + // desired + } + + // lets now release an object and try to accquire a new one + targetSource.releaseTarget(pooledInstances[9]); + pooledInstances[9] = targetSource.getTarget(); + + // release all objects + for (int i = 0; i < pooledInstances.length; i++) { + targetSource.releaseTarget(pooledInstances[i]); + } + } + + public void testHitMaxSizeLoadedFromContext() throws Exception { + Advised person = (Advised) beanFactory.getBean("maxSizePooledPerson"); + CommonsPoolTargetSource targetSource = (CommonsPoolTargetSource) person.getTargetSource(); + + int maxSize = targetSource.getMaxSize(); + Object[] pooledInstances = new Object[maxSize]; + + for (int x = 0; x < maxSize; x++) { + Object instance = targetSource.getTarget(); + assertNotNull(instance); + pooledInstances[x] = instance; + } + + // should be at maximum now + try { + targetSource.getTarget(); + fail("Should throw NoSuchElementException"); + } + catch (NoSuchElementException ex) { + // desired + } + + // lets now release an object and try to accquire a new one + targetSource.releaseTarget(pooledInstances[9]); + pooledInstances[9] = targetSource.getTarget(); + + // release all objects + for (int i = 0; i < pooledInstances.length; i++) { + targetSource.releaseTarget(pooledInstances[i]); + } + } + + public void testSetWhenExhaustedAction() { + CommonsPoolTargetSource targetSource = new CommonsPoolTargetSource(); + targetSource.setWhenExhaustedActionName("WHEN_EXHAUSTED_BLOCK"); + assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK, targetSource.getWhenExhaustedAction()); + } + + private void prepareTargetSource(CommonsPoolTargetSource targetSource) { + String beanName = "target"; + + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.registerPrototype(beanName, SerializablePerson.class); + + targetSource.setTargetBeanName(beanName); + targetSource.setBeanFactory(applicationContext); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java new file mode 100644 index 00000000000..3115144eb7e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java @@ -0,0 +1,154 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.interceptor.SerializableNopInterceptor; +import org.springframework.aop.interceptor.SideEffectBean; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.beans.Person; +import org.springframework.beans.SerializablePerson; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rod Johnson + */ +public class HotSwappableTargetSourceTests extends TestCase { + + /** Initial count value set in bean factory XML */ + private static final int INITIAL_COUNT = 10; + + private XmlBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource("hotSwapTests.xml", getClass())); + } + + /** + * We must simulate container shutdown, which should clear threads. + */ + protected void tearDown() { + // Will call pool.close() + this.beanFactory.destroySingletons(); + } + + /** + * Check it works like a normal invoker + * + */ + public void testBasicFunctionality() { + SideEffectBean target1 = (SideEffectBean) beanFactory.getBean("target1"); + SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable"); + assertEquals(INITIAL_COUNT, proxied.getCount() ); + proxied.doWork(); + assertEquals(INITIAL_COUNT + 1, proxied.getCount() ); + + proxied = (SideEffectBean) beanFactory.getBean("swappable"); + proxied.doWork(); + assertEquals(INITIAL_COUNT + 2, proxied.getCount() ); + } + + public void testValidSwaps() { + SideEffectBean target1 = (SideEffectBean) beanFactory.getBean("target1"); + SideEffectBean target2 = (SideEffectBean) beanFactory.getBean("target2"); + + SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable"); + // assertEquals(target1, ((Advised) proxied).getTarget()); + assertEquals(target1.getCount(), proxied.getCount() ); + proxied.doWork(); + assertEquals(INITIAL_COUNT + 1, proxied.getCount() ); + + HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper"); + Object old = swapper.swap(target2); + assertEquals("Correct old target was returned", target1, old); + + // TODO should be able to make this assertion: need to fix target handling + // in AdvisedSupport + //assertEquals(target2, ((Advised) proxied).getTarget()); + + assertEquals(20, proxied.getCount()); + proxied.doWork(); + assertEquals(21, target2.getCount()); + + // Swap it back + swapper.swap(target1); + assertEquals(target1.getCount(), proxied.getCount()); + } + + + /** + * + * @param invalid + * @return the message + */ + private IllegalArgumentException testRejectsSwapToInvalidValue(Object invalid) { + HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper"); + IllegalArgumentException aopex = null; + try { + swapper.swap(invalid); + fail("Shouldn't be able to swap to invalid value [" + invalid + "]"); + } + catch (IllegalArgumentException ex) { + // Ok + aopex = ex; + } + + // It shouldn't be corrupted, it should still work + testBasicFunctionality(); + return aopex; + } + + public void testRejectsSwapToNull() { + IllegalArgumentException ex = testRejectsSwapToInvalidValue(null); + assertTrue(ex.getMessage().indexOf("null") != -1); + } + + // TODO test reject swap to wrong interface or class? + // how to decide what's valid? + + + public void testSerialization() throws Exception { + SerializablePerson sp1 = new SerializablePerson(); + sp1.setName("Tony"); + SerializablePerson sp2 = new SerializablePerson(); + sp1.setName("Gordon"); + + HotSwappableTargetSource hts = new HotSwappableTargetSource(sp1); + ProxyFactory pf = new ProxyFactory(); + pf.addInterface(Person.class); + pf.setTargetSource(hts); + pf.addAdvisor(new DefaultPointcutAdvisor(new SerializableNopInterceptor())); + Person p = (Person) pf.getProxy(); + + assertEquals(sp1.getName(), p.getName()); + hts.swap(sp2); + assertEquals(sp2.getName(), p.getName()); + + p = (Person) SerializationTestUtils.serializeAndDeserialize(p); + // We need to get a reference to the client-side targetsource + hts = (HotSwappableTargetSource) ((Advised) p).getTargetSource(); + assertEquals(sp2.getName(), p.getName()); + hts.swap(sp1); + assertEquals(sp1.getName(), p.getName()); + + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyCreationTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyCreationTargetSourceTests.java new file mode 100644 index 00000000000..cae3b1bb87a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyCreationTargetSourceTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import junit.framework.TestCase; + +import org.springframework.aop.TargetSource; +import org.springframework.aop.framework.ProxyFactory; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class LazyCreationTargetSourceTests extends TestCase { + + public void testCreateLazy() { + TargetSource targetSource = new AbstractLazyCreationTargetSource() { + protected Object createObject() { + return new InitCountingBean(); + } + public Class getTargetClass() { + return InitCountingBean.class; + } + }; + + InitCountingBean proxy = (InitCountingBean) ProxyFactory.getProxy(targetSource); + assertEquals("Init count should be 0", 0, InitCountingBean.initCount); + assertEquals("Target class incorrect", InitCountingBean.class, targetSource.getTargetClass()); + assertEquals("Init count should still be 0 after getTargetClass()", 0, InitCountingBean.initCount); + + proxy.doSomething(); + assertEquals("Init count should now be 1", 1, InitCountingBean.initCount); + + proxy.doSomething(); + assertEquals("Init count should still be 1", 1, InitCountingBean.initCount); + } + + + private static class InitCountingBean { + + public static int initCount; + + public InitCountingBean() { + if (InitCountingBean.class.equals(getClass())) { + // only increment when creating the actual target - not the proxy + initCount++; + } + } + + public void doSomething() { + //no-op + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java new file mode 100644 index 00000000000..0f284f4804b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + * @author Rob Harrop + * @since 07.01.2005 + */ +public class LazyInitTargetSourceTests extends TestCase { + + public void testLazyInitSingletonTargetSource() { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("lazyInitSingletonTests.xml", getClass())); + bf.preInstantiateSingletons(); + + ITestBean tb = (ITestBean) bf.getBean("proxy"); + assertFalse(bf.containsSingleton("target")); + assertEquals(10, tb.getAge()); + assertTrue(bf.containsSingleton("target")); + } + + public void testCustomLazyInitSingletonTargetSource() { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("customLazyInitTarget.xml", getClass())); + bf.preInstantiateSingletons(); + + ITestBean tb = (ITestBean) bf.getBean("proxy"); + assertFalse(bf.containsSingleton("target")); + assertEquals("Rob Harrop", tb.getName()); + assertTrue(bf.containsSingleton("target")); + } + + public void testLazyInitFactoryBeanTargetSource() { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("lazyInitFactoryBean.xml", getClass())); + bf.preInstantiateSingletons(); + + Set set1 = (Set) bf.getBean("proxy1"); + assertFalse(bf.containsSingleton("target1")); + assertTrue(set1.contains("10")); + assertTrue(bf.containsSingleton("target1")); + + Set set2 = (Set) bf.getBean("proxy2"); + assertFalse(bf.containsSingleton("target2")); + assertTrue(set2.contains("20")); + assertTrue(bf.containsSingleton("target2")); + } + + + public static class CustomLazyInitTargetSource extends LazyInitTargetSource { + + protected void postProcessTargetObject(Object targetObject) { + ((ITestBean) targetObject).setName("Rob Harrop"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java new file mode 100644 index 00000000000..c3a92a0a813 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import junit.framework.TestCase; + +import org.springframework.aop.TargetSource; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.SerializablePerson; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.util.SerializationTestUtils; + +/** + * Unit tests relating to the abstract AbstractPrototypeBasedTargetSource + * and not subclasses. + * + * @author Rod Johnson + */ +public class PrototypeBasedTargetSourceTests extends TestCase { + + public void testSerializability() throws Exception { + MutablePropertyValues tsPvs = new MutablePropertyValues(); + tsPvs.addPropertyValue("targetBeanName", "person"); + RootBeanDefinition tsBd = new RootBeanDefinition(TestTargetSource.class, tsPvs); + + MutablePropertyValues pvs = new MutablePropertyValues(); + RootBeanDefinition bd = new RootBeanDefinition(SerializablePerson.class, pvs); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("ts", tsBd); + bf.registerBeanDefinition("person", bd); + + TestTargetSource cpts = (TestTargetSource) bf.getBean("ts"); + TargetSource serialized = (TargetSource) SerializationTestUtils.serializeAndDeserialize(cpts); + assertTrue("Changed to SingletonTargetSource on deserialization", + serialized instanceof SingletonTargetSource); + SingletonTargetSource sts = (SingletonTargetSource) serialized; + assertNotNull(sts.getTarget()); + } + + + private static class TestTargetSource extends AbstractPrototypeBasedTargetSource { + + /** + * Nonserializable test field to check that subclass + * state can't prevent serialization from working + */ + private TestBean thisFieldIsNotSerializable = new TestBean(); + + public Object getTarget() throws Exception { + return newPrototypeInstance(); + } + + public void releaseTarget(Object target) throws Exception { + // Do nothing + } + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java new file mode 100644 index 00000000000..292b99b4309 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import junit.framework.TestCase; + +import org.springframework.aop.interceptor.SideEffectBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rod Johnson + */ +public class PrototypeTargetSourceTests extends TestCase { + + /** Initial count value set in bean factory XML */ + private static final int INITIAL_COUNT = 10; + + private BeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource("prototypeTests.xml", getClass())); + } + + /** + * Test that multiple invocations of the prototype bean will result + * in no change to visible state, as a new instance is used. + * With the singleton, there will be change. + */ + public void testPrototypeAndSingletonBehaveDifferently() { + SideEffectBean singleton = (SideEffectBean) beanFactory.getBean("singleton"); + assertEquals(INITIAL_COUNT, singleton.getCount() ); + singleton.doWork(); + assertEquals(INITIAL_COUNT + 1, singleton.getCount() ); + + SideEffectBean prototype = (SideEffectBean) beanFactory.getBean("prototype"); + assertEquals(INITIAL_COUNT, prototype.getCount() ); + prototype.doWork(); + assertEquals(INITIAL_COUNT, prototype.getCount() ); + } + + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java new file mode 100644 index 00000000000..d5817d8eabb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java @@ -0,0 +1,146 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import junit.framework.TestCase; + +import org.springframework.aop.interceptor.SideEffectBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rod Johnson + */ +public class ThreadLocalTargetSourceTests extends TestCase { + + /** Initial count value set in bean factory XML */ + private static final int INITIAL_COUNT = 10; + + private XmlBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource("threadLocalTests.xml", getClass())); + } + + /** + * We must simulate container shutdown, which should clear threads. + */ + protected void tearDown() { + this.beanFactory.destroySingletons(); + } + + /** + * Check we can use two different ThreadLocalTargetSources + * managing objects of different types without them interfering + * with one another. + */ + public void testUseDifferentManagedInstancesInSameThread() { + SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment"); + assertEquals(INITIAL_COUNT, apartment.getCount() ); + apartment.doWork(); + assertEquals(INITIAL_COUNT + 1, apartment.getCount() ); + + ITestBean test = (ITestBean) beanFactory.getBean("threadLocal2"); + assertEquals("Rod", test.getName()); + assertEquals("Kerry", test.getSpouse().getName()); + } + + public void testReuseInSameThread() { + SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment"); + assertEquals(INITIAL_COUNT, apartment.getCount() ); + apartment.doWork(); + assertEquals(INITIAL_COUNT + 1, apartment.getCount() ); + + apartment = (SideEffectBean) beanFactory.getBean("apartment"); + assertEquals(INITIAL_COUNT + 1, apartment.getCount() ); + } + + /** + * Relies on introduction. + */ + public void testCanGetStatsViaMixin() { + ThreadLocalTargetSourceStats stats = (ThreadLocalTargetSourceStats) beanFactory.getBean("apartment"); + // +1 because creating target for stats call counts + assertEquals(1, stats.getInvocationCount()); + SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment"); + apartment.doWork(); + // +1 again + assertEquals(3, stats.getInvocationCount()); + // + 1 for states call! + assertEquals(3, stats.getHitCount()); + apartment.doWork(); + assertEquals(6, stats.getInvocationCount()); + assertEquals(6, stats.getHitCount()); + // Only one thread so only one object can have been bound + assertEquals(1, stats.getObjectCount()); + } + + public void testNewThreadHasOwnInstance() throws InterruptedException { + SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment"); + assertEquals(INITIAL_COUNT, apartment.getCount() ); + apartment.doWork(); + apartment.doWork(); + apartment.doWork(); + assertEquals(INITIAL_COUNT + 3, apartment.getCount() ); + + class Runner implements Runnable { + public SideEffectBean mine; + public void run() { + this.mine = (SideEffectBean) beanFactory.getBean("apartment"); + assertEquals(INITIAL_COUNT, mine.getCount() ); + mine.doWork(); + assertEquals(INITIAL_COUNT + 1, mine.getCount() ); + } + } + Runner r = new Runner(); + Thread t = new Thread(r); + t.start(); + t.join(); + + assertNotNull(r); + + // Check it didn't affect the other thread's copy + assertEquals(INITIAL_COUNT + 3, apartment.getCount() ); + + // When we use other thread's copy in this thread + // it should behave like ours + assertEquals(INITIAL_COUNT + 3, r.mine.getCount() ); + + // Bound to two threads + assertEquals(2, ((ThreadLocalTargetSourceStats) apartment).getObjectCount()); + } + + /** + * Test for SPR-1442. Destroyed target should re-associated with thread and not throw NPE + */ + public void testReuseDestroyedTarget() { + ThreadLocalTargetSource source = (ThreadLocalTargetSource)this.beanFactory.getBean("threadLocalTs"); + + // try first time + Object o = source.getTarget(); + source.destroy(); + + // try second time + try { + source.getTarget(); + } catch(NullPointerException ex) { + fail("Should not throw NPE"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolProxyTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolProxyTests.xml new file mode 100644 index 00000000000..47bacce831c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolProxyTests.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolTests.xml new file mode 100644 index 00000000000..a67be5b92f0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/commonsPoolTests.xml @@ -0,0 +1,69 @@ + + + + + + + 10 + + + + prototypeTest + 25 + + + + + getPoolingConfigMixin + + + + + + + + nop + + + + + + + + + poolConfigAdvisor + + true + + + + + + + + + prototypePerson + 10 + + + + + serializableNop + + + + + + + + + + + + serializableNop + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/customLazyInitTarget.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/customLazyInitTarget.xml new file mode 100644 index 00000000000..09782ac5c02 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/customLazyInitTarget.xml @@ -0,0 +1,21 @@ + + + + + + + 10 + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java new file mode 100644 index 00000000000..cc4aee4b4d7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java @@ -0,0 +1,126 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target.dynamic; + +import junit.framework.TestCase; + +/** + * @author Rob Harrop + */ +public class RefreshableTargetSourceTests extends TestCase { + + /** + * Test what happens when checking for refresh but not refreshing object. + */ + public void testRefreshCheckWithNonRefresh() throws Exception { + CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(); + ts.setRefreshCheckDelay(0); + + Object a = ts.getTarget(); + Thread.sleep(1); + Object b = ts.getTarget(); + + assertEquals("Should be one call to freshTarget to get initial target", 1, ts.getCallCount()); + assertSame("Returned objects should be the same - no refresh should occur", a, b); + } + + /** + * Test what happens when checking for refresh and refresh occurs. + */ + public void testRefreshCheckWithRefresh() throws Exception { + CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true); + ts.setRefreshCheckDelay(0); + + Object a = ts.getTarget(); + Thread.sleep(100); + Object b = ts.getTarget(); + + assertEquals("Should have called freshTarget twice", 2, ts.getCallCount()); + assertNotSame("Should be different objects", a, b); + } + + /** + * Test what happens when no refresh occurs. + */ + public void testWithNoRefreshCheck() throws Exception { + CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true); + ts.setRefreshCheckDelay(-1); + + Object a = ts.getTarget(); + Object b = ts.getTarget(); + + assertEquals("Refresh target should only be called once", 1, ts.getCallCount()); + assertSame("Objects should be the same - refresh check delay not elapsed", a, b); + } + + public void testRefreshOverTime() throws Exception { + CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true); + ts.setRefreshCheckDelay(100); + + Object a = ts.getTarget(); + Object b = ts.getTarget(); + assertEquals("Objects should be same", a, b); + + Thread.sleep(50); + + Object c = ts.getTarget(); + assertEquals("A and C should be same", a, c); + + Thread.sleep(60); + + Object d = ts.getTarget(); + assertNotNull("D should not be null", d); + assertFalse("A and D should not be equal", a.equals(d)); + + Object e = ts.getTarget(); + assertEquals("D and E should be equal", d, e); + + Thread.sleep(110); + + Object f = ts.getTarget(); + assertFalse("E and F should be different", e.equals(f)); + } + + + private static class CountingRefreshableTargetSource extends AbstractRefreshableTargetSource { + + private int callCount; + + private boolean requiresRefresh; + + public CountingRefreshableTargetSource() { + } + + public CountingRefreshableTargetSource(boolean requiresRefresh) { + this.requiresRefresh = requiresRefresh; + } + + protected Object freshTarget() { + this.callCount++; + return new Object(); + } + + public int getCallCount() { + return this.callCount; + } + + protected boolean requiresRefresh() { + return this.requiresRefresh; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/hotSwapTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/hotSwapTests.xml new file mode 100644 index 00000000000..349193136c6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/hotSwapTests.xml @@ -0,0 +1,27 @@ + + + + + + + + 10 + + + + 20 + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitFactoryBean.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitFactoryBean.xml new file mode 100644 index 00000000000..4b408a3410f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitFactoryBean.xml @@ -0,0 +1,47 @@ + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 20 + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitSingletonTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitSingletonTests.xml new file mode 100644 index 00000000000..0b2d472135a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/lazyInitSingletonTests.xml @@ -0,0 +1,21 @@ + + + + + + + 10 + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/prototypeTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/prototypeTests.xml new file mode 100644 index 00000000000..33a2907aca2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/prototypeTests.xml @@ -0,0 +1,33 @@ + + + + + + + + 10 + + + + 10 + + + + prototypeTest + + + + + + debugInterceptor,test + + + + + + debugInterceptor + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/target/threadLocalTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/threadLocalTests.xml new file mode 100644 index 00000000000..4c5e3ba3130 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/target/threadLocalTests.xml @@ -0,0 +1,55 @@ + + + + + + + 10 + + + + prototypeTest + + + + + + + + getStatsMixin + + + + + debugInterceptor,statsAdvisor + + + true + + + + + + Rod + + + + + Kerry + + + + test + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java new file mode 100644 index 00000000000..0d0b71e6842 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + */ +public abstract class AbstractPropertyValuesTests extends TestCase { + + /** + * Must contain: forname=Tony surname=Blair age=50 + */ + protected void doTestTony(PropertyValues pvs) throws Exception { + assertTrue("Contains 3", pvs.getPropertyValues().length == 3); + assertTrue("Contains forname", pvs.contains("forname")); + assertTrue("Contains surname", pvs.contains("surname")); + assertTrue("Contains age", pvs.contains("age")); + assertTrue("Doesn't contain tory", !pvs.contains("tory")); + + PropertyValue[] ps = pvs.getPropertyValues(); + Map m = new HashMap(); + m.put("forname", "Tony"); + m.put("surname", "Blair"); + m.put("age", "50"); + for (int i = 0; i < ps.length; i++) { + Object val = m.get(ps[i].getName()); + assertTrue("Can't have unexpected value", val != null); + assertTrue("Val i string", val instanceof String); + assertTrue("val matches expected", val.equals(ps[i].getValue())); + m.remove(ps[i].getName()); + } + assertTrue("Map size is 0", m.size() == 0); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanUtilsTests.java new file mode 100644 index 00000000000..29b9a239b3d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanUtilsTests.java @@ -0,0 +1,309 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceEditor; + +/** + * @author Juergen Hoeller + * @author Rob Harrop + * @since 19.05.2003 + */ +public class BeanUtilsTests extends TestCase { + + public void testInstantiateClass() { + // give proper class + BeanUtils.instantiateClass(ArrayList.class); + + try { + // give interface + BeanUtils.instantiateClass(List.class); + fail("Should have thrown FatalBeanException"); + } + catch (FatalBeanException ex) { + // expected + } + + try { + // give class without default constructor + BeanUtils.instantiateClass(CustomDateEditor.class); + fail("Should have thrown FatalBeanException"); + } + catch (FatalBeanException ex) { + // expected + } + } + + public void testGetPropertyDescriptors() throws Exception { + PropertyDescriptor[] actual = Introspector.getBeanInfo(TestBean.class).getPropertyDescriptors(); + PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(TestBean.class); + assertNotNull("Descriptors should not be null", descriptors); + assertEquals("Invalid number of descriptors returned", actual.length, descriptors.length); + } + + public void testBeanPropertyIsArray() { + PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(ContainerBean.class); + for (int i = 0; i < descriptors.length; i++) { + PropertyDescriptor descriptor = descriptors[i]; + if ("containedBeans".equals(descriptor.getName())) { + assertTrue("Property should be an array", descriptor.getPropertyType().isArray()); + assertEquals(descriptor.getPropertyType().getComponentType(), ContainedBean.class); + } + } + } + + public void testFindEditorByConvention() { + assertEquals(ResourceEditor.class, BeanUtils.findEditorByConvention(Resource.class).getClass()); + } + + public void testCopyProperties() throws Exception { + TestBean tb = new TestBean(); + tb.setName("rod"); + tb.setAge(32); + tb.setTouchy("touchy"); + TestBean tb2 = new TestBean(); + assertTrue("Name empty", tb2.getName() == null); + assertTrue("Age empty", tb2.getAge() == 0); + assertTrue("Touchy empty", tb2.getTouchy() == null); + BeanUtils.copyProperties(tb, tb2); + assertTrue("Name copied", tb2.getName().equals(tb.getName())); + assertTrue("Age copied", tb2.getAge() == tb.getAge()); + assertTrue("Touchy copied", tb2.getTouchy().equals(tb.getTouchy())); + } + + public void testCopyPropertiesWithDifferentTypes1() throws Exception { + DerivedTestBean tb = new DerivedTestBean(); + tb.setName("rod"); + tb.setAge(32); + tb.setTouchy("touchy"); + TestBean tb2 = new TestBean(); + assertTrue("Name empty", tb2.getName() == null); + assertTrue("Age empty", tb2.getAge() == 0); + assertTrue("Touchy empty", tb2.getTouchy() == null); + BeanUtils.copyProperties(tb, tb2); + assertTrue("Name copied", tb2.getName().equals(tb.getName())); + assertTrue("Age copied", tb2.getAge() == tb.getAge()); + assertTrue("Touchy copied", tb2.getTouchy().equals(tb.getTouchy())); + } + + public void testCopyPropertiesWithDifferentTypes2() throws Exception { + TestBean tb = new TestBean(); + tb.setName("rod"); + tb.setAge(32); + tb.setTouchy("touchy"); + DerivedTestBean tb2 = new DerivedTestBean(); + assertTrue("Name empty", tb2.getName() == null); + assertTrue("Age empty", tb2.getAge() == 0); + assertTrue("Touchy empty", tb2.getTouchy() == null); + BeanUtils.copyProperties(tb, tb2); + assertTrue("Name copied", tb2.getName().equals(tb.getName())); + assertTrue("Age copied", tb2.getAge() == tb.getAge()); + assertTrue("Touchy copied", tb2.getTouchy().equals(tb.getTouchy())); + } + + public void testCopyPropertiesWithEditable() throws Exception { + TestBean tb = new TestBean(); + assertTrue("Name empty", tb.getName() == null); + tb.setAge(32); + tb.setTouchy("bla"); + TestBean tb2 = new TestBean(); + tb2.setName("rod"); + assertTrue("Age empty", tb2.getAge() == 0); + assertTrue("Touchy empty", tb2.getTouchy() == null); + + // "touchy" should not be copied: it's not defined in ITestBean + BeanUtils.copyProperties(tb, tb2, ITestBean.class); + assertTrue("Name copied", tb2.getName() == null); + assertTrue("Age copied", tb2.getAge() == 32); + assertTrue("Touchy still empty", tb2.getTouchy() == null); + } + + public void testCopyPropertiesWithIgnore() throws Exception { + TestBean tb = new TestBean(); + assertTrue("Name empty", tb.getName() == null); + tb.setAge(32); + tb.setTouchy("bla"); + TestBean tb2 = new TestBean(); + tb2.setName("rod"); + assertTrue("Age empty", tb2.getAge() == 0); + assertTrue("Touchy empty", tb2.getTouchy() == null); + + // "spouse", "touchy", "age" should not be copied + BeanUtils.copyProperties(tb, tb2, new String[]{"spouse", "touchy", "age"}); + assertTrue("Name copied", tb2.getName() == null); + assertTrue("Age still empty", tb2.getAge() == 0); + assertTrue("Touchy still empty", tb2.getTouchy() == null); + } + + public void testCopyPropertiesWithIgnoredNonExistingProperty() { + NameAndSpecialProperty source = new NameAndSpecialProperty(); + source.setName("name"); + TestBean target = new TestBean(); + BeanUtils.copyProperties(source, target, new String[]{"specialProperty"}); + assertEquals(target.getName(), "name"); + } + + public void testResolveSimpleSignature() throws Exception { + Method desiredMethod = MethodSignatureBean.class.getMethod("doSomething", null); + assertSignatureEquals(desiredMethod, "doSomething"); + assertSignatureEquals(desiredMethod, "doSomething()"); + } + + public void testResolveInvalidSignature() throws Exception { + try { + BeanUtils.resolveSignature("doSomething(", MethodSignatureBean.class); + fail("Should not be able to parse with opening but no closing paren."); + } + catch (IllegalArgumentException ex) { + // success + } + + try { + BeanUtils.resolveSignature("doSomething)", MethodSignatureBean.class); + fail("Should not be able to parse with closing but no opening paren."); + } + catch (IllegalArgumentException ex) { + // success + } + } + + public void testResolveWithAndWithoutArgList() throws Exception { + Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingElse", new Class[]{String.class, int.class}); + assertSignatureEquals(desiredMethod, "doSomethingElse"); + assertNull(BeanUtils.resolveSignature("doSomethingElse()", MethodSignatureBean.class)); + } + + public void testResolveTypedSignature() throws Exception { + Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingElse", new Class[]{String.class, int.class}); + assertSignatureEquals(desiredMethod, "doSomethingElse(java.lang.String, int)"); + } + + public void testResolveOverloadedSignature() throws Exception { + // test resolve with no args + Method desiredMethod = MethodSignatureBean.class.getMethod("overloaded", null); + assertSignatureEquals(desiredMethod, "overloaded()"); + + // resolve with single arg + desiredMethod = MethodSignatureBean.class.getMethod("overloaded", new Class[]{String.class}); + assertSignatureEquals(desiredMethod, "overloaded(java.lang.String)"); + + // resolve with two args + desiredMethod = MethodSignatureBean.class.getMethod("overloaded", new Class[]{String.class, BeanFactory.class}); + assertSignatureEquals(desiredMethod, "overloaded(java.lang.String, org.springframework.beans.factory.BeanFactory)"); + } + + public void testResolveSignatureWithArray() throws Exception { + Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingWithAnArray", new Class[]{String[].class}); + assertSignatureEquals(desiredMethod, "doSomethingWithAnArray(java.lang.String[])"); + + desiredMethod = MethodSignatureBean.class.getMethod("doSomethingWithAMultiDimensionalArray", new Class[]{String[][].class}); + assertSignatureEquals(desiredMethod, "doSomethingWithAMultiDimensionalArray(java.lang.String[][])"); + } + + private void assertSignatureEquals(Method desiredMethod, String signature) { + assertEquals(desiredMethod, BeanUtils.resolveSignature(signature, MethodSignatureBean.class)); + } + + + private static class NameAndSpecialProperty { + + private String name; + + private int specialProperty; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public void setSpecialProperty(int specialProperty) { + this.specialProperty = specialProperty; + } + + public int getSpecialProperty() { + return specialProperty; + } + } + + + private static class ContainerBean { + + private ContainedBean[] containedBeans; + + public ContainedBean[] getContainedBeans() { + return containedBeans; + } + + public void setContainedBeans(ContainedBean[] containedBeans) { + this.containedBeans = containedBeans; + } + } + + + private static class ContainedBean { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + + private static class MethodSignatureBean { + + public void doSomething() { + } + + public void doSomethingElse(String s, int x) { + } + + public void overloaded() { + } + + public void overloaded(String s) { + } + + public void overloaded(String s, BeanFactory beanFactory) { + } + + public void doSomethingWithAnArray(String[] strings) { + } + + public void doSomethingWithAMultiDimensionalArray(String[][] strings) { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWithObjectProperty.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWithObjectProperty.java new file mode 100644 index 00000000000..18ddbd3b78b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWithObjectProperty.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * @author Juergen Hoeller + * @since 17.08.2004 + */ +public class BeanWithObjectProperty { + + private Object object; + + public Object getObject() { + return object; + } + + public void setObject(Object object) { + this.object = object; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWrapperTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWrapperTests.java new file mode 100644 index 00000000000..25991f3ed40 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/BeanWrapperTests.java @@ -0,0 +1,1711 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.beans.PropertyEditorSupport; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import junit.framework.TestCase; +import org.apache.commons.logging.LogFactory; +import org.hibernate.FlushMode; + +import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.beans.propertyeditors.StringArrayPropertyEditor; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.beans.support.DerivedFromProtectedBaseBean; +import org.springframework.util.StopWatch; +import org.springframework.util.StringUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Alef Arendsen + * @author Arjen Poutsma + */ +public class BeanWrapperTests extends TestCase { + + public void testSetWrappedInstanceOfSameClass() throws Exception { + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + assertTrue(bw.isReadableProperty("age")); + tb.setAge(11); + + TestBean tb2 = new TestBean(); + bw.setWrappedInstance(tb2); + + bw.setPropertyValue("age", new Integer(14)); + assertTrue("2nd changed", tb2.getAge() == 14); + assertTrue("1 didn't change", tb.getAge() == 11); + } + + public void testIsReadablePropertyNotReadable() { + NoRead nr = new NoRead(); + BeanWrapper bw = new BeanWrapperImpl(nr); + assertFalse(bw.isReadableProperty("age")); + } + + /** + * Shouldn't throw an exception: should just return false + */ + public void testIsReadablePropertyNoSuchProperty() { + NoRead nr = new NoRead(); + BeanWrapper bw = new BeanWrapperImpl(nr); + assertFalse(bw.isReadableProperty("xxxxx")); + } + + public void testIsReadablePropertyNull() { + NoRead nr = new NoRead(); + BeanWrapper bw = new BeanWrapperImpl(nr); + try { + bw.isReadableProperty(null); + fail("Can't inquire into readability of null property"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testIsWritablePropertyNull() { + NoRead nr = new NoRead(); + BeanWrapper bw = new BeanWrapperImpl(nr); + try { + bw.isWritableProperty(null); + fail("Can't inquire into writability of null property"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testReadableAndWritableForIndexedProperties() { + BeanWrapper bw = new BeanWrapperImpl(IndexedTestBean.class); + + assertTrue(bw.isReadableProperty("array")); + assertTrue(bw.isReadableProperty("list")); + assertTrue(bw.isReadableProperty("set")); + assertTrue(bw.isReadableProperty("map")); + assertFalse(bw.isReadableProperty("xxx")); + + assertTrue(bw.isWritableProperty("array")); + assertTrue(bw.isWritableProperty("list")); + assertTrue(bw.isWritableProperty("set")); + assertTrue(bw.isWritableProperty("map")); + assertFalse(bw.isWritableProperty("xxx")); + + assertTrue(bw.isReadableProperty("array[0]")); + assertTrue(bw.isReadableProperty("array[0].name")); + assertTrue(bw.isReadableProperty("list[0]")); + assertTrue(bw.isReadableProperty("list[0].name")); + assertTrue(bw.isReadableProperty("set[0]")); + assertTrue(bw.isReadableProperty("set[0].name")); + assertTrue(bw.isReadableProperty("map[key1]")); + assertTrue(bw.isReadableProperty("map[key1].name")); + assertTrue(bw.isReadableProperty("map[key4][0]")); + assertTrue(bw.isReadableProperty("map[key4][0].name")); + assertTrue(bw.isReadableProperty("map[key4][1]")); + assertTrue(bw.isReadableProperty("map[key4][1].name")); + assertFalse(bw.isReadableProperty("array[key1]")); + + assertTrue(bw.isWritableProperty("array[0]")); + assertTrue(bw.isWritableProperty("array[0].name")); + assertTrue(bw.isWritableProperty("list[0]")); + assertTrue(bw.isWritableProperty("list[0].name")); + assertTrue(bw.isWritableProperty("set[0]")); + assertTrue(bw.isWritableProperty("set[0].name")); + assertTrue(bw.isWritableProperty("map[key1]")); + assertTrue(bw.isWritableProperty("map[key1].name")); + assertTrue(bw.isWritableProperty("map[key4][0]")); + assertTrue(bw.isWritableProperty("map[key4][0].name")); + assertTrue(bw.isWritableProperty("map[key4][1]")); + assertTrue(bw.isWritableProperty("map[key4][1].name")); + assertFalse(bw.isWritableProperty("array[key1]")); + } + + public void testTypeDeterminationForIndexedProperty() { + BeanWrapper bw = new BeanWrapperImpl(IndexedTestBean.class); + assertEquals(null, bw.getPropertyType("map[key0]")); + + bw = new BeanWrapperImpl(IndexedTestBean.class); + bw.setPropertyValue("map[key0]", "my String"); + assertEquals(String.class, bw.getPropertyType("map[key0]")); + + bw = new BeanWrapperImpl(IndexedTestBean.class); + bw.registerCustomEditor(String.class, "map[key0]", new StringTrimmerEditor(false)); + assertEquals(String.class, bw.getPropertyType("map[key0]")); + } + + public void testSetWrappedInstanceOfDifferentClass() { + ThrowsException tex = new ThrowsException(); + BeanWrapper bw = new BeanWrapperImpl(tex); + + TestBean tb2 = new TestBean(); + bw.setWrappedInstance(tb2); + + bw.setPropertyValue("age", new Integer(14)); + assertTrue("2nd changed", tb2.getAge() == 14); + } + + public void testGetterThrowsException() { + GetterBean gb = new GetterBean(); + BeanWrapper bw = new BeanWrapperImpl(gb); + bw.setPropertyValue("name", "tom"); + assertTrue("Set name to tom", gb.getName().equals("tom")); + } + + public void testEmptyPropertyValuesSet() { + TestBean t = new TestBean(); + int age = 50; + String name = "Tony"; + t.setAge(age); + t.setName(name); + try { + BeanWrapper bw = new BeanWrapperImpl(t); + assertTrue("age is OK", t.getAge() == age); + assertTrue("name is OK", name.equals(t.getName())); + bw.setPropertyValues(new MutablePropertyValues()); + // Check its unchanged + assertTrue("age is OK", t.getAge() == age); + assertTrue("name is OK", name.equals(t.getName())); + } + catch (BeansException ex) { + fail("Shouldn't throw exception when everything is valid"); + } + } + + public void testAllValid() { + TestBean t = new TestBean(); + String newName = "tony"; + int newAge = 65; + String newTouchy = "valid"; + try { + BeanWrapper bw = new BeanWrapperImpl(t); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("age", new Integer(newAge))); + pvs.addPropertyValue(new PropertyValue("name", newName)); + + pvs.addPropertyValue(new PropertyValue("touchy", newTouchy)); + bw.setPropertyValues(pvs); + assertTrue("Validly set property must stick", t.getName().equals(newName)); + assertTrue("Validly set property must stick", t.getTouchy().equals(newTouchy)); + assertTrue("Validly set property must stick", t.getAge() == newAge); + } + catch (BeansException ex) { + fail("Shouldn't throw exception when everything is valid"); + } + } + + public void testBeanWrapperUpdates() { + TestBean t = new TestBean(); + int newAge = 33; + try { + BeanWrapper bw = new BeanWrapperImpl(t); + t.setAge(newAge); + Object bwAge = bw.getPropertyValue("age"); + assertTrue("Age is an integer", bwAge instanceof Integer); + int bwi = ((Integer) bwAge).intValue(); + assertTrue("Bean wrapper must pick up changes", bwi == newAge); + } + catch (Exception ex) { + fail("Shouldn't throw exception when everything is valid"); + } + } + + public void testValidNullUpdate() { + TestBean t = new TestBean(); + t.setName("Frank"); // we need to change it back + t.setSpouse(t); + BeanWrapper bw = new BeanWrapperImpl(t); + assertTrue("name is not null to start off", t.getName() != null); + bw.setPropertyValue("name", null); + assertTrue("name is now null", t.getName() == null); + // now test with non-string + assertTrue("spouse is not null to start off", t.getSpouse() != null); + bw.setPropertyValue("spouse", null); + assertTrue("spouse is now null", t.getSpouse() == null); + } + + public void testIgnoringIndexedProperty() { + MutablePropertyValues values = new MutablePropertyValues(); + values.addPropertyValue("toBeIgnored[0]", new Integer(42)); + BeanWrapper bw = new BeanWrapperImpl(new Object()); + bw.setPropertyValues(values, true); + } + + public void testConvertPrimitiveToString() { + MutablePropertyValues values = new MutablePropertyValues(); + values.addPropertyValue("name", new Integer(42)); + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.setPropertyValues(values); + assertEquals("42", tb.getName()); + } + + public void testConvertClassToString() { + MutablePropertyValues values = new MutablePropertyValues(); + values.addPropertyValue("name", Integer.class); + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, new PropertyEditorSupport() { + public void setValue(Object value) { + super.setValue(value.toString()); + } + }); + bw.setPropertyValues(values); + assertEquals(Integer.class.toString(), tb.getName()); + } + + public void testBooleanObject() { + BooleanTestBean tb = new BooleanTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + + bw.setPropertyValue("bool2", "true"); + assertTrue("Correct bool2 value", Boolean.TRUE.equals(bw.getPropertyValue("bool2"))); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "false"); + assertTrue("Correct bool2 value", Boolean.FALSE.equals(bw.getPropertyValue("bool2"))); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + } + + public void testNumberObjects() { + NumberTestBean tb = new NumberTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + + try { + bw.setPropertyValue("short2", "2"); + bw.setPropertyValue("int2", "8"); + bw.setPropertyValue("long2", "6"); + bw.setPropertyValue("bigInteger", "3"); + bw.setPropertyValue("float2", "8.1"); + bw.setPropertyValue("double2", "6.1"); + bw.setPropertyValue("bigDecimal", "4.0"); + } + catch (BeansException ex) { + fail("Should not throw BeansException: " + ex.getMessage()); + } + + assertTrue("Correct short2 value", new Short("2").equals(bw.getPropertyValue("short2"))); + assertTrue("Correct short2 value", new Short("2").equals(tb.getShort2())); + assertTrue("Correct int2 value", new Integer("8").equals(bw.getPropertyValue("int2"))); + assertTrue("Correct int2 value", new Integer("8").equals(tb.getInt2())); + assertTrue("Correct long2 value", new Long("6").equals(bw.getPropertyValue("long2"))); + assertTrue("Correct long2 value", new Long("6").equals(tb.getLong2())); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(bw.getPropertyValue("bigInteger"))); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(tb.getBigInteger())); + assertTrue("Correct float2 value", new Float("8.1").equals(bw.getPropertyValue("float2"))); + assertTrue("Correct float2 value", new Float("8.1").equals(tb.getFloat2())); + assertTrue("Correct double2 value", new Double("6.1").equals(bw.getPropertyValue("double2"))); + assertTrue("Correct double2 value", new Double("6.1").equals(tb.getDouble2())); + assertTrue("Correct bigDecimal value", new BigDecimal("4.0").equals(bw.getPropertyValue("bigDecimal"))); + assertTrue("Correct bigDecimal value", new BigDecimal("4.0").equals(tb.getBigDecimal())); + } + + public void testNumberCoercion() { + NumberTestBean tb = new NumberTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + + try { + bw.setPropertyValue("short2", new Integer(2)); + bw.setPropertyValue("int2", new Long(8)); + bw.setPropertyValue("long2", new BigInteger("6")); + bw.setPropertyValue("bigInteger", new Integer(3)); + bw.setPropertyValue("float2", new Double(8.1)); + bw.setPropertyValue("double2", new BigDecimal(6.1)); + bw.setPropertyValue("bigDecimal", new Float(4.0)); + } + catch (BeansException ex) { + fail("Should not throw BeansException: " + ex.getMessage()); + } + + assertTrue("Correct short2 value", new Short("2").equals(bw.getPropertyValue("short2"))); + assertTrue("Correct short2 value", new Short("2").equals(tb.getShort2())); + assertTrue("Correct int2 value", new Integer("8").equals(bw.getPropertyValue("int2"))); + assertTrue("Correct int2 value", new Integer("8").equals(tb.getInt2())); + assertTrue("Correct long2 value", new Long("6").equals(bw.getPropertyValue("long2"))); + assertTrue("Correct long2 value", new Long("6").equals(tb.getLong2())); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(bw.getPropertyValue("bigInteger"))); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(tb.getBigInteger())); + assertTrue("Correct float2 value", new Float("8.1").equals(bw.getPropertyValue("float2"))); + assertTrue("Correct float2 value", new Float("8.1").equals(tb.getFloat2())); + assertTrue("Correct double2 value", new Double("6.1").equals(bw.getPropertyValue("double2"))); + assertTrue("Correct double2 value", new Double("6.1").equals(tb.getDouble2())); + assertTrue("Correct bigDecimal value", new BigDecimal("4.0").equals(bw.getPropertyValue("bigDecimal"))); + assertTrue("Correct bigDecimal value", new BigDecimal("4.0").equals(tb.getBigDecimal())); + } + + public void testEnumByFieldName() { + EnumTester et = new EnumTester(); + BeanWrapper bw = new BeanWrapperImpl(et); + + bw.setPropertyValue("flushMode", "NEVER"); + assertEquals(FlushMode.NEVER, et.getFlushMode()); + + bw.setPropertyValue("flushMode", " AUTO "); + assertEquals(FlushMode.AUTO, et.getFlushMode()); + + try { + bw.setPropertyValue("flushMode", "EVER"); + fail("Should have thrown TypeMismatchException"); + } + catch (TypeMismatchException ex) { + // expected + } + } + + public void testPropertiesProperty() throws Exception { + PropsTester pt = new PropsTester(); + BeanWrapper bw = new BeanWrapperImpl(pt); + bw.setPropertyValue("name", "ptest"); + + // Note format... + String ps = "peace=war\nfreedom=slavery"; + bw.setPropertyValue("properties", ps); + + assertTrue("name was set", pt.name.equals("ptest")); + assertTrue("props non null", pt.props != null); + String freedomVal = pt.props.getProperty("freedom"); + String peaceVal = pt.props.getProperty("peace"); + assertTrue("peace==war", peaceVal.equals("war")); + assertTrue("Freedom==slavery", freedomVal.equals("slavery")); + } + + public void testStringArrayProperty() throws Exception { + PropsTester pt = new PropsTester(); + BeanWrapper bw = new BeanWrapperImpl(pt); + + bw.setPropertyValue("stringArray", new String[] {"foo", "fi", "fi", "fum"}); + assertTrue("stringArray length = 4", pt.stringArray.length == 4); + assertTrue("correct values", pt.stringArray[0].equals("foo") && pt.stringArray[1].equals("fi") && + pt.stringArray[2].equals("fi") && pt.stringArray[3].equals("fum")); + + List list = new ArrayList(); + list.add("foo"); + list.add("fi"); + list.add("fi"); + list.add("fum"); + bw.setPropertyValue("stringArray", list); + assertTrue("stringArray length = 4", pt.stringArray.length == 4); + assertTrue("correct values", pt.stringArray[0].equals("foo") && pt.stringArray[1].equals("fi") && + pt.stringArray[2].equals("fi") && pt.stringArray[3].equals("fum")); + + Set set = new HashSet(); + set.add("foo"); + set.add("fi"); + set.add("fum"); + bw.setPropertyValue("stringArray", set); + assertTrue("stringArray length = 3", pt.stringArray.length == 3); + List result = Arrays.asList(pt.stringArray); + assertTrue("correct values", result.contains("foo") && result.contains("fi") && result.contains("fum")); + + bw.setPropertyValue("stringArray", "one"); + assertTrue("stringArray length = 1", pt.stringArray.length == 1); + assertTrue("stringArray elt is ok", pt.stringArray[0].equals("one")); + + bw.setPropertyValue("stringArray", null); + assertTrue("stringArray is null", pt.stringArray == null); + } + + public void testStringArrayPropertyWithCustomStringEditor() throws Exception { + PropsTester pt = new PropsTester(); + BeanWrapper bw = new BeanWrapperImpl(pt); + bw.registerCustomEditor(String.class, "stringArray", new PropertyEditorSupport() { + public void setAsText(String text) { + setValue(text.substring(1)); + } + }); + + bw.setPropertyValue("stringArray", new String[] {"4foo", "7fi", "6fi", "5fum"}); + assertTrue("stringArray length = 4", pt.stringArray.length == 4); + assertTrue("correct values", pt.stringArray[0].equals("foo") && pt.stringArray[1].equals("fi") && + pt.stringArray[2].equals("fi") && pt.stringArray[3].equals("fum")); + + List list = new ArrayList(); + list.add("4foo"); + list.add("7fi"); + list.add("6fi"); + list.add("5fum"); + bw.setPropertyValue("stringArray", list); + assertTrue("stringArray length = 4", pt.stringArray.length == 4); + assertTrue("correct values", pt.stringArray[0].equals("foo") && pt.stringArray[1].equals("fi") && + pt.stringArray[2].equals("fi") && pt.stringArray[3].equals("fum")); + + Set set = new HashSet(); + set.add("4foo"); + set.add("7fi"); + set.add("6fum"); + bw.setPropertyValue("stringArray", set); + assertTrue("stringArray length = 3", pt.stringArray.length == 3); + List result = Arrays.asList(pt.stringArray); + assertTrue("correct values", result.contains("foo") && result.contains("fi") && result.contains("fum")); + + bw.setPropertyValue("stringArray", "8one"); + assertTrue("stringArray length = 1", pt.stringArray.length == 1); + assertTrue("correct values", pt.stringArray[0].equals("one")); + } + + public void testStringArrayPropertyWithStringSplitting() throws Exception { + PropsTester pt = new PropsTester(); + BeanWrapperImpl bw = new BeanWrapperImpl(pt); + bw.useConfigValueEditors(); + bw.setPropertyValue("stringArray", "a1,b2"); + assertTrue("stringArray length = 2", pt.stringArray.length == 2); + assertTrue("correct values", pt.stringArray[0].equals("a1") && pt.stringArray[1].equals("b2")); + } + + public void testStringArrayPropertyWithCustomStringDelimiter() throws Exception { + PropsTester pt = new PropsTester(); + BeanWrapper bw = new BeanWrapperImpl(pt); + bw.registerCustomEditor(String[].class, "stringArray", new StringArrayPropertyEditor("-")); + bw.setPropertyValue("stringArray", "a1-b2"); + assertTrue("stringArray length = 2", pt.stringArray.length == 2); + assertTrue("correct values", pt.stringArray[0].equals("a1") && pt.stringArray[1].equals("b2")); + } + + public void testStringPropertyWithCustomEditor() throws Exception { + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, "name", new PropertyEditorSupport() { + public void setValue(Object value) { + if (value instanceof String[]) { + setValue(StringUtils.arrayToDelimitedString(((String[]) value), "-")); + } + else { + super.setValue(value != null ? value : ""); + } + } + }); + bw.setPropertyValue("name", new String[] {}); + assertEquals("", tb.getName()); + bw.setPropertyValue("name", new String[] {"a1", "b2"}); + assertEquals("a1-b2", tb.getName()); + bw.setPropertyValue("name", null); + assertEquals("", tb.getName()); + } + + public void testIntArrayProperty() { + PropsTester pt = new PropsTester(); + BeanWrapper bw = new BeanWrapperImpl(pt); + + bw.setPropertyValue("intArray", new int[] {4, 5, 2, 3}); + assertTrue("intArray length = 4", pt.intArray.length == 4); + assertTrue("correct values", pt.intArray[0] == 4 && pt.intArray[1] == 5 && + pt.intArray[2] == 2 && pt.intArray[3] == 3); + + bw.setPropertyValue("intArray", new String[] {"4", "5", "2", "3"}); + assertTrue("intArray length = 4", pt.intArray.length == 4); + assertTrue("correct values", pt.intArray[0] == 4 && pt.intArray[1] == 5 && + pt.intArray[2] == 2 && pt.intArray[3] == 3); + + List list = new ArrayList(); + list.add(new Integer(4)); + list.add("5"); + list.add(new Integer(2)); + list.add("3"); + bw.setPropertyValue("intArray", list); + assertTrue("intArray length = 4", pt.intArray.length == 4); + assertTrue("correct values", pt.intArray[0] == 4 && pt.intArray[1] == 5 && + pt.intArray[2] == 2 && pt.intArray[3] == 3); + + Set set = new HashSet(); + set.add("4"); + set.add(new Integer(5)); + set.add("3"); + bw.setPropertyValue("intArray", set); + assertTrue("intArray length = 3", pt.intArray.length == 3); + List result = new ArrayList(); + result.add(new Integer(pt.intArray[0])); + result.add(new Integer(pt.intArray[1])); + result.add(new Integer(pt.intArray[2])); + assertTrue("correct values", result.contains(new Integer(4)) && result.contains(new Integer(5)) && + result.contains(new Integer(3))); + + bw.setPropertyValue("intArray", new Integer[] {new Integer(1)}); + assertTrue("intArray length = 4", pt.intArray.length == 1); + assertTrue("correct values", pt.intArray[0] == 1); + + bw.setPropertyValue("intArray", new Integer(1)); + assertTrue("intArray length = 4", pt.intArray.length == 1); + assertTrue("correct values", pt.intArray[0] == 1); + + bw.setPropertyValue("intArray", new String[] {"1"}); + assertTrue("intArray length = 4", pt.intArray.length == 1); + assertTrue("correct values", pt.intArray[0] == 1); + + bw.setPropertyValue("intArray", "1"); + assertTrue("intArray length = 4", pt.intArray.length == 1); + assertTrue("correct values", pt.intArray[0] == 1); + } + + public void testIntArrayPropertyWithCustomEditor() { + PropsTester pt = new PropsTester(); + BeanWrapper bw = new BeanWrapperImpl(pt); + bw.registerCustomEditor(int.class, new PropertyEditorSupport() { + public void setAsText(String text) { + setValue(new Integer(Integer.parseInt(text) + 1)); + } + }); + + bw.setPropertyValue("intArray", new int[] {4, 5, 2, 3}); + assertTrue("intArray length = 4", pt.intArray.length == 4); + assertTrue("correct values", pt.intArray[0] == 4 && pt.intArray[1] == 5 && + pt.intArray[2] == 2 && pt.intArray[3] == 3); + + bw.setPropertyValue("intArray", new String[] {"3", "4", "1", "2"}); + assertTrue("intArray length = 4", pt.intArray.length == 4); + assertTrue("correct values", pt.intArray[0] == 4 && pt.intArray[1] == 5 && + pt.intArray[2] == 2 && pt.intArray[3] == 3); + + bw.setPropertyValue("intArray", new Integer(1)); + assertTrue("intArray length = 4", pt.intArray.length == 1); + assertTrue("correct values", pt.intArray[0] == 1); + + bw.setPropertyValue("intArray", new String[] {"0"}); + assertTrue("intArray length = 4", pt.intArray.length == 1); + assertTrue("correct values", pt.intArray[0] == 1); + + bw.setPropertyValue("intArray", "0"); + assertTrue("intArray length = 4", pt.intArray.length == 1); + assertTrue("correct values", pt.intArray[0] == 1); + } + + public void testIntArrayPropertyWithStringSplitting() throws Exception { + PropsTester pt = new PropsTester(); + BeanWrapperImpl bw = new BeanWrapperImpl(pt); + bw.useConfigValueEditors(); + bw.setPropertyValue("intArray", "4,5"); + assertTrue("intArray length = 2", pt.intArray.length == 2); + assertTrue("correct values", pt.intArray[0] == 4 && pt.intArray[1] == 5); + } + + public void testIndividualAllValid() { + TestBean t = new TestBean(); + String newName = "tony"; + int newAge = 65; + String newTouchy = "valid"; + try { + BeanWrapper bw = new BeanWrapperImpl(t); + bw.setPropertyValue("age", new Integer(newAge)); + bw.setPropertyValue(new PropertyValue("name", newName)); + bw.setPropertyValue(new PropertyValue("touchy", newTouchy)); + assertTrue("Validly set property must stick", t.getName().equals(newName)); + assertTrue("Validly set property must stick", t.getTouchy().equals(newTouchy)); + assertTrue("Validly set property must stick", t.getAge() == newAge); + } + catch (BeansException ex) { + fail("Shouldn't throw exception when everything is valid"); + } + } + + public void test2Invalid() { + TestBean t = new TestBean(); + String newName = "tony"; + String invalidTouchy = ".valid"; + try { + BeanWrapper bw = new BeanWrapperImpl(t); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("age", "foobar")); + pvs.addPropertyValue(new PropertyValue("name", newName)); + pvs.addPropertyValue(new PropertyValue("touchy", invalidTouchy)); + bw.setPropertyValues(pvs); + fail("Should throw exception when everything is valid"); + } + catch (PropertyBatchUpdateException ex) { + assertTrue("Must contain 2 exceptions", ex.getExceptionCount() == 2); + // Test validly set property matches + assertTrue("Validly set property must stick", t.getName().equals(newName)); + assertTrue("Invalidly set property must retain old value", t.getAge() == 0); + assertTrue("New value of dodgy setter must be available through exception", + ex.getPropertyAccessException("touchy").getPropertyChangeEvent().getNewValue().equals(invalidTouchy)); + } + } + + public void testPossibleMatches() { + TestBean tb = new TestBean(); + try { + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.setPropertyValue("ag", "foobar"); + fail("Should throw exception on invalid property"); + } + catch (NotWritablePropertyException ex) { + // expected + assertEquals(1, ex.getPossibleMatches().length); + assertEquals("age", ex.getPossibleMatches()[0]); + } + } + + public void testTypeMismatch() { + TestBean t = new TestBean(); + try { + BeanWrapper bw = new BeanWrapperImpl(t); + bw.setPropertyValue("age", "foobar"); + fail("Should throw exception on type mismatch"); + } + catch (TypeMismatchException ex) { + // expected + } + } + + public void testEmptyValueForPrimitiveProperty() { + TestBean t = new TestBean(); + try { + BeanWrapper bw = new BeanWrapperImpl(t); + bw.setPropertyValue("age", ""); + fail("Should throw exception on type mismatch"); + } + catch (TypeMismatchException ex) { + // expected + } + catch (Exception ex) { + fail("Shouldn't throw exception other than Type mismatch"); + } + } + + public void testSetPropertyValuesIgnoresInvalidNestedOnRequest() { + ITestBean rod = new TestBean(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("name", "rod")); + pvs.addPropertyValue(new PropertyValue("graceful.rubbish", "tony")); + pvs.addPropertyValue(new PropertyValue("more.garbage", new Object())); + BeanWrapper bw = new BeanWrapperImpl(rod); + bw.setPropertyValues(pvs, true); + assertTrue("Set valid and ignored invalid", rod.getName().equals("rod")); + try { + // Don't ignore: should fail + bw.setPropertyValues(pvs, false); + fail("Shouldn't have ignored invalid updates"); + } + catch (NotWritablePropertyException ex) { + // OK: but which exception?? + } + } + + public void testGetNestedProperty() { + ITestBean rod = new TestBean("rod", 31); + ITestBean kerry = new TestBean("kerry", 35); + rod.setSpouse(kerry); + kerry.setSpouse(rod); + BeanWrapper bw = new BeanWrapperImpl(rod); + Integer KA = (Integer) bw.getPropertyValue("spouse.age"); + assertTrue("kerry is 35", KA.intValue() == 35); + Integer RA = (Integer) bw.getPropertyValue("spouse.spouse.age"); + assertTrue("rod is 31, not" + RA, RA.intValue() == 31); + ITestBean spousesSpouse = (ITestBean) bw.getPropertyValue("spouse.spouse"); + assertTrue("spousesSpouse = initial point", rod == spousesSpouse); + } + + public void testGetNestedPropertyNullValue() throws Exception { + ITestBean rod = new TestBean("rod", 31); + ITestBean kerry = new TestBean("kerry", 35); + rod.setSpouse(kerry); + + BeanWrapper bw = new BeanWrapperImpl(rod); + try { + bw.getPropertyValue("spouse.spouse.age"); + fail("Shouldn't have succeded with null path"); + } + catch (NullValueInNestedPathException ex) { + // ok + assertTrue("it was the spouse.spouse property that was null, not " + ex.getPropertyName(), + ex.getPropertyName().equals("spouse.spouse")); + } + } + + public void testSetNestedProperty() throws Exception { + ITestBean rod = new TestBean("rod", 31); + ITestBean kerry = new TestBean("kerry", 0); + + BeanWrapper bw = new BeanWrapperImpl(rod); + bw.setPropertyValue("spouse", kerry); + + assertTrue("nested set worked", rod.getSpouse() == kerry); + assertTrue("no back relation", kerry.getSpouse() == null); + bw.setPropertyValue(new PropertyValue("spouse.spouse", rod)); + assertTrue("nested set worked", kerry.getSpouse() == rod); + assertTrue("kerry age not set", kerry.getAge() == 0); + bw.setPropertyValue(new PropertyValue("spouse.age", new Integer(35))); + assertTrue("Set primitive on spouse", kerry.getAge() == 35); + + assertEquals(kerry, bw.getPropertyValue("spouse")); + assertEquals(rod, bw.getPropertyValue("spouse.spouse")); + } + + public void testSetNestedPropertyNullValue() throws Exception { + ITestBean rod = new TestBean("rod", 31); + BeanWrapper bw = new BeanWrapperImpl(rod); + try { + bw.setPropertyValue("spouse.age", new Integer(31)); + fail("Shouldn't have succeeded with null path"); + } + catch (NullValueInNestedPathException ex) { + // expected + assertTrue("it was the spouse property that was null, not " + ex.getPropertyName(), + ex.getPropertyName().equals("spouse")); + } + } + + public void testSetNestedPropertyPolymorphic() throws Exception { + ITestBean rod = new TestBean("rod", 31); + ITestBean kerry = new Employee(); + + BeanWrapper bw = new BeanWrapperImpl(rod); + bw.setPropertyValue("spouse", kerry); + bw.setPropertyValue("spouse.age", new Integer(35)); + bw.setPropertyValue("spouse.name", "Kerry"); + bw.setPropertyValue("spouse.company", "Lewisham"); + assertTrue("kerry name is Kerry", kerry.getName().equals("Kerry")); + + assertTrue("nested set worked", rod.getSpouse() == kerry); + assertTrue("no back relation", kerry.getSpouse() == null); + bw.setPropertyValue(new PropertyValue("spouse.spouse", rod)); + assertTrue("nested set worked", kerry.getSpouse() == rod); + + BeanWrapper kbw = new BeanWrapperImpl(kerry); + assertTrue("spouse.spouse.spouse.spouse.company=Lewisham", + "Lewisham".equals(kbw.getPropertyValue("spouse.spouse.spouse.spouse.company"))); + } + + public void testNewWrappedInstancePropertyValuesGet() { + BeanWrapper bw = new BeanWrapperImpl(); + + TestBean t = new TestBean("Tony", 50); + bw.setWrappedInstance(t); + assertEquals("Bean wrapper returns wrong property value", + new Integer(t.getAge()), bw.getPropertyValue("age")); + + TestBean u = new TestBean("Udo", 30); + bw.setWrappedInstance(u); + assertEquals("Bean wrapper returns cached property value", + new Integer(u.getAge()), bw.getPropertyValue("age")); + } + + public void testNewWrappedInstanceNestedPropertyValuesGet() { + BeanWrapper bw = new BeanWrapperImpl(); + + TestBean t = new TestBean("Tony", 50); + t.setSpouse(new TestBean("Sue", 40)); + bw.setWrappedInstance(t); + assertEquals("Bean wrapper returns wrong nested property value", + new Integer(t.getSpouse().getAge()), bw.getPropertyValue("spouse.age")); + + TestBean u = new TestBean("Udo", 30); + u.setSpouse(new TestBean("Vera", 20)); + bw.setWrappedInstance(u); + assertEquals("Bean wrapper returns cached nested property value", + new Integer(u.getSpouse().getAge()), bw.getPropertyValue("spouse.age")); + } + + public void testNullObject() { + try { + new BeanWrapperImpl((Object) null); + fail("Must throw an exception when constructed with null object"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testNestedProperties() { + String doctorCompany = ""; + String lawyerCompany = "Dr. Sueem"; + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.setPropertyValue("doctor.company", doctorCompany); + bw.setPropertyValue("lawyer.company", lawyerCompany); + assertEquals(doctorCompany, tb.getDoctor().getCompany()); + assertEquals(lawyerCompany, tb.getLawyer().getCompany()); + } + + public void testIndexedProperties() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + TestBean tb0 = bean.getArray()[0]; + TestBean tb1 = bean.getArray()[1]; + TestBean tb2 = ((TestBean) bean.getList().get(0)); + TestBean tb3 = ((TestBean) bean.getList().get(1)); + TestBean tb6 = ((TestBean) bean.getSet().toArray()[0]); + TestBean tb7 = ((TestBean) bean.getSet().toArray()[1]); + TestBean tb4 = ((TestBean) bean.getMap().get("key1")); + TestBean tb5 = ((TestBean) bean.getMap().get("key.3")); + assertEquals("name0", tb0.getName()); + assertEquals("name1", tb1.getName()); + assertEquals("name2", tb2.getName()); + assertEquals("name3", tb3.getName()); + assertEquals("name6", tb6.getName()); + assertEquals("name7", tb7.getName()); + assertEquals("name4", tb4.getName()); + assertEquals("name5", tb5.getName()); + assertEquals("name0", bw.getPropertyValue("array[0].name")); + assertEquals("name1", bw.getPropertyValue("array[1].name")); + assertEquals("name2", bw.getPropertyValue("list[0].name")); + assertEquals("name3", bw.getPropertyValue("list[1].name")); + assertEquals("name6", bw.getPropertyValue("set[0].name")); + assertEquals("name7", bw.getPropertyValue("set[1].name")); + assertEquals("name4", bw.getPropertyValue("map[key1].name")); + assertEquals("name5", bw.getPropertyValue("map[key.3].name")); + assertEquals("name4", bw.getPropertyValue("map['key1'].name")); + assertEquals("name5", bw.getPropertyValue("map[\"key.3\"].name")); + assertEquals("nameX", bw.getPropertyValue("map[key4][0].name")); + assertEquals("nameY", bw.getPropertyValue("map[key4][1].name")); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].name", "name5"); + pvs.addPropertyValue("array[1].name", "name4"); + pvs.addPropertyValue("list[0].name", "name3"); + pvs.addPropertyValue("list[1].name", "name2"); + pvs.addPropertyValue("set[0].name", "name8"); + pvs.addPropertyValue("set[1].name", "name9"); + pvs.addPropertyValue("map[key1].name", "name1"); + pvs.addPropertyValue("map['key.3'].name", "name0"); + pvs.addPropertyValue("map[key4][0].name", "nameA"); + pvs.addPropertyValue("map[key4][1].name", "nameB"); + bw.setPropertyValues(pvs); + assertEquals("name5", tb0.getName()); + assertEquals("name4", tb1.getName()); + assertEquals("name3", tb2.getName()); + assertEquals("name2", tb3.getName()); + assertEquals("name1", tb4.getName()); + assertEquals("name0", tb5.getName()); + assertEquals("name5", bw.getPropertyValue("array[0].name")); + assertEquals("name4", bw.getPropertyValue("array[1].name")); + assertEquals("name3", bw.getPropertyValue("list[0].name")); + assertEquals("name2", bw.getPropertyValue("list[1].name")); + assertEquals("name8", bw.getPropertyValue("set[0].name")); + assertEquals("name9", bw.getPropertyValue("set[1].name")); + assertEquals("name1", bw.getPropertyValue("map[\"key1\"].name")); + assertEquals("name0", bw.getPropertyValue("map['key.3'].name")); + assertEquals("nameA", bw.getPropertyValue("map[key4][0].name")); + assertEquals("nameB", bw.getPropertyValue("map[key4][1].name")); + } + + public void testIndexedPropertiesWithDirectAccess() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + TestBean tb0 = bean.getArray()[0]; + TestBean tb1 = bean.getArray()[1]; + TestBean tb2 = ((TestBean) bean.getList().get(0)); + TestBean tb3 = ((TestBean) bean.getList().get(1)); + TestBean tb6 = ((TestBean) bean.getSet().toArray()[0]); + TestBean tb7 = ((TestBean) bean.getSet().toArray()[1]); + TestBean tb4 = ((TestBean) bean.getMap().get("key1")); + TestBean tb5 = ((TestBean) bean.getMap().get("key2")); + assertEquals(tb0, bw.getPropertyValue("array[0]")); + assertEquals(tb1, bw.getPropertyValue("array[1]")); + assertEquals(tb2, bw.getPropertyValue("list[0]")); + assertEquals(tb3, bw.getPropertyValue("list[1]")); + assertEquals(tb6, bw.getPropertyValue("set[0]")); + assertEquals(tb7, bw.getPropertyValue("set[1]")); + assertEquals(tb4, bw.getPropertyValue("map[key1]")); + assertEquals(tb5, bw.getPropertyValue("map[key2]")); + assertEquals(tb4, bw.getPropertyValue("map['key1']")); + assertEquals(tb5, bw.getPropertyValue("map[\"key2\"]")); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0]", tb5); + pvs.addPropertyValue("array[1]", tb4); + pvs.addPropertyValue("list[0]", tb3); + pvs.addPropertyValue("list[1]", tb2); + pvs.addPropertyValue("list[2]", tb0); + pvs.addPropertyValue("list[4]", tb1); + pvs.addPropertyValue("map[key1]", tb1); + pvs.addPropertyValue("map['key2']", tb0); + pvs.addPropertyValue("map[key5]", tb4); + pvs.addPropertyValue("map['key9']", tb5); + bw.setPropertyValues(pvs); + assertEquals(tb5, bean.getArray()[0]); + assertEquals(tb4, bean.getArray()[1]); + assertEquals(tb3, ((TestBean) bean.getList().get(0))); + assertEquals(tb2, ((TestBean) bean.getList().get(1))); + assertEquals(tb0, ((TestBean) bean.getList().get(2))); + assertEquals(null, ((TestBean) bean.getList().get(3))); + assertEquals(tb1, ((TestBean) bean.getList().get(4))); + assertEquals(tb1, ((TestBean) bean.getMap().get("key1"))); + assertEquals(tb0, ((TestBean) bean.getMap().get("key2"))); + assertEquals(tb4, ((TestBean) bean.getMap().get("key5"))); + assertEquals(tb5, ((TestBean) bean.getMap().get("key9"))); + assertEquals(tb5, bw.getPropertyValue("array[0]")); + assertEquals(tb4, bw.getPropertyValue("array[1]")); + assertEquals(tb3, bw.getPropertyValue("list[0]")); + assertEquals(tb2, bw.getPropertyValue("list[1]")); + assertEquals(tb0, bw.getPropertyValue("list[2]")); + assertEquals(null, bw.getPropertyValue("list[3]")); + assertEquals(tb1, bw.getPropertyValue("list[4]")); + assertEquals(tb1, bw.getPropertyValue("map[\"key1\"]")); + assertEquals(tb0, bw.getPropertyValue("map['key2']")); + assertEquals(tb4, bw.getPropertyValue("map[\"key5\"]")); + assertEquals(tb5, bw.getPropertyValue("map['key9']")); + } + + public void testMapAccessWithTypeConversion() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(TestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + if (!StringUtils.hasLength(text)) { + throw new IllegalArgumentException(); + } + setValue(new TestBean(text)); + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("map[key1]", "rod"); + pvs.addPropertyValue("map[key2]", "rob"); + bw.setPropertyValues(pvs); + assertEquals("rod", ((TestBean) bean.getMap().get("key1")).getName()); + assertEquals("rob", ((TestBean) bean.getMap().get("key2")).getName()); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("map[key1]", "rod"); + pvs.addPropertyValue("map[key2]", ""); + try { + bw.setPropertyValues(pvs); + fail("Should have thrown TypeMismatchException"); + } + catch (PropertyBatchUpdateException ex) { + PropertyAccessException pae = ex.getPropertyAccessException("map[key2]"); + assertTrue(pae instanceof TypeMismatchException); + } + } + + public void testMapAccessWithUnmodifiableMap() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(TestBean.class, "map", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + if (!StringUtils.hasLength(text)) { + throw new IllegalArgumentException(); + } + setValue(new TestBean(text)); + } + }); + + Map inputMap = new HashMap(); + inputMap.put(new Integer(1), "rod"); + inputMap.put(new Integer(2), "rob"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("map", Collections.unmodifiableMap(inputMap)); + bw.setPropertyValues(pvs); + assertEquals("rod", ((TestBean) bean.getMap().get(new Integer(1))).getName()); + assertEquals("rob", ((TestBean) bean.getMap().get(new Integer(2))).getName()); + } + + public void testMapAccessWithCustomUnmodifiableMap() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(TestBean.class, "map", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + if (!StringUtils.hasLength(text)) { + throw new IllegalArgumentException(); + } + setValue(new TestBean(text)); + } + }); + + Map inputMap = new HashMap(); + inputMap.put(new Integer(1), "rod"); + inputMap.put(new Integer(2), "rob"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("map", new ReadOnlyMap(inputMap)); + bw.setPropertyValues(pvs); + assertEquals("rod", ((TestBean) bean.getMap().get(new Integer(1))).getName()); + assertEquals("rob", ((TestBean) bean.getMap().get(new Integer(2))).getName()); + } + + public void testRawMapAccessWithNoEditorRegistered() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + Map inputMap = new HashMap(); + inputMap.put(new Integer(1), "rod"); + inputMap.put(new Integer(2), "rob"); + ReadOnlyMap readOnlyMap = new ReadOnlyMap(inputMap); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("map", readOnlyMap); + bw.setPropertyValues(pvs); + assertSame(readOnlyMap, bean.getMap()); + assertFalse(readOnlyMap.isAccessed()); + } + + public void testPrimitiveArray() { + PrimitiveArrayBean tb = new PrimitiveArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.setPropertyValue("array", new String[] {"1", "2"}); + assertEquals(2, tb.getArray().length); + assertEquals(1, tb.getArray()[0]); + assertEquals(2, tb.getArray()[1]); + } + + public void testLargeMatchingPrimitiveArray() { + if (LogFactory.getLog(BeanWrapperTests.class).isTraceEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + + PrimitiveArrayBean tb = new PrimitiveArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + int[] input = new int[1024]; + StopWatch sw = new StopWatch(); + sw.start("array1"); + for (int i = 0; i < 1000; i++) { + bw.setPropertyValue("array", input); + } + sw.stop(); + assertEquals(1024, tb.getArray().length); + assertEquals(0, tb.getArray()[0]); + long time1 = sw.getLastTaskTimeMillis(); + assertTrue("Took too long", sw.getLastTaskTimeMillis() < 100); + + bw.registerCustomEditor(String.class, new StringTrimmerEditor(false)); + sw.start("array2"); + for (int i = 0; i < 1000; i++) { + bw.setPropertyValue("array", input); + } + sw.stop(); + assertTrue("Took too long", sw.getLastTaskTimeMillis() < 100); + + bw.registerCustomEditor(int.class, "array.somePath", new CustomNumberEditor(Integer.class, false)); + sw.start("array3"); + for (int i = 0; i < 1000; i++) { + bw.setPropertyValue("array", input); + } + sw.stop(); + assertTrue("Took too long", sw.getLastTaskTimeMillis() < 100); + + bw.registerCustomEditor(int.class, "array[0].somePath", new CustomNumberEditor(Integer.class, false)); + sw.start("array3"); + for (int i = 0; i < 1000; i++) { + bw.setPropertyValue("array", input); + } + sw.stop(); + assertTrue("Took too long", sw.getLastTaskTimeMillis() < 100); + + bw.registerCustomEditor(int.class, new CustomNumberEditor(Integer.class, false)); + sw.start("array4"); + for (int i = 0; i < 100; i++) { + bw.setPropertyValue("array", input); + } + sw.stop(); + assertEquals(1024, tb.getArray().length); + assertEquals(0, tb.getArray()[0]); + assertTrue("Took too long", sw.getLastTaskTimeMillis() > time1); + } + + public void testLargeMatchingPrimitiveArrayWithSpecificEditor() { + PrimitiveArrayBean tb = new PrimitiveArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(int.class, "array", new PropertyEditorSupport() { + public void setValue(Object value) { + if (value instanceof Integer) { + super.setValue(new Integer(((Integer) value).intValue() + 1)); + } + } + }); + int[] input = new int[1024]; + bw.setPropertyValue("array", input); + assertEquals(1024, tb.getArray().length); + assertEquals(1, tb.getArray()[0]); + assertEquals(1, tb.getArray()[1]); + } + + public void testLargeMatchingPrimitiveArrayWithIndexSpecificEditor() { + PrimitiveArrayBean tb = new PrimitiveArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(int.class, "array[1]", new PropertyEditorSupport() { + public void setValue(Object value) { + if (value instanceof Integer) { + super.setValue(new Integer(((Integer) value).intValue() + 1)); + } + } + }); + int[] input = new int[1024]; + bw.setPropertyValue("array", input); + assertEquals(1024, tb.getArray().length); + assertEquals(0, tb.getArray()[0]); + assertEquals(1, tb.getArray()[1]); + } + + public void testPropertiesInProtectedBaseBean() { + DerivedFromProtectedBaseBean bean = new DerivedFromProtectedBaseBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.setPropertyValue("someProperty", "someValue"); + assertEquals("someValue", bw.getPropertyValue("someProperty")); + assertEquals("someValue", bean.getSomeProperty()); + } + + public void testErrorMessageOfNestedProperty() { + ITestBean parent = new TestBean(); + ITestBean child = new DifferentTestBean(); + child.setName("test"); + parent.setSpouse(child); + BeanWrapper bw = new BeanWrapperImpl(parent); + try { + bw.getPropertyValue("spouse.bla"); + } + catch (NotReadablePropertyException ex) { + assertTrue(ex.getMessage().indexOf(TestBean.class.getName()) != -1); + } + } + + public void testMatchingCollections() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + Collection coll = new HashSet(); + coll.add("coll1"); + bw.setPropertyValue("collection", coll); + Set set = new HashSet(); + set.add("set1"); + bw.setPropertyValue("set", set); + SortedSet sortedSet = new TreeSet(); + sortedSet.add("sortedSet1"); + bw.setPropertyValue("sortedSet", sortedSet); + List list = new LinkedList(); + list.add("list1"); + bw.setPropertyValue("list", list); + assertSame(coll, tb.getCollection()); + assertSame(set, tb.getSet()); + assertSame(sortedSet, tb.getSortedSet()); + assertSame(list, tb.getList()); + } + + public void testNonMatchingCollections() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + Collection coll = new ArrayList(); + coll.add("coll1"); + bw.setPropertyValue("collection", coll); + List set = new LinkedList(); + set.add("set1"); + bw.setPropertyValue("set", set); + List sortedSet = new ArrayList(); + sortedSet.add("sortedSet1"); + bw.setPropertyValue("sortedSet", sortedSet); + Set list = new HashSet(); + list.add("list1"); + bw.setPropertyValue("list", list); + assertEquals(1, tb.getCollection().size()); + assertTrue(tb.getCollection().containsAll(coll)); + assertEquals(1, tb.getSet().size()); + assertTrue(tb.getSet().containsAll(set)); + assertEquals(1, tb.getSortedSet().size()); + assertTrue(tb.getSortedSet().containsAll(sortedSet)); + assertEquals(1, tb.getList().size()); + assertTrue(tb.getList().containsAll(list)); + } + + public void testCollectionsWithArrayValues() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + Collection coll = new HashSet(); + coll.add("coll1"); + bw.setPropertyValue("collection", coll.toArray()); + List set = new LinkedList(); + set.add("set1"); + bw.setPropertyValue("set", set.toArray()); + List sortedSet = new ArrayList(); + sortedSet.add("sortedSet1"); + bw.setPropertyValue("sortedSet", sortedSet.toArray()); + Set list = new HashSet(); + list.add("list1"); + bw.setPropertyValue("list", list.toArray()); + assertEquals(1, tb.getCollection().size()); + assertTrue(tb.getCollection().containsAll(coll)); + assertEquals(1, tb.getSet().size()); + assertTrue(tb.getSet().containsAll(set)); + assertEquals(1, tb.getSortedSet().size()); + assertTrue(tb.getSortedSet().containsAll(sortedSet)); + assertEquals(1, tb.getList().size()); + assertTrue(tb.getList().containsAll(list)); + } + + public void testCollectionsWithIntArrayValues() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + Collection coll = new HashSet(); + coll.add(new Integer(0)); + bw.setPropertyValue("collection", new int[] {0}); + List set = new LinkedList(); + set.add(new Integer(1)); + bw.setPropertyValue("set", new int[] {1}); + List sortedSet = new ArrayList(); + sortedSet.add(new Integer(2)); + bw.setPropertyValue("sortedSet", new int[] {2}); + Set list = new HashSet(); + list.add(new Integer(3)); + bw.setPropertyValue("list", new int[] {3}); + assertEquals(1, tb.getCollection().size()); + assertTrue(tb.getCollection().containsAll(coll)); + assertEquals(1, tb.getSet().size()); + assertTrue(tb.getSet().containsAll(set)); + assertEquals(1, tb.getSortedSet().size()); + assertTrue(tb.getSortedSet().containsAll(sortedSet)); + assertEquals(1, tb.getList().size()); + assertTrue(tb.getList().containsAll(list)); + } + + public void testCollectionsWithIntegerValues() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + Collection coll = new HashSet(); + coll.add(new Integer(0)); + bw.setPropertyValue("collection", new Integer(0)); + List set = new LinkedList(); + set.add(new Integer(1)); + bw.setPropertyValue("set", new Integer(1)); + List sortedSet = new ArrayList(); + sortedSet.add(new Integer(2)); + bw.setPropertyValue("sortedSet", new Integer(2)); + Set list = new HashSet(); + list.add(new Integer(3)); + bw.setPropertyValue("list", new Integer(3)); + assertEquals(1, tb.getCollection().size()); + assertTrue(tb.getCollection().containsAll(coll)); + assertEquals(1, tb.getSet().size()); + assertTrue(tb.getSet().containsAll(set)); + assertEquals(1, tb.getSortedSet().size()); + assertTrue(tb.getSortedSet().containsAll(sortedSet)); + assertEquals(1, tb.getList().size()); + assertTrue(tb.getList().containsAll(list)); + } + + public void testCollectionsWithStringValues() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + List set = new LinkedList(); + set.add("set1"); + bw.setPropertyValue("set", "set1"); + List sortedSet = new ArrayList(); + sortedSet.add("sortedSet1"); + bw.setPropertyValue("sortedSet", "sortedSet1"); + Set list = new HashSet(); + list.add("list1"); + bw.setPropertyValue("list", "list1"); + assertEquals(1, tb.getSet().size()); + assertTrue(tb.getSet().containsAll(set)); + assertEquals(1, tb.getSortedSet().size()); + assertTrue(tb.getSortedSet().containsAll(sortedSet)); + assertEquals(1, tb.getList().size()); + assertTrue(tb.getList().containsAll(list)); + } + + public void testCollectionsWithStringValuesAndCustomEditor() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, "set", new StringTrimmerEditor(false)); + bw.registerCustomEditor(String.class, "list", new StringTrimmerEditor(false)); + + bw.setPropertyValue("set", "set1 "); + bw.setPropertyValue("sortedSet", "sortedSet1"); + bw.setPropertyValue("list", "list1 "); + assertEquals(1, tb.getSet().size()); + assertTrue(tb.getSet().contains("set1")); + assertEquals(1, tb.getSortedSet().size()); + assertTrue(tb.getSortedSet().contains("sortedSet1")); + assertEquals(1, tb.getList().size()); + assertTrue(tb.getList().contains("list1")); + + bw.setPropertyValue("list", Arrays.asList(new String[] {"list1 "})); + assertTrue(tb.getList().contains("list1")); + } + + public void testMatchingMaps() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + Map map = new HashMap(); + map.put("key", "value"); + bw.setPropertyValue("map", map); + SortedMap sortedMap = new TreeMap(); + map.put("sortedKey", "sortedValue"); + bw.setPropertyValue("sortedMap", sortedMap); + assertSame(map, tb.getMap()); + assertSame(sortedMap, tb.getSortedMap()); + } + + public void testNonMatchingMaps() { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + Map map = new TreeMap(); + map.put("key", "value"); + bw.setPropertyValue("map", map); + Map sortedMap = new HashMap(); + sortedMap.put("sortedKey", "sortedValue"); + bw.setPropertyValue("sortedMap", sortedMap); + assertEquals(1, tb.getMap().size()); + assertEquals("value", tb.getMap().get("key")); + assertEquals(1, tb.getSortedMap().size()); + assertEquals("sortedValue", tb.getSortedMap().get("sortedKey")); + } + + public void testSetNumberProperties() { + NumberPropertyBean bean = new NumberPropertyBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + + String byteValue = " " + Byte.MAX_VALUE + " "; + String shortValue = " " + Short.MAX_VALUE + " "; + String intValue = " " + Integer.MAX_VALUE + " "; + String longValue = " " + Long.MAX_VALUE + " "; + String floatValue = " " + Float.MAX_VALUE + " "; + String doubleValue = " " + Double.MAX_VALUE + " "; + + bw.setPropertyValue("myPrimitiveByte", byteValue); + bw.setPropertyValue("myByte", byteValue); + + bw.setPropertyValue("myPrimitiveShort", shortValue); + bw.setPropertyValue("myShort", shortValue); + + bw.setPropertyValue("myPrimitiveInt", intValue); + bw.setPropertyValue("myInteger", intValue); + + bw.setPropertyValue("myPrimitiveLong", longValue); + bw.setPropertyValue("myLong", longValue); + + bw.setPropertyValue("myPrimitiveFloat", floatValue); + bw.setPropertyValue("myFloat", floatValue); + + bw.setPropertyValue("myPrimitiveDouble", doubleValue); + bw.setPropertyValue("myDouble", doubleValue); + + assertEquals(Byte.MAX_VALUE, bean.getMyPrimitiveByte()); + assertEquals(Byte.MAX_VALUE, bean.getMyByte().byteValue()); + + assertEquals(Short.MAX_VALUE, bean.getMyPrimitiveShort()); + assertEquals(Short.MAX_VALUE, bean.getMyShort().shortValue()); + + assertEquals(Integer.MAX_VALUE, bean.getMyPrimitiveInt()); + assertEquals(Integer.MAX_VALUE, bean.getMyInteger().intValue()); + + assertEquals(Long.MAX_VALUE, bean.getMyPrimitiveLong()); + assertEquals(Long.MAX_VALUE, bean.getMyLong().longValue()); + + assertEquals(Float.MAX_VALUE, bean.getMyPrimitiveFloat(), 0.001); + assertEquals(Float.MAX_VALUE, bean.getMyFloat().floatValue(), 0.001); + + assertEquals(Double.MAX_VALUE, bean.getMyPrimitiveDouble(), 0.001); + assertEquals(Double.MAX_VALUE, bean.getMyDouble().doubleValue(), 0.001); + + } + + public void testAlternativesForTypo() { + IntelliBean ib = new IntelliBean(); + BeanWrapper bw = new BeanWrapperImpl(ib); + try { + bw.setPropertyValue("names", "Alef"); + } + catch (NotWritablePropertyException ex) { + assertNotNull("Possible matches not determined", ex.getPossibleMatches()); + assertEquals("Invalid amount of alternatives", 1, ex.getPossibleMatches().length); + } + } + + public void testAlternativesForTypos() { + IntelliBean ib = new IntelliBean(); + BeanWrapper bw = new BeanWrapperImpl(ib); + try { + bw.setPropertyValue("mystring", "Arjen"); + } + catch (NotWritablePropertyException ex) { + assertNotNull("Possible matches not determined", ex.getPossibleMatches()); + assertEquals("Invalid amount of alternatives", 3, ex.getPossibleMatches().length); + } + } + + + private static class DifferentTestBean extends TestBean { + // class to test naming of beans in a BeanWrapper error message + } + + + private static class NoRead { + + public void setAge(int age) { + } + } + + + private static class EnumTester { + + private FlushMode flushMode; + + public void setFlushMode(FlushMode flushMode) { + this.flushMode = flushMode; + } + + public FlushMode getFlushMode() { + return flushMode; + } + } + + + private static class PropsTester { + + private Properties props; + + private String name; + + private String[] stringArray; + + private int[] intArray; + + public void setProperties(Properties p) { + props = p; + } + + public void setName(String name) { + this.name = name; + } + + public void setStringArray(String[] sa) { + this.stringArray = sa; + } + + public void setIntArray(int[] intArray) { + this.intArray = intArray; + } + } + + + private static class GetterBean { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + if (this.name == null) { + throw new RuntimeException("name property must be set"); + } + return name; + } + } + + + private static class ThrowsException { + + public void doSomething(Throwable t) throws Throwable { + throw t; + } + } + + + private static class PrimitiveArrayBean { + + private int[] array; + + public int[] getArray() { + return array; + } + + public void setArray(int[] array) { + this.array = array; + } + } + + + private static class NumberPropertyBean { + + private byte myPrimitiveByte; + private Byte myByte; + + private short myPrimitiveShort; + private Short myShort; + + private int myPrimitiveInt; + private Integer myInteger; + + private long myPrimitiveLong; + private Long myLong; + + private float myPrimitiveFloat; + private Float myFloat; + + private double myPrimitiveDouble; + private Double myDouble; + + public byte getMyPrimitiveByte() { + return myPrimitiveByte; + } + + public void setMyPrimitiveByte(byte myPrimitiveByte) { + this.myPrimitiveByte = myPrimitiveByte; + } + + public Byte getMyByte() { + return myByte; + } + + public void setMyByte(Byte myByte) { + this.myByte = myByte; + } + + public short getMyPrimitiveShort() { + return myPrimitiveShort; + } + + public void setMyPrimitiveShort(short myPrimitiveShort) { + this.myPrimitiveShort = myPrimitiveShort; + } + + public Short getMyShort() { + return myShort; + } + + public void setMyShort(Short myShort) { + this.myShort = myShort; + } + + public int getMyPrimitiveInt() { + return myPrimitiveInt; + } + + public void setMyPrimitiveInt(int myPrimitiveInt) { + this.myPrimitiveInt = myPrimitiveInt; + } + + public Integer getMyInteger() { + return myInteger; + } + + public void setMyInteger(Integer myInteger) { + this.myInteger = myInteger; + } + + public long getMyPrimitiveLong() { + return myPrimitiveLong; + } + + public void setMyPrimitiveLong(long myPrimitiveLong) { + this.myPrimitiveLong = myPrimitiveLong; + } + + public Long getMyLong() { + return myLong; + } + + public void setMyLong(Long myLong) { + this.myLong = myLong; + } + + public float getMyPrimitiveFloat() { + return myPrimitiveFloat; + } + + public void setMyPrimitiveFloat(float myPrimitiveFloat) { + this.myPrimitiveFloat = myPrimitiveFloat; + } + + public Float getMyFloat() { + return myFloat; + } + + public void setMyFloat(Float myFloat) { + this.myFloat = myFloat; + } + + public double getMyPrimitiveDouble() { + return myPrimitiveDouble; + } + + public void setMyPrimitiveDouble(double myPrimitiveDouble) { + this.myPrimitiveDouble = myPrimitiveDouble; + } + + public Double getMyDouble() { + return myDouble; + } + + public void setMyDouble(Double myDouble) { + this.myDouble = myDouble; + } + } + + + private static class IntelliBean { + + public void setName(String name) {} + + public void setMyString(String string) {} + + public void setMyStrings(String string) {} + + public void setMyStriNg(String string) {} + + public void setMyStringss(String string) {} + } + + + public static class ReadOnlyMap extends HashMap { + + private boolean frozen = false; + + private boolean accessed = false; + + public ReadOnlyMap() { + this.frozen = true; + } + + public ReadOnlyMap(Map map) { + super(map); + this.frozen = true; + } + + public Object put(Object key, Object value) { + if (this.frozen) { + throw new UnsupportedOperationException(); + } + else { + return super.put(key, value); + } + } + + public Set entrySet() { + this.accessed = true; + return super.entrySet(); + } + + public Set keySet() { + this.accessed = true; + return super.keySet(); + } + + public int size() { + this.accessed = true; + return super.size(); + } + + public boolean isAccessed() { + return this.accessed; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/BooleanTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/BooleanTestBean.java new file mode 100644 index 00000000000..608fb109eea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/BooleanTestBean.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * @author Juergen Hoeller + * @since 10.06.2003 + */ +public class BooleanTestBean { + + private boolean bool1; + + private Boolean bool2; + + public boolean isBool1() { + return bool1; + } + + public void setBool1(boolean bool1) { + this.bool1 = bool1; + } + + public Boolean getBool2() { + return bool2; + } + + public void setBool2(Boolean bool2) { + this.bool2 = bool2; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java new file mode 100644 index 00000000000..09db3bb2ce6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import junit.framework.TestCase; + +import org.springframework.core.OverridingClassLoader; + +/** + * @author Juergen Hoeller + */ +public class CachedIntrospectionResultsTests extends TestCase { + + public void testAcceptClassLoader() throws Exception { + BeanWrapper bw = new BeanWrapperImpl(TestBean.class); + assertTrue(bw.isWritableProperty("name")); + assertTrue(bw.isWritableProperty("age")); + assertTrue(CachedIntrospectionResults.classCache.containsKey(TestBean.class)); + + ClassLoader child = new OverridingClassLoader(getClass().getClassLoader()); + Class tbClass = child.loadClass("org.springframework.beans.TestBean"); + assertFalse(CachedIntrospectionResults.classCache.containsKey(tbClass)); + CachedIntrospectionResults.acceptClassLoader(child); + bw = new BeanWrapperImpl(tbClass); + assertTrue(bw.isWritableProperty("name")); + assertTrue(bw.isWritableProperty("age")); + assertTrue(CachedIntrospectionResults.classCache.containsKey(tbClass)); + CachedIntrospectionResults.clearClassLoader(child); + assertFalse(CachedIntrospectionResults.classCache.containsKey(tbClass)); + + assertTrue(CachedIntrospectionResults.classCache.containsKey(TestBean.class)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/Colour.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/Colour.java new file mode 100644 index 00000000000..4db722187d9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/Colour.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import org.springframework.core.enums.ShortCodedLabeledEnum; + +/** + * @author Rob Harrop + */ +public class Colour extends ShortCodedLabeledEnum { + + public static final Colour RED = new Colour(0, "RED"); + public static final Colour BLUE = new Colour(1, "BLUE"); + public static final Colour GREEN = new Colour(2, "GREEN"); + public static final Colour PURPLE = new Colour(3, "PURPLE"); + + private Colour(int code, String label) { + super(code, label); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/ConcurrentBeanWrapperTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/ConcurrentBeanWrapperTests.java new file mode 100644 index 00000000000..028f79e46c3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/ConcurrentBeanWrapperTests.java @@ -0,0 +1,145 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Properties; +import java.util.Set; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author Guillaume Poirier + * @author Juergen Hoeller + * @since 08.03.2004 + */ +public class ConcurrentBeanWrapperTests extends TestCase { + + private final Log logger = LogFactory.getLog(getClass()); + + private Set set = Collections.synchronizedSet(new HashSet()); + + private Throwable ex = null; + + public void testSingleThread() { + for (int i = 0; i < 100; i++) { + performSet(); + } + } + + public void testConcurrent() { + for (int i = 0; i < 10; i++) { + TestRun run = new TestRun(this); + set.add(run); + Thread t = new Thread(run); + t.setDaemon(true); + t.start(); + } + logger.info("Thread creation over, " + set.size() + " still active."); + synchronized (this) { + while (!set.isEmpty() && ex == null) { + try { + wait(); + } + catch (InterruptedException e) { + logger.info(e.toString()); + } + logger.info(set.size() + " threads still active."); + } + } + if (ex != null) { + fail(ex.getMessage()); + } + } + + private static void performSet() { + TestBean bean = new TestBean(); + + Properties p = (Properties) System.getProperties().clone(); + + assertTrue("The System properties must not be empty", p.size() != 0); + + for (Iterator i = p.entrySet().iterator(); i.hasNext();) { + i.next(); + if (Math.random() > 0.9) { + i.remove(); + } + } + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + try { + p.store(buffer, null); + } + catch (IOException e) { + // ByteArrayOutputStream does not throw + // any IOException + } + String value = new String(buffer.toByteArray()); + + BeanWrapperImpl wrapper = new BeanWrapperImpl(bean); + wrapper.setPropertyValue("properties", value); + assertEquals(p, bean.getProperties()); + } + + + private static class TestRun implements Runnable { + + private ConcurrentBeanWrapperTests test; + + public TestRun(ConcurrentBeanWrapperTests test) { + this.test = test; + } + + public void run() { + try { + for (int i = 0; i < 100; i++) { + performSet(); + } + } + catch (Throwable e) { + test.ex = e; + } + finally { + synchronized (test) { + test.set.remove(this); + test.notifyAll(); + } + } + } + } + + + private static class TestBean { + + private Properties properties; + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/DerivedTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/DerivedTestBean.java new file mode 100644 index 00000000000..db326041c36 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/DerivedTestBean.java @@ -0,0 +1,85 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.Serializable; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; + +/** + * @author Juergen Hoeller + * @since 21.08.2003 + */ +public class DerivedTestBean extends TestBean implements Serializable, BeanNameAware, DisposableBean { + + private String beanName; + + private boolean initialized; + + private boolean destroyed; + + + public DerivedTestBean() { + } + + public DerivedTestBean(String[] names) { + if (names == null || names.length < 2) { + throw new IllegalArgumentException("Invalid names array"); + } + setName(names[0]); + setBeanName(names[1]); + } + + public static DerivedTestBean create(String[] names) { + return new DerivedTestBean(names); + } + + + public void setBeanName(String beanName) { + if (this.beanName == null || beanName == null) { + this.beanName = beanName; + } + } + + public String getBeanName() { + return beanName; + } + + public void setSpouseRef(String name) { + setSpouse(new TestBean(name)); + } + + + public void initialize() { + this.initialized = true; + } + + public boolean wasInitialized() { + return initialized; + } + + + public void destroy() { + this.destroyed = true; + } + + public boolean wasDestroyed() { + return destroyed; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/Employee.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/Employee.java new file mode 100644 index 00000000000..923c0041087 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/Employee.java @@ -0,0 +1,39 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +public class Employee extends TestBean { + + private String co; + + /** + * Constructor for Employee. + */ + public Employee() { + super(); + } + + public String getCompany() { + return co; + } + + public void setCompany(String co) { + this.co = co; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/FieldAccessBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/FieldAccessBean.java new file mode 100644 index 00000000000..f367fb5d6e3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/FieldAccessBean.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * @author Juergen Hoeller + * @since 07.03.2006 + */ +public class FieldAccessBean { + + public String name; + + protected int age; + + private TestBean spouse; + + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public TestBean getSpouse() { + return spouse; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/INestedTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/INestedTestBean.java new file mode 100644 index 00000000000..e9d9c581bb4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/INestedTestBean.java @@ -0,0 +1,23 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +public interface INestedTestBean { + + public String getCompany(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/IOther.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/IOther.java new file mode 100644 index 00000000000..41f657082c4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/IOther.java @@ -0,0 +1,24 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +public interface IOther { + + void absquatulate(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/ITestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/ITestBean.java new file mode 100644 index 00000000000..2efb9b7be1b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/ITestBean.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.IOException; + +/** + * Interface used for {@link TestBean}. + * + *

Two methods are the same as on Person, but if this + * extends person it breaks quite a few tests.. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public interface ITestBean { + + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + + ITestBean getSpouse(); + + void setSpouse(ITestBean spouse); + + ITestBean[] getSpouses(); + + String[] getStringArray(); + + void setStringArray(String[] stringArray); + + /** + * Throws a given (non-null) exception. + */ + void exceptional(Throwable t) throws Throwable; + + Object returnsThis(); + + INestedTestBean getDoctor(); + + INestedTestBean getLawyer(); + + IndexedTestBean getNestedIndexedBean(); + + /** + * Increment the age by one. + * @return the previous age + */ + int haveBirthday(); + + void unreliableFileOperation() throws IOException; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/IndexedTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/IndexedTestBean.java new file mode 100644 index 00000000000..4f3012666ea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/IndexedTestBean.java @@ -0,0 +1,145 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * @author Juergen Hoeller + * @since 11.11.2003 + */ +public class IndexedTestBean { + + private TestBean[] array; + + private Collection collection; + + private List list; + + private Set set; + + private SortedSet sortedSet; + + private Map map; + + private SortedMap sortedMap; + + + public IndexedTestBean() { + this(true); + } + + public IndexedTestBean(boolean populate) { + if (populate) { + populate(); + } + } + + public void populate() { + TestBean tb0 = new TestBean("name0", 0); + TestBean tb1 = new TestBean("name1", 0); + TestBean tb2 = new TestBean("name2", 0); + TestBean tb3 = new TestBean("name3", 0); + TestBean tb4 = new TestBean("name4", 0); + TestBean tb5 = new TestBean("name5", 0); + TestBean tb6 = new TestBean("name6", 0); + TestBean tb7 = new TestBean("name7", 0); + TestBean tbX = new TestBean("nameX", 0); + TestBean tbY = new TestBean("nameY", 0); + this.array = new TestBean[] {tb0, tb1}; + this.list = new ArrayList(); + this.list.add(tb2); + this.list.add(tb3); + this.set = new TreeSet(); + this.set.add(tb6); + this.set.add(tb7); + this.map = new HashMap(); + this.map.put("key1", tb4); + this.map.put("key2", tb5); + this.map.put("key.3", tb5); + List list = new ArrayList(); + list.add(tbX); + list.add(tbY); + this.map.put("key4", list); + } + + + public TestBean[] getArray() { + return array; + } + + public void setArray(TestBean[] array) { + this.array = array; + } + + public Collection getCollection() { + return collection; + } + + public void setCollection(Collection collection) { + this.collection = collection; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public Set getSet() { + return set; + } + + public void setSet(Set set) { + this.set = set; + } + + public SortedSet getSortedSet() { + return sortedSet; + } + + public void setSortedSet(SortedSet sortedSet) { + this.sortedSet = sortedSet; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public SortedMap getSortedMap() { + return sortedMap; + } + + public void setSortedMap(SortedMap sortedMap) { + this.sortedMap = sortedMap; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java new file mode 100644 index 00000000000..c6fa04227a4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * Tests for MutablePropertyValues. + * + * @author Rod Johnson + */ +public class MutablePropertyValuesTests extends AbstractPropertyValuesTests { + + public void testValid() throws Exception { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("forname", "Tony")); + pvs.addPropertyValue(new PropertyValue("surname", "Blair")); + pvs.addPropertyValue(new PropertyValue("age", "50")); + doTestTony(pvs); + + MutablePropertyValues deepCopy = new MutablePropertyValues(pvs); + doTestTony(deepCopy); + deepCopy.setPropertyValueAt(new PropertyValue("name", "Gordon"), 0); + doTestTony(pvs); + assertEquals("Gordon", deepCopy.getPropertyValue("name").getValue()); + } + + public void addOrOverride() throws Exception { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("forname", "Tony")); + pvs.addPropertyValue(new PropertyValue("surname", "Blair")); + pvs.addPropertyValue(new PropertyValue("age", "50")); + doTestTony(pvs); + PropertyValue addedPv = new PropertyValue("rod", "Rod"); + pvs.addPropertyValue(addedPv); + assertTrue(pvs.getPropertyValue("rod").equals(addedPv)); + PropertyValue changedPv = new PropertyValue("forname", "Greg"); + pvs.addPropertyValue(changedPv); + assertTrue(pvs.getPropertyValue("forename").equals(changedPv)); + } + + public void testChangesOnEquals() throws Exception { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("forname", "Tony")); + pvs.addPropertyValue(new PropertyValue("surname", "Blair")); + pvs.addPropertyValue(new PropertyValue("age", "50")); + MutablePropertyValues pvs2 = pvs; + PropertyValues changes = pvs2.changesSince(pvs); + assertTrue("changes are empty", changes.getPropertyValues().length == 0); + } + + public void testChangeOfOneField() throws Exception { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("forname", "Tony")); + pvs.addPropertyValue(new PropertyValue("surname", "Blair")); + pvs.addPropertyValue(new PropertyValue("age", "50")); + + MutablePropertyValues pvs2 = new MutablePropertyValues(pvs); + PropertyValues changes = pvs2.changesSince(pvs); + assertTrue("changes are empty, not of length " + changes.getPropertyValues().length, + changes.getPropertyValues().length == 0); + + pvs2.addPropertyValue(new PropertyValue("forname", "Gordon")); + changes = pvs2.changesSince(pvs); + assertEquals("1 change", 1, changes.getPropertyValues().length); + PropertyValue fn = changes.getPropertyValue("forname"); + assertTrue("change is forname", fn != null); + assertTrue("new value is gordon", fn.getValue().equals("Gordon")); + + MutablePropertyValues pvs3 = new MutablePropertyValues(pvs); + changes = pvs3.changesSince(pvs); + assertTrue("changes are empty, not of length " + changes.getPropertyValues().length, + changes.getPropertyValues().length == 0); + + // add new + pvs3.addPropertyValue(new PropertyValue("foo", "bar")); + pvs3.addPropertyValue(new PropertyValue("fi", "fum")); + changes = pvs3.changesSince(pvs); + assertTrue("2 change", changes.getPropertyValues().length == 2); + fn = changes.getPropertyValue("foo"); + assertTrue("change in foo", fn != null); + assertTrue("new value is bar", fn.getValue().equals("bar")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/NestedTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/NestedTestBean.java new file mode 100644 index 00000000000..6b545416234 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/NestedTestBean.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * Simple nested test bean used for testing bean factories, AOP framework etc. + * + * @author Trevor D. Cook + * @since 30.09.2003 + */ +public class NestedTestBean implements INestedTestBean { + + private String company = ""; + + public NestedTestBean() { + } + + public NestedTestBean(String company) { + setCompany(company); + } + + public void setCompany(String company) { + this.company = (company != null ? company : ""); + } + + public String getCompany() { + return company; + } + + public boolean equals(Object obj) { + if (!(obj instanceof NestedTestBean)) { + return false; + } + NestedTestBean ntb = (NestedTestBean) obj; + return this.company.equals(ntb.company); + } + + public int hashCode() { + return this.company.hashCode(); + } + + public String toString() { + return "NestedTestBean: " + this.company; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/NumberTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/NumberTestBean.java new file mode 100644 index 00000000000..80c3ec372aa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/NumberTestBean.java @@ -0,0 +1,143 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * @author Juergen Hoeller + * @since 10.06.2003 + */ +public class NumberTestBean { + + private short short1; + private Short short2; + + private int int1; + private Integer int2; + + private long long1; + private Long long2; + + private BigInteger bigInteger; + + private float float1; + private Float float2; + + private double double1; + private Double double2; + + private BigDecimal bigDecimal; + + public short getShort1() { + return short1; + } + + public void setShort1(short short1) { + this.short1 = short1; + } + + public Short getShort2() { + return short2; + } + + public void setShort2(Short short2) { + this.short2 = short2; + } + + public int getInt1() { + return int1; + } + + public void setInt1(int int1) { + this.int1 = int1; + } + + public Integer getInt2() { + return int2; + } + + public void setInt2(Integer int2) { + this.int2 = int2; + } + + public long getLong1() { + return long1; + } + + public void setLong1(long long1) { + this.long1 = long1; + } + + public Long getLong2() { + return long2; + } + + public void setLong2(Long long2) { + this.long2 = long2; + } + + public BigInteger getBigInteger() { + return bigInteger; + } + + public void setBigInteger(BigInteger bigInteger) { + this.bigInteger = bigInteger; + } + + public float getFloat1() { + return float1; + } + + public void setFloat1(float float1) { + this.float1 = float1; + } + + public Float getFloat2() { + return float2; + } + + public void setFloat2(Float float2) { + this.float2 = float2; + } + + public double getDouble1() { + return double1; + } + + public void setDouble1(double double1) { + this.double1 = double1; + } + + public Double getDouble2() { + return double2; + } + + public void setDouble2(Double double2) { + this.double2 = double2; + } + + public BigDecimal getBigDecimal() { + return bigDecimal; + } + + public void setBigDecimal(BigDecimal bigDecimal) { + this.bigDecimal = bigDecimal; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/Person.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/Person.java new file mode 100644 index 00000000000..af3bb924f7e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/Person.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * + * @author Rod Johnson + */ +public interface Person { + + String getName(); + void setName(String name); + int getAge(); + void setAge(int i); + + /** + * Test for non-property method matching. + * If the parameter is a Throwable, it will be thrown rather than + * returned. + */ + Object echo(Object o) throws Throwable; +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/Pet.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/Pet.java new file mode 100644 index 00000000000..eb78f612fb0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/Pet.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class Pet { + + private String name; + + public Pet(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String toString() { + return getName(); + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Pet pet = (Pet) o; + + if (name != null ? !name.equals(pet.name) : pet.name != null) return false; + + return true; + } + + public int hashCode() { + return (name != null ? name.hashCode() : 0); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/PropertyAccessorUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/PropertyAccessorUtilsTests.java new file mode 100644 index 00000000000..7c483830807 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/PropertyAccessorUtilsTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.util.Arrays; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + */ +public class PropertyAccessorUtilsTests extends TestCase { + + public void testCanonicalPropertyName() { + assertEquals("map", PropertyAccessorUtils.canonicalPropertyName("map")); + assertEquals("map[key1]", PropertyAccessorUtils.canonicalPropertyName("map[key1]")); + assertEquals("map[key1]", PropertyAccessorUtils.canonicalPropertyName("map['key1']")); + assertEquals("map[key1]", PropertyAccessorUtils.canonicalPropertyName("map[\"key1\"]")); + assertEquals("map[key1][key2]", PropertyAccessorUtils.canonicalPropertyName("map[key1][key2]")); + assertEquals("map[key1][key2]", PropertyAccessorUtils.canonicalPropertyName("map['key1'][\"key2\"]")); + assertEquals("map[key1].name", PropertyAccessorUtils.canonicalPropertyName("map[key1].name")); + assertEquals("map[key1].name", PropertyAccessorUtils.canonicalPropertyName("map['key1'].name")); + assertEquals("map[key1].name", PropertyAccessorUtils.canonicalPropertyName("map[\"key1\"].name")); + } + + public void testCanonicalPropertyNames() { + String[] original = + new String[] {"map", "map[key1]", "map['key1']", "map[\"key1\"]", "map[key1][key2]", + "map['key1'][\"key2\"]", "map[key1].name", "map['key1'].name", "map[\"key1\"].name"}; + String[] canonical = + new String[] {"map", "map[key1]", "map[key1]", "map[key1]", "map[key1][key2]", + "map[key1][key2]", "map[key1].name", "map[key1].name", "map[key1].name"}; + + assertTrue(Arrays.equals(canonical, PropertyAccessorUtils.canonicalPropertyNames(original))); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/ResourceTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/ResourceTestBean.java new file mode 100644 index 00000000000..d9d8cd166ae --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/ResourceTestBean.java @@ -0,0 +1,41 @@ +package org.springframework.beans; + +import java.io.InputStream; + +import org.springframework.core.io.Resource; + +/** + * @author Juergen Hoeller + * @since 01.04.2004 + */ +public class ResourceTestBean { + + private Resource resource; + + private InputStream inputStream; + + public ResourceTestBean() { + } + + public ResourceTestBean(Resource resource, InputStream inputStream) { + this.resource = resource; + this.inputStream = inputStream; + } + + public void setResource(Resource resource) { + this.resource = resource; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + public Resource getResource() { + return resource; + } + + public InputStream getInputStream() { + return inputStream; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/SerializablePerson.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/SerializablePerson.java new file mode 100644 index 00000000000..66a41f51131 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/SerializablePerson.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.Serializable; + +import org.springframework.util.ObjectUtils; + +/** + * Serializable implementation of the Person interface. + * + * @author Rod Johnson + */ +public class SerializablePerson implements Person, Serializable { + + private String name; + private int age; + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Object echo(Object o) throws Throwable { + if (o instanceof Throwable) { + throw (Throwable) o; + } + return o; + } + + public boolean equals(Object other) { + if (!(other instanceof SerializablePerson)) { + return false; + } + SerializablePerson p = (SerializablePerson) other; + return p.age == age && ObjectUtils.nullSafeEquals(name, p.name); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/TestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/TestBean.java new file mode 100644 index 00000000000..c2a39d38788 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/TestBean.java @@ -0,0 +1,437 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.util.ObjectUtils; + +/** + * Simple test bean used for testing bean factories, the AOP framework etc. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 15 April 2001 + */ +public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOther, Comparable { + + private String beanName; + + private String country; + + private BeanFactory beanFactory; + + private boolean postProcessed; + + private String name; + + private String sex; + + private int age; + + private boolean jedi; + + private ITestBean[] spouses; + + private String touchy; + + private String[] stringArray; + + private Integer[] someIntegerArray; + + private Date date = new Date(); + + private Float myFloat = new Float(0.0); + + private Collection friends = new LinkedList(); + + private Set someSet = new HashSet(); + + private Map someMap = new HashMap(); + + private List someList = new ArrayList(); + + private Properties someProperties = new Properties(); + + private INestedTestBean doctor = new NestedTestBean(); + + private INestedTestBean lawyer = new NestedTestBean(); + + private IndexedTestBean nestedIndexedBean; + + private boolean destroyed; + + private Number someNumber; + + private Colour favouriteColour; + + private Boolean someBoolean; + + private List otherColours; + + private List pets; + + + public TestBean() { + } + + public TestBean(String name) { + this.name = name; + } + + public TestBean(ITestBean spouse) { + this.spouses = new ITestBean[] {spouse}; + } + + public TestBean(String name, int age) { + this.name = name; + this.age = age; + } + + public TestBean(ITestBean spouse, Properties someProperties) { + this.spouses = new ITestBean[] {spouse}; + this.someProperties = someProperties; + } + + public TestBean(List someList) { + this.someList = someList; + } + + public TestBean(Set someSet) { + this.someSet = someSet; + } + + public TestBean(Map someMap) { + this.someMap = someMap; + } + + public TestBean(Properties someProperties) { + this.someProperties = someProperties; + } + + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + public BeanFactory getBeanFactory() { + return beanFactory; + } + + public void setPostProcessed(boolean postProcessed) { + this.postProcessed = postProcessed; + } + + public boolean isPostProcessed() { + return postProcessed; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + if (this.name == null) { + this.name = sex; + } + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public boolean isJedi() { + return jedi; + } + + public void setJedi(boolean jedi) { + this.jedi = jedi; + } + + public ITestBean getSpouse() { + return (spouses != null ? spouses[0] : null); + } + + public void setSpouse(ITestBean spouse) { + this.spouses = new ITestBean[] {spouse}; + } + + public ITestBean[] getSpouses() { + return spouses; + } + + public String getTouchy() { + return touchy; + } + + public void setTouchy(String touchy) throws Exception { + if (touchy.indexOf('.') != -1) { + throw new Exception("Can't contain a ."); + } + if (touchy.indexOf(',') != -1) { + throw new NumberFormatException("Number format exception: contains a ,"); + } + this.touchy = touchy; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String[] getStringArray() { + return stringArray; + } + + public void setStringArray(String[] stringArray) { + this.stringArray = stringArray; + } + + public Integer[] getSomeIntegerArray() { + return someIntegerArray; + } + + public void setSomeIntegerArray(Integer[] someIntegerArray) { + this.someIntegerArray = someIntegerArray; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Float getMyFloat() { + return myFloat; + } + + public void setMyFloat(Float myFloat) { + this.myFloat = myFloat; + } + + public Collection getFriends() { + return friends; + } + + public void setFriends(Collection friends) { + this.friends = friends; + } + + public Set getSomeSet() { + return someSet; + } + + public void setSomeSet(Set someSet) { + this.someSet = someSet; + } + + public Map getSomeMap() { + return someMap; + } + + public void setSomeMap(Map someMap) { + this.someMap = someMap; + } + + public List getSomeList() { + return someList; + } + + public void setSomeList(List someList) { + this.someList = someList; + } + + public Properties getSomeProperties() { + return someProperties; + } + + public void setSomeProperties(Properties someProperties) { + this.someProperties = someProperties; + } + + public INestedTestBean getDoctor() { + return doctor; + } + + public void setDoctor(INestedTestBean doctor) { + this.doctor = doctor; + } + + public INestedTestBean getLawyer() { + return lawyer; + } + + public void setLawyer(INestedTestBean lawyer) { + this.lawyer = lawyer; + } + + public Number getSomeNumber() { + return someNumber; + } + + public void setSomeNumber(Number someNumber) { + this.someNumber = someNumber; + } + + public Colour getFavouriteColour() { + return favouriteColour; + } + + public void setFavouriteColour(Colour favouriteColour) { + this.favouriteColour = favouriteColour; + } + + public Boolean getSomeBoolean() { + return someBoolean; + } + + public void setSomeBoolean(Boolean someBoolean) { + this.someBoolean = someBoolean; + } + + public IndexedTestBean getNestedIndexedBean() { + return nestedIndexedBean; + } + + public void setNestedIndexedBean(IndexedTestBean nestedIndexedBean) { + this.nestedIndexedBean = nestedIndexedBean; + } + + public List getOtherColours() { + return otherColours; + } + + public void setOtherColours(List otherColours) { + this.otherColours = otherColours; + } + + public List getPets() { + return pets; + } + + public void setPets(List pets) { + this.pets = pets; + } + + + /** + * @see ITestBean#exceptional(Throwable) + */ + public void exceptional(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + } + + public void unreliableFileOperation() throws IOException { + throw new IOException(); + } + /** + * @see ITestBean#returnsThis() + */ + public Object returnsThis() { + return this; + } + + /** + * @see IOther#absquatulate() + */ + public void absquatulate() { + } + + public int haveBirthday() { + return age++; + } + + + public void destroy() { + this.destroyed = true; + } + + public boolean wasDestroyed() { + return destroyed; + } + + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || !(other instanceof TestBean)) { + return false; + } + TestBean tb2 = (TestBean) other; + return (ObjectUtils.nullSafeEquals(this.name, tb2.name) && this.age == tb2.age); + } + + public int hashCode() { + return this.age; + } + + public int compareTo(Object other) { + if (this.name != null && other instanceof TestBean) { + return this.name.compareTo(((TestBean) other).getName()); + } + else { + return 1; + } + } + + public String toString() { + return this.name; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractBeanFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractBeanFactoryTests.java new file mode 100644 index 00000000000..06adde9568f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractBeanFactoryTests.java @@ -0,0 +1,328 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import java.beans.PropertyEditorSupport; +import java.util.StringTokenizer; + +import junit.framework.TestCase; + +import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyBatchUpdateException; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; + +/** + * Subclasses must implement setUp() to initialize bean factory + * and any other variables they need. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class AbstractBeanFactoryTests extends TestCase { + + protected abstract BeanFactory getBeanFactory(); + + /** + * Roderick beans inherits from rod, overriding name only. + */ + public void testInheritance() { + assertTrue(getBeanFactory().containsBean("rod")); + assertTrue(getBeanFactory().containsBean("roderick")); + TestBean rod = (TestBean) getBeanFactory().getBean("rod"); + TestBean roderick = (TestBean) getBeanFactory().getBean("roderick"); + assertTrue("not == ", rod != roderick); + assertTrue("rod.name is Rod", rod.getName().equals("Rod")); + assertTrue("rod.age is 31", rod.getAge() == 31); + assertTrue("roderick.name is Roderick", roderick.getName().equals("Roderick")); + assertTrue("roderick.age was inherited", roderick.getAge() == rod.getAge()); + } + + public void testGetBeanWithNullArg() { + try { + getBeanFactory().getBean(null); + fail("Can't get null bean"); + } + catch (IllegalArgumentException ex) { + // OK + } + } + + /** + * Test that InitializingBean objects receive the afterPropertiesSet() callback + */ + public void testInitializingBeanCallback() { + MustBeInitialized mbi = (MustBeInitialized) getBeanFactory().getBean("mustBeInitialized"); + // The dummy business method will throw an exception if the + // afterPropertiesSet() callback wasn't invoked + mbi.businessMethod(); + } + + /** + * Test that InitializingBean/BeanFactoryAware/DisposableBean objects receive the + * afterPropertiesSet() callback before BeanFactoryAware callbacks + */ + public void testLifecycleCallbacks() { + LifecycleBean lb = (LifecycleBean) getBeanFactory().getBean("lifecycle"); + assertEquals("lifecycle", lb.getBeanName()); + // The dummy business method will throw an exception if the + // necessary callbacks weren't invoked in the right order. + lb.businessMethod(); + assertTrue("Not destroyed", !lb.isDestroyed()); + } + + public void testFindsValidInstance() { + try { + Object o = getBeanFactory().getBean("rod"); + assertTrue("Rod bean is a TestBean", o instanceof TestBean); + TestBean rod = (TestBean) o; + assertTrue("rod.name is Rod", rod.getName().equals("Rod")); + assertTrue("rod.age is 31", rod.getAge() == 31); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Shouldn't throw exception on getting valid instance"); + } + } + + public void testGetInstanceByMatchingClass() { + try { + Object o = getBeanFactory().getBean("rod", TestBean.class); + assertTrue("Rod bean is a TestBean", o instanceof TestBean); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Shouldn't throw exception on getting valid instance with matching class"); + } + } + + public void testGetInstanceByNonmatchingClass() { + try { + Object o = getBeanFactory().getBean("rod", BeanFactory.class); + fail("Rod bean is not of type BeanFactory; getBeanInstance(rod, BeanFactory.class) should throw BeanNotOfRequiredTypeException"); + } + catch (BeanNotOfRequiredTypeException ex) { + // So far, so good + assertTrue("Exception has correct bean name", ex.getBeanName().equals("rod")); + assertTrue("Exception requiredType must be BeanFactory.class", ex.getRequiredType().equals(BeanFactory.class)); + assertTrue("Exception actualType as TestBean.class", TestBean.class.isAssignableFrom(ex.getActualType())); + assertTrue("Actual type is correct", ex.getActualType() == getBeanFactory().getBean("rod").getClass()); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Shouldn't throw exception on getting valid instance"); + } + } + + public void testGetSharedInstanceByMatchingClass() { + try { + Object o = getBeanFactory().getBean("rod", TestBean.class); + assertTrue("Rod bean is a TestBean", o instanceof TestBean); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Shouldn't throw exception on getting valid instance with matching class"); + } + } + + public void testGetSharedInstanceByMatchingClassNoCatch() { + Object o = getBeanFactory().getBean("rod", TestBean.class); + assertTrue("Rod bean is a TestBean", o instanceof TestBean); + } + + public void testGetSharedInstanceByNonmatchingClass() { + try { + Object o = getBeanFactory().getBean("rod", BeanFactory.class); + fail("Rod bean is not of type BeanFactory; getBeanInstance(rod, BeanFactory.class) should throw BeanNotOfRequiredTypeException"); + } + catch (BeanNotOfRequiredTypeException ex) { + // So far, so good + assertTrue("Exception has correct bean name", ex.getBeanName().equals("rod")); + assertTrue("Exception requiredType must be BeanFactory.class", ex.getRequiredType().equals(BeanFactory.class)); + assertTrue("Exception actualType as TestBean.class", TestBean.class.isAssignableFrom(ex.getActualType())); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Shouldn't throw exception on getting valid instance"); + } + } + + public void testSharedInstancesAreEqual() { + try { + Object o = getBeanFactory().getBean("rod"); + assertTrue("Rod bean1 is a TestBean", o instanceof TestBean); + Object o1 = getBeanFactory().getBean("rod"); + assertTrue("Rod bean2 is a TestBean", o1 instanceof TestBean); + assertTrue("Object equals applies", o == o1); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Shouldn't throw exception on getting valid instance"); + } + } + + public void testPrototypeInstancesAreIndependent() { + TestBean tb1 = (TestBean) getBeanFactory().getBean("kathy"); + TestBean tb2 = (TestBean) getBeanFactory().getBean("kathy"); + assertTrue("ref equal DOES NOT apply", tb1 != tb2); + assertTrue("object equal true", tb1.equals(tb2)); + tb1.setAge(1); + tb2.setAge(2); + assertTrue("1 age independent = 1", tb1.getAge() == 1); + assertTrue("2 age independent = 2", tb2.getAge() == 2); + assertTrue("object equal now false", !tb1.equals(tb2)); + } + + public void testNotThere() { + assertFalse(getBeanFactory().containsBean("Mr Squiggle")); + try { + Object o = getBeanFactory().getBean("Mr Squiggle"); + fail("Can't find missing bean"); + } + catch (BeansException ex) { + //ex.printStackTrace(); + //fail("Shouldn't throw exception on getting valid instance"); + } + } + + public void testValidEmpty() { + try { + Object o = getBeanFactory().getBean("validEmpty"); + assertTrue("validEmpty bean is a TestBean", o instanceof TestBean); + TestBean ve = (TestBean) o; + assertTrue("Valid empty has defaults", ve.getName() == null && ve.getAge() == 0 && ve.getSpouse() == null); + } + catch (BeansException ex) { + ex.printStackTrace(); + fail("Shouldn't throw exception on valid empty"); + } + } + + public void xtestTypeMismatch() { + try { + Object o = getBeanFactory().getBean("typeMismatch"); + fail("Shouldn't succeed with type mismatch"); + } + catch (BeanCreationException wex) { + assertEquals("typeMismatch", wex.getBeanName()); + assertTrue(wex.getCause() instanceof PropertyBatchUpdateException); + PropertyBatchUpdateException ex = (PropertyBatchUpdateException) wex.getCause(); + // Further tests + assertTrue("Has one error ", ex.getExceptionCount() == 1); + assertTrue("Error is for field age", ex.getPropertyAccessException("age") != null); + assertTrue("We have rejected age in exception", ex.getPropertyAccessException("age").getPropertyChangeEvent().getNewValue().equals("34x")); + } + } + + public void testGrandparentDefinitionFoundInBeanFactory() throws Exception { + TestBean dad = (TestBean) getBeanFactory().getBean("father"); + assertTrue("Dad has correct name", dad.getName().equals("Albert")); + } + + public void testFactorySingleton() throws Exception { + assertTrue(getBeanFactory().isSingleton("&singletonFactory")); + assertTrue(getBeanFactory().isSingleton("singletonFactory")); + TestBean tb = (TestBean) getBeanFactory().getBean("singletonFactory"); + assertTrue("Singleton from factory has correct name, not " + tb.getName(), tb.getName().equals(DummyFactory.SINGLETON_NAME)); + DummyFactory factory = (DummyFactory) getBeanFactory().getBean("&singletonFactory"); + TestBean tb2 = (TestBean) getBeanFactory().getBean("singletonFactory"); + assertTrue("Singleton references ==", tb == tb2); + assertTrue("FactoryBean is BeanFactoryAware", factory.getBeanFactory() != null); + } + + public void testFactoryPrototype() throws Exception { + assertTrue(getBeanFactory().isSingleton("&prototypeFactory")); + assertFalse(getBeanFactory().isSingleton("prototypeFactory")); + TestBean tb = (TestBean) getBeanFactory().getBean("prototypeFactory"); + assertTrue(!tb.getName().equals(DummyFactory.SINGLETON_NAME)); + TestBean tb2 = (TestBean) getBeanFactory().getBean("prototypeFactory"); + assertTrue("Prototype references !=", tb != tb2); + } + + /** + * Check that we can get the factory bean itself. + * This is only possible if we're dealing with a factory + * @throws Exception + */ + public void testGetFactoryItself() throws Exception { + DummyFactory factory = (DummyFactory) getBeanFactory().getBean("&singletonFactory"); + assertTrue(factory != null); + } + + /** + * Check that afterPropertiesSet gets called on factory + * @throws Exception + */ + public void testFactoryIsInitialized() throws Exception { + TestBean tb = (TestBean) getBeanFactory().getBean("singletonFactory"); + DummyFactory factory = (DummyFactory) getBeanFactory().getBean("&singletonFactory"); + assertTrue("Factory was initialized because it implemented InitializingBean", factory.wasInitialized()); + } + + /** + * It should be illegal to dereference a normal bean + * as a factory + */ + public void testRejectsFactoryGetOnNormalBean() { + try { + getBeanFactory().getBean("&rod"); + fail("Shouldn't permit factory get on normal bean"); + } + catch (BeanIsNotAFactoryException ex) { + // Ok + } + } + + // TODO: refactor in AbstractBeanFactory (tests for AbstractBeanFactory) + // and rename this class + public void testAliasing() { + BeanFactory bf = getBeanFactory(); + if (!(bf instanceof ConfigurableBeanFactory)) { + return; + } + ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) bf; + + String alias = "rods alias"; + try { + cbf.getBean(alias); + fail("Shouldn't permit factory get on normal bean"); + } + catch (NoSuchBeanDefinitionException ex) { + // Ok + assertTrue(alias.equals(ex.getBeanName())); + } + + // Create alias + cbf.registerAlias("rod", alias); + Object rod = getBeanFactory().getBean("rod"); + Object aliasRod = getBeanFactory().getBean(alias); + assertTrue(rod == aliasRod); + } + + + public static class TestBeanEditor extends PropertyEditorSupport { + + public void setAsText(String text) { + TestBean tb = new TestBean(); + StringTokenizer st = new StringTokenizer(text, "_"); + tb.setName(st.nextToken()); + tb.setAge(Integer.parseInt(st.nextToken())); + setValue(tb); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractListableBeanFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractListableBeanFactoryTests.java new file mode 100644 index 00000000000..0230237cd9c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/AbstractListableBeanFactoryTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import org.springframework.beans.TestBean; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class AbstractListableBeanFactoryTests extends AbstractBeanFactoryTests { + + /** Subclasses must initialize this */ + protected ListableBeanFactory getListableBeanFactory() { + BeanFactory bf = getBeanFactory(); + if (!(bf instanceof ListableBeanFactory)) { + throw new IllegalStateException("ListableBeanFactory required"); + } + return (ListableBeanFactory) bf; + } + + /** + * Subclasses can override this. + */ + public void testCount() { + assertCount(13); + } + + protected final void assertCount(int count) { + String[] defnames = getListableBeanFactory().getBeanDefinitionNames(); + assertTrue("We should have " + count + " beans, not " + defnames.length, defnames.length == count); + } + + public void assertTestBeanCount(int count) { + String[] defNames = getListableBeanFactory().getBeanNamesForType(TestBean.class, true, false); + assertTrue("We should have " + count + " beans for class org.springframework.beans.TestBean, not " + + defNames.length, defNames.length == count); + + int countIncludingFactoryBeans = count + 2; + String[] names = getListableBeanFactory().getBeanNamesForType(TestBean.class, true, true); + assertTrue("We should have " + countIncludingFactoryBeans + + " beans for class org.springframework.beans.TestBean, not " + names.length, + names.length == countIncludingFactoryBeans); + } + + public void testGetDefinitionsForNoSuchClass() { + String[] defnames = getListableBeanFactory().getBeanNamesForType(String.class); + assertTrue("No string definitions", defnames.length == 0); + } + + /** + * Check that count refers to factory class, not bean class. (We don't know + * what type factories may return, and it may even change over time.) + */ + public void testGetCountForFactoryClass() { + assertTrue("Should have 2 factories, not " + + getListableBeanFactory().getBeanNamesForType(FactoryBean.class).length, + getListableBeanFactory().getBeanNamesForType(FactoryBean.class).length == 2); + + assertTrue("Should have 2 factories, not " + + getListableBeanFactory().getBeanNamesForType(FactoryBean.class).length, + getListableBeanFactory().getBeanNamesForType(FactoryBean.class).length == 2); + } + + public void testContainsBeanDefinition() { + assertTrue(getListableBeanFactory().containsBeanDefinition("rod")); + assertTrue(getListableBeanFactory().containsBeanDefinition("roderick")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java new file mode 100644 index 00000000000..bd5240cc828 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java @@ -0,0 +1,273 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.ObjectUtils; +import org.springframework.web.servlet.HandlerAdapter; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 04.07.2003 + */ +public class BeanFactoryUtilsTests extends TestCase { + + private ConfigurableListableBeanFactory listableBeanFactory; + + private ConfigurableListableBeanFactory dependentBeansBF; + + protected void setUp() { + // Interesting hierarchical factory to test counts. + // Slow to read so we cache it. + XmlBeanFactory grandParent = new XmlBeanFactory(new ClassPathResource("root.xml", getClass())); + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("middle.xml", getClass()), grandParent); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("leaf.xml", getClass()), parent); + this.dependentBeansBF = new XmlBeanFactory(new ClassPathResource("dependentBeans.xml", getClass())); + dependentBeansBF.preInstantiateSingletons(); + this.listableBeanFactory = child; + } + + public void testHierarchicalCountBeansWithNonHierarchicalFactory() { + StaticListableBeanFactory lbf = new StaticListableBeanFactory(); + lbf.addBean("t1", new TestBean()); + lbf.addBean("t2", new TestBean()); + assertTrue(BeanFactoryUtils.countBeansIncludingAncestors(lbf) == 2); + } + + /** + * Check that override doesn't count as two separate beans. + */ + public void testHierarchicalCountBeansWithOverride() throws Exception { + // Leaf count + assertTrue(this.listableBeanFactory.getBeanDefinitionCount() == 1); + // Count minus duplicate + assertTrue("Should count 7 beans, not " + + BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory), + BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7); + } + + public void testHierarchicalNamesWithNoMatch() throws Exception { + List names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, + HandlerAdapter.class)); + assertEquals(0, names.size()); + } + + public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception { + List names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, + IndexedTestBean.class)); + assertEquals(1, names.size()); + assertTrue(names.contains("indexedBean")); + // Distinguish from default ListableBeanFactory behavior + assertTrue(listableBeanFactory.getBeanNamesForType(IndexedTestBean.class).length == 0); + } + + public void testGetBeanNamesForTypeWithOverride() throws Exception { + List names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, + ITestBean.class)); + // includes 2 TestBeans from FactoryBeans (DummyFactory definitions) + assertEquals(4, names.size()); + assertTrue(names.contains("test")); + assertTrue(names.contains("test3")); + assertTrue(names.contains("testFactory1")); + assertTrue(names.contains("testFactory2")); + } + + public void testNoBeansOfType() { + StaticListableBeanFactory lbf = new StaticListableBeanFactory(); + lbf.addBean("foo", new Object()); + Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false); + assertTrue(beans.isEmpty()); + } + + public void testFindsBeansOfTypeWithStaticFactory() { + StaticListableBeanFactory lbf = new StaticListableBeanFactory(); + TestBean t1 = new TestBean(); + TestBean t2 = new TestBean(); + DummyFactory t3 = new DummyFactory(); + DummyFactory t4 = new DummyFactory(); + t4.setSingleton(false); + lbf.addBean("t1", t1); + lbf.addBean("t2", t2); + lbf.addBean("t3", t3); + lbf.addBean("t4", t4); + + Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false); + assertEquals(2, beans.size()); + assertEquals(t1, beans.get("t1")); + assertEquals(t2, beans.get("t2")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, false, true); + assertEquals(3, beans.size()); + assertEquals(t1, beans.get("t1")); + assertEquals(t2, beans.get("t2")); + assertEquals(t3.getObject(), beans.get("t3")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true); + assertEquals(4, beans.size()); + assertEquals(t1, beans.get("t1")); + assertEquals(t2, beans.get("t2")); + assertEquals(t3.getObject(), beans.get("t3")); + assertTrue(beans.get("t4") instanceof TestBean); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, DummyFactory.class, true, true); + assertEquals(2, beans.size()); + assertEquals(t3, beans.get("&t3")); + assertEquals(t4, beans.get("&t4")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, FactoryBean.class, true, true); + assertEquals(2, beans.size()); + assertEquals(t3, beans.get("&t3")); + assertEquals(t4, beans.get("&t4")); + } + + public void testFindsBeansOfTypeWithDefaultFactory() { + Object test3 = this.listableBeanFactory.getBean("test3"); + Object test = this.listableBeanFactory.getBean("test"); + + TestBean t1 = new TestBean(); + TestBean t2 = new TestBean(); + DummyFactory t3 = new DummyFactory(); + DummyFactory t4 = new DummyFactory(); + t4.setSingleton(false); + this.listableBeanFactory.registerSingleton("t1", t1); + this.listableBeanFactory.registerSingleton("t2", t2); + this.listableBeanFactory.registerSingleton("t3", t3); + this.listableBeanFactory.registerSingleton("t4", t4); + + Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, + false); + assertEquals(6, beans.size()); + assertEquals(test3, beans.get("test3")); + assertEquals(test, beans.get("test")); + assertEquals(t1, beans.get("t1")); + assertEquals(t2, beans.get("t2")); + assertEquals(t3.getObject(), beans.get("t3")); + assertTrue(beans.get("t4") instanceof TestBean); + // t3 and t4 are found here as of Spring 2.0, since they are + // pre-registered + // singleton instances, while testFactory1 and testFactory are *not* + // found + // because they are FactoryBean definitions that haven't been + // initialized yet. + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, false, true); + Object testFactory1 = this.listableBeanFactory.getBean("testFactory1"); + assertEquals(5, beans.size()); + assertEquals(test, beans.get("test")); + assertEquals(testFactory1, beans.get("testFactory1")); + assertEquals(t1, beans.get("t1")); + assertEquals(t2, beans.get("t2")); + assertEquals(t3.getObject(), beans.get("t3")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, true); + assertEquals(8, beans.size()); + assertEquals(test3, beans.get("test3")); + assertEquals(test, beans.get("test")); + assertEquals(testFactory1, beans.get("testFactory1")); + assertTrue(beans.get("testFactory2") instanceof TestBean); + assertEquals(t1, beans.get("t1")); + assertEquals(t2, beans.get("t2")); + assertEquals(t3.getObject(), beans.get("t3")); + assertTrue(beans.get("t4") instanceof TestBean); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, DummyFactory.class, true, true); + assertEquals(4, beans.size()); + assertEquals(this.listableBeanFactory.getBean("&testFactory1"), beans.get("&testFactory1")); + assertEquals(this.listableBeanFactory.getBean("&testFactory2"), beans.get("&testFactory2")); + assertEquals(t3, beans.get("&t3")); + assertEquals(t4, beans.get("&t4")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, FactoryBean.class, true, true); + assertEquals(4, beans.size()); + assertEquals(this.listableBeanFactory.getBean("&testFactory1"), beans.get("&testFactory1")); + assertEquals(this.listableBeanFactory.getBean("&testFactory2"), beans.get("&testFactory2")); + assertEquals(t3, beans.get("&t3")); + assertEquals(t4, beans.get("&t4")); + } + + public void testHierarchicalResolutionWithOverride() throws Exception { + Object test3 = this.listableBeanFactory.getBean("test3"); + Object test = this.listableBeanFactory.getBean("test"); + + Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, + false); + assertEquals(2, beans.size()); + assertEquals(test3, beans.get("test3")); + assertEquals(test, beans.get("test")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, false, false); + assertEquals(1, beans.size()); + assertEquals(test, beans.get("test")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, false, true); + Object testFactory1 = this.listableBeanFactory.getBean("testFactory1"); + assertEquals(2, beans.size()); + assertEquals(test, beans.get("test")); + assertEquals(testFactory1, beans.get("testFactory1")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, true); + assertEquals(4, beans.size()); + assertEquals(test3, beans.get("test3")); + assertEquals(test, beans.get("test")); + assertEquals(testFactory1, beans.get("testFactory1")); + assertTrue(beans.get("testFactory2") instanceof TestBean); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, DummyFactory.class, true, true); + assertEquals(2, beans.size()); + assertEquals(this.listableBeanFactory.getBean("&testFactory1"), beans.get("&testFactory1")); + assertEquals(this.listableBeanFactory.getBean("&testFactory2"), beans.get("&testFactory2")); + + beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, FactoryBean.class, true, true); + assertEquals(2, beans.size()); + assertEquals(this.listableBeanFactory.getBean("&testFactory1"), beans.get("&testFactory1")); + assertEquals(this.listableBeanFactory.getBean("&testFactory2"), beans.get("&testFactory2")); + } + + public void testADependencies() { + String[] deps = this.dependentBeansBF.getDependentBeans("a"); + assertTrue(ObjectUtils.isEmpty(deps)); + } + + public void testBDependencies() { + String[] deps = this.dependentBeansBF.getDependentBeans("b"); + assertTrue(Arrays.equals(new String[] { "c" }, deps)); + } + + public void testCDependencies() { + String[] deps = this.dependentBeansBF.getDependentBeans("c"); + assertTrue(Arrays.equals(new String[] { "int", "long" }, deps)); + } + + public void testIntDependencies() { + String[] deps = this.dependentBeansBF.getDependentBeans("int"); + assertTrue(Arrays.equals(new String[] { "buffer" }, deps)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java new file mode 100644 index 00000000000..81ab7fe5ff4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java @@ -0,0 +1,149 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Guillaume Poirier + * @author Juergen Hoeller + * @since 10.03.2004 + */ +public class ConcurrentBeanFactoryTests extends TestCase { + + private static final Log logger = LogFactory.getLog(ConcurrentBeanFactoryTests.class); + + private static final SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd"); + + private static final Date date1; + + private static final Date date2; + + static { + try { + date1 = df.parse("2004/08/08"); + date2 = df.parse("2000/02/02"); + } + catch (ParseException e) { + throw new RuntimeException(e); + } + } + + private BeanFactory factory; + + private Set set = Collections.synchronizedSet(new HashSet()); + + private Throwable ex = null; + + protected void setUp() throws Exception { + XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("concurrent.xml", getClass())); + CustomDateEditor editor = new CustomDateEditor(df, false); + factory.registerCustomEditor(Date.class, editor); + this.factory = factory; + } + + public void testSingleThread() { + for (int i = 0; i < 100; i++) { + performTest(); + } + } + + public void testConcurrent() { + for (int i = 0; i < 100; i++) { + TestRun run = new TestRun(); + run.setDaemon(true); + set.add(run); + } + for (Iterator it = new HashSet(set).iterator(); it.hasNext();) { + TestRun run = (TestRun) it.next(); + run.start(); + } + logger.info("Thread creation over, " + set.size() + " still active."); + synchronized (set) { + while (!set.isEmpty() && ex == null) { + try { + set.wait(); + } + catch (InterruptedException e) { + logger.info(e.toString()); + } + logger.info(set.size() + " threads still active."); + } + } + if (ex != null) { + fail(ex.getMessage()); + } + } + + private void performTest() { + ConcurrentBean b1 = (ConcurrentBean) factory.getBean("bean1"); + ConcurrentBean b2 = (ConcurrentBean) factory.getBean("bean2"); + + assertEquals(b1.getDate(), date1); + assertEquals(b2.getDate(), date2); + } + + + private class TestRun extends Thread { + + public void run() { + try { + for (int i = 0; i < 10000; i++) { + performTest(); + } + } + catch (Throwable e) { + ex = e; + } + finally { + synchronized (set) { + set.remove(this); + set.notifyAll(); + } + } + } + } + + + public static class ConcurrentBean { + + private Date date; + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/CountingFactory.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/CountingFactory.java new file mode 100644 index 00000000000..147184f2328 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/CountingFactory.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import org.springframework.beans.TestBean; + +/** + * @author Juergen Hoeller + */ +public class CountingFactory implements FactoryBean { + + private static int factoryBeanInstanceCount = 0; + + + /** + * Clear static state. + */ + public static void reset() { + factoryBeanInstanceCount = 0; + } + + public static int getFactoryBeanInstanceCount() { + return factoryBeanInstanceCount; + } + + + public CountingFactory() { + factoryBeanInstanceCount++; + } + + public void setTestBean(TestBean tb) { + if (tb.getSpouse() == null) { + throw new IllegalStateException("TestBean needs to have spouse"); + } + } + + + public Object getObject() { + return "myString"; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java new file mode 100644 index 00000000000..2b127406e65 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -0,0 +1,2239 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.security.AccessController; +import java.security.Principal; +import java.security.PrivilegedAction; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.security.auth.Subject; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.aop.interceptor.SideEffectBean; +import org.springframework.beans.BeansException; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.NestedTestBean; +import org.springframework.beans.NotWritablePropertyException; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.TestBean; +import org.springframework.beans.TypeConverter; +import org.springframework.beans.TypeMismatchException; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ChildBeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.ConstructorDependenciesBean; +import org.springframework.beans.factory.xml.DependenciesBean; +import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.core.MethodParameter; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.test.AssertThrows; +import org.springframework.util.StopWatch; + +/** + * Tests properties population and autowire behavior. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + * @author Sam Brannen + */ +public class DefaultListableBeanFactoryTests extends TestCase { + + private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); + + + public void testUnreferencedSingletonWasInstantiated() { + KnowsIfInstantiated.clearInstantiationRecord(); + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("x1.(class)", KnowsIfInstantiated.class.getName()); + assertTrue("singleton not instantiated", !KnowsIfInstantiated.wasInstantiated()); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + lbf.preInstantiateSingletons(); + assertTrue("singleton was instantiated", KnowsIfInstantiated.wasInstantiated()); + } + + public void testLazyInitialization() { + KnowsIfInstantiated.clearInstantiationRecord(); + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("x1.(class)", KnowsIfInstantiated.class.getName()); + p.setProperty("x1.(lazy-init)", "true"); + assertTrue("singleton not instantiated", !KnowsIfInstantiated.wasInstantiated()); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + assertTrue("singleton not instantiated", !KnowsIfInstantiated.wasInstantiated()); + lbf.preInstantiateSingletons(); + + assertTrue("singleton not instantiated", !KnowsIfInstantiated.wasInstantiated()); + lbf.getBean("x1"); + assertTrue("singleton was instantiated", KnowsIfInstantiated.wasInstantiated()); + } + + public void testFactoryBeanDidNotCreatePrototype() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("x1.(class)", DummyFactory.class.getName()); + // Reset static state + DummyFactory.reset(); + p.setProperty("x1.singleton", "false"); + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + assertEquals(TestBean.class, lbf.getType("x1")); + lbf.preInstantiateSingletons(); + + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + lbf.getBean("x1"); + assertEquals(TestBean.class, lbf.getType("x1")); + assertTrue(lbf.containsBean("x1")); + assertTrue(lbf.containsBean("&x1")); + assertTrue("prototype was instantiated", DummyFactory.wasPrototypeCreated()); + } + + public void testPrototypeFactoryBeanIgnoredByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("x1.(class)", DummyFactory.class.getName()); + // Reset static state + DummyFactory.reset(); + p.setProperty("x1.(singleton)", "false"); + p.setProperty("x1.singleton", "false"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(0, beanNames.length); + assertFalse(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertTrue(lbf.containsBean("&x1")); + assertFalse(lbf.isSingleton("x1")); + assertFalse(lbf.isSingleton("&x1")); + assertTrue(lbf.isPrototype("x1")); + assertTrue(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertTrue(lbf.isTypeMatch("&x1", DummyFactory.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(DummyFactory.class, lbf.getType("&x1")); + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + } + + public void testPrototypeSingletonFactoryBeanIgnoredByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("x1.(class)", DummyFactory.class.getName()); + // Reset static state + DummyFactory.reset(); + p.setProperty("x1.(singleton)", "false"); + p.setProperty("x1.singleton", "true"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(0, beanNames.length); + assertFalse(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertTrue(lbf.containsBean("&x1")); + assertFalse(lbf.isSingleton("x1")); + assertFalse(lbf.isSingleton("&x1")); + assertTrue(lbf.isPrototype("x1")); + assertTrue(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertTrue(lbf.isTypeMatch("&x1", DummyFactory.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(DummyFactory.class, lbf.getType("&x1")); + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + } + + public void testNonInitializedFactoryBeanIgnoredByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("x1.(class)", DummyFactory.class.getName()); + // Reset static state + DummyFactory.reset(); + p.setProperty("x1.singleton", "false"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(0, beanNames.length); + assertFalse(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertTrue(lbf.containsBean("&x1")); + assertFalse(lbf.isSingleton("x1")); + assertTrue(lbf.isSingleton("&x1")); + assertTrue(lbf.isPrototype("x1")); + assertFalse(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertTrue(lbf.isTypeMatch("&x1", DummyFactory.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(DummyFactory.class, lbf.getType("&x1")); + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + } + + public void testInitializedFactoryBeanFoundByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("x1.(class)", DummyFactory.class.getName()); + // Reset static state + DummyFactory.reset(); + p.setProperty("x1.singleton", "false"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + lbf.preInstantiateSingletons(); + + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(1, beanNames.length); + assertEquals("x1", beanNames[0]); + assertTrue(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertTrue(lbf.containsBean("&x1")); + assertTrue(lbf.containsLocalBean("x1")); + assertTrue(lbf.containsLocalBean("&x1")); + assertFalse(lbf.isSingleton("x1")); + assertTrue(lbf.isSingleton("&x1")); + assertTrue(lbf.isPrototype("x1")); + assertFalse(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertTrue(lbf.isTypeMatch("&x1", DummyFactory.class)); + assertTrue(lbf.isTypeMatch("x1", Object.class)); + assertTrue(lbf.isTypeMatch("&x1", Object.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(DummyFactory.class, lbf.getType("&x1")); + assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated()); + + lbf.registerAlias("x1", "x2"); + assertTrue(lbf.containsBean("x2")); + assertTrue(lbf.containsBean("&x2")); + assertTrue(lbf.containsLocalBean("x2")); + assertTrue(lbf.containsLocalBean("&x2")); + assertFalse(lbf.isSingleton("x2")); + assertTrue(lbf.isSingleton("&x2")); + assertTrue(lbf.isPrototype("x2")); + assertFalse(lbf.isPrototype("&x2")); + assertTrue(lbf.isTypeMatch("x2", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x2", TestBean.class)); + assertTrue(lbf.isTypeMatch("&x2", DummyFactory.class)); + assertTrue(lbf.isTypeMatch("x2", Object.class)); + assertTrue(lbf.isTypeMatch("&x2", Object.class)); + assertEquals(TestBean.class, lbf.getType("x2")); + assertEquals(DummyFactory.class, lbf.getType("&x2")); + assertEquals(1, lbf.getAliases("x1").length); + assertEquals("x2", lbf.getAliases("x1")[0]); + assertEquals(1, lbf.getAliases("&x1").length); + assertEquals("&x2", lbf.getAliases("&x1")[0]); + assertEquals(1, lbf.getAliases("x2").length); + assertEquals("x1", lbf.getAliases("x2")[0]); + assertEquals(1, lbf.getAliases("&x2").length); + assertEquals("&x1", lbf.getAliases("&x2")[0]); + } + + public void testStaticFactoryMethodFoundByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBeanFactory.class); + rbd.setFactoryMethodName("createTestBean"); + lbf.registerBeanDefinition("x1", rbd); + + TestBeanFactory.initialized = false; + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(1, beanNames.length); + assertEquals("x1", beanNames[0]); + assertFalse(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertFalse(lbf.containsBean("&x1")); + assertTrue(lbf.isSingleton("x1")); + assertFalse(lbf.isSingleton("&x1")); + assertFalse(lbf.isPrototype("x1")); + assertFalse(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(null, lbf.getType("&x1")); + assertFalse(TestBeanFactory.initialized); + } + + public void testStaticPrototypeFactoryMethodFoundByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBeanFactory.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setFactoryMethodName("createTestBean"); + lbf.registerBeanDefinition("x1", rbd); + + TestBeanFactory.initialized = false; + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(1, beanNames.length); + assertEquals("x1", beanNames[0]); + assertFalse(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertFalse(lbf.containsBean("&x1")); + assertFalse(lbf.isSingleton("x1")); + assertFalse(lbf.isSingleton("&x1")); + assertTrue(lbf.isPrototype("x1")); + assertFalse(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(null, lbf.getType("&x1")); + assertFalse(TestBeanFactory.initialized); + } + + public void testNonStaticFactoryMethodFoundByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition factoryBd = new RootBeanDefinition(TestBeanFactory.class); + lbf.registerBeanDefinition("factory", factoryBd); + RootBeanDefinition rbd = new RootBeanDefinition(TestBeanFactory.class); + rbd.setFactoryBeanName("factory"); + rbd.setFactoryMethodName("createTestBeanNonStatic"); + lbf.registerBeanDefinition("x1", rbd); + + TestBeanFactory.initialized = false; + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(1, beanNames.length); + assertEquals("x1", beanNames[0]); + assertFalse(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertFalse(lbf.containsBean("&x1")); + assertTrue(lbf.isSingleton("x1")); + assertFalse(lbf.isSingleton("&x1")); + assertFalse(lbf.isPrototype("x1")); + assertFalse(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(null, lbf.getType("&x1")); + assertFalse(TestBeanFactory.initialized); + } + + public void testNonStaticPrototypeFactoryMethodFoundByNonEagerTypeMatching() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition factoryBd = new RootBeanDefinition(TestBeanFactory.class); + lbf.registerBeanDefinition("factory", factoryBd); + RootBeanDefinition rbd = new RootBeanDefinition(); + rbd.setFactoryBeanName("factory"); + rbd.setFactoryMethodName("createTestBeanNonStatic"); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + lbf.registerBeanDefinition("x1", rbd); + + TestBeanFactory.initialized = false; + String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false); + assertEquals(1, beanNames.length); + assertEquals("x1", beanNames[0]); + assertFalse(lbf.containsSingleton("x1")); + assertTrue(lbf.containsBean("x1")); + assertFalse(lbf.containsBean("&x1")); + assertTrue(lbf.containsLocalBean("x1")); + assertFalse(lbf.containsLocalBean("&x1")); + assertFalse(lbf.isSingleton("x1")); + assertFalse(lbf.isSingleton("&x1")); + assertTrue(lbf.isPrototype("x1")); + assertFalse(lbf.isPrototype("&x1")); + assertTrue(lbf.isTypeMatch("x1", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x1", TestBean.class)); + assertTrue(lbf.isTypeMatch("x1", Object.class)); + assertFalse(lbf.isTypeMatch("&x1", Object.class)); + assertEquals(TestBean.class, lbf.getType("x1")); + assertEquals(null, lbf.getType("&x1")); + assertFalse(TestBeanFactory.initialized); + + lbf.registerAlias("x1", "x2"); + assertTrue(lbf.containsBean("x2")); + assertFalse(lbf.containsBean("&x2")); + assertTrue(lbf.containsLocalBean("x2")); + assertFalse(lbf.containsLocalBean("&x2")); + assertFalse(lbf.isSingleton("x2")); + assertFalse(lbf.isSingleton("&x2")); + assertTrue(lbf.isPrototype("x2")); + assertFalse(lbf.isPrototype("&x2")); + assertTrue(lbf.isTypeMatch("x2", TestBean.class)); + assertFalse(lbf.isTypeMatch("&x2", TestBean.class)); + assertTrue(lbf.isTypeMatch("x2", Object.class)); + assertFalse(lbf.isTypeMatch("&x2", Object.class)); + assertEquals(TestBean.class, lbf.getType("x2")); + assertEquals(null, lbf.getType("&x2")); + assertEquals(1, lbf.getAliases("x1").length); + assertEquals("x2", lbf.getAliases("x1")[0]); + assertEquals(1, lbf.getAliases("&x1").length); + assertEquals("&x2", lbf.getAliases("&x1")[0]); + assertEquals(1, lbf.getAliases("x2").length); + assertEquals("x1", lbf.getAliases("x2")[0]); + assertEquals(1, lbf.getAliases("&x2").length); + assertEquals("&x1", lbf.getAliases("&x2")[0]); + } + + public void testEmpty() { + ListableBeanFactory lbf = new DefaultListableBeanFactory(); + assertTrue("No beans defined --> array != null", lbf.getBeanDefinitionNames() != null); + assertTrue("No beans defined after no arg constructor", lbf.getBeanDefinitionNames().length == 0); + assertTrue("No beans defined after no arg constructor", lbf.getBeanDefinitionCount() == 0); + } + + public void testEmptyPropertiesPopulation() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + assertTrue("No beans defined after ignorable invalid", lbf.getBeanDefinitionCount() == 0); + } + + public void testHarmlessIgnorableRubbish() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("foo", "bar"); + p.setProperty("qwert", "er"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p, "test"); + assertTrue("No beans defined after harmless ignorable rubbish", lbf.getBeanDefinitionCount() == 0); + } + + public void testPropertiesPopulationWithNullPrefix() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("test.(class)", "org.springframework.beans.TestBean"); + p.setProperty("test.name", "Tony"); + p.setProperty("test.age", "48"); + int count = (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + assertTrue("1 beans registered, not " + count, count == 1); + testSingleTestBean(lbf); + } + + public void testPropertiesPopulationWithPrefix() { + String PREFIX = "beans."; + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty(PREFIX + "test.(class)", "org.springframework.beans.TestBean"); + p.setProperty(PREFIX + "test.name", "Tony"); + p.setProperty(PREFIX + "test.age", "0x30"); + int count = (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p, PREFIX); + assertTrue("1 beans registered, not " + count, count == 1); + testSingleTestBean(lbf); + } + + public void testSimpleReference() { + String PREFIX = "beans."; + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + + p.setProperty(PREFIX + "rod.(class)", "org.springframework.beans.TestBean"); + p.setProperty(PREFIX + "rod.name", "Rod"); + + p.setProperty(PREFIX + "kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty(PREFIX + "kerry.name", "Kerry"); + p.setProperty(PREFIX + "kerry.age", "35"); + p.setProperty(PREFIX + "kerry.spouse(ref)", "rod"); + + int count = (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p, PREFIX); + assertTrue("2 beans registered, not " + count, count == 2); + + TestBean kerry = (TestBean) lbf.getBean("kerry", TestBean.class); + assertTrue("Kerry name is Kerry", "Kerry".equals(kerry.getName())); + ITestBean spouse = kerry.getSpouse(); + assertTrue("Kerry spouse is non null", spouse != null); + assertTrue("Kerry spouse name is Rod", "Rod".equals(spouse.getName())); + } + + public void testPropertiesWithDotsInKey() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + + p.setProperty("tb.(class)", "org.springframework.beans.TestBean"); + p.setProperty("tb.someMap[my.key]", "my.value"); + + int count = (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + assertTrue("1 beans registered, not " + count, count == 1); + assertEquals(1, lbf.getBeanDefinitionCount()); + + TestBean tb = (TestBean) lbf.getBean("tb", TestBean.class); + assertEquals("my.value", tb.getSomeMap().get("my.key")); + } + + public void testUnresolvedReference() { + String PREFIX = "beans."; + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + + try { + p.setProperty(PREFIX + "kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty(PREFIX + "kerry.name", "Kerry"); + p.setProperty(PREFIX + "kerry.age", "35"); + p.setProperty(PREFIX + "kerry.spouse(ref)", "rod"); + + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p, PREFIX); + + lbf.getBean("kerry"); + fail("Unresolved reference should have been detected"); + } + catch (BeansException ex) { + // cool + } + } + + public void testSelfReference() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("self")); + lbf.registerBeanDefinition("self", new RootBeanDefinition(TestBean.class, pvs)); + TestBean self = (TestBean) lbf.getBean("self"); + assertEquals(self, self.getSpouse()); + } + + public void testPossibleMatches() { + try { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("ag", "foobar"); + lbf.registerBeanDefinition("tb", new RootBeanDefinition(TestBean.class, pvs)); + lbf.getBean("tb"); + fail("Should throw exception on invalid property"); + } + catch (BeanCreationException ex) { + ex.printStackTrace(); + assertTrue(ex.getCause() instanceof NotWritablePropertyException); + NotWritablePropertyException cause = (NotWritablePropertyException) ex.getCause(); + // expected + assertEquals(1, cause.getPossibleMatches().length); + assertEquals("age", cause.getPossibleMatches()[0]); + } + } + + public void testPrototype() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty("kerry.age", "35"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + TestBean kerry1 = (TestBean) lbf.getBean("kerry"); + TestBean kerry2 = (TestBean) lbf.getBean("kerry"); + assertTrue("Non null", kerry1 != null); + assertTrue("Singletons equal", kerry1 == kerry2); + + lbf = new DefaultListableBeanFactory(); + p = new Properties(); + p.setProperty("kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty("kerry.(scope)", "prototype"); + p.setProperty("kerry.age", "35"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + kerry1 = (TestBean) lbf.getBean("kerry"); + kerry2 = (TestBean) lbf.getBean("kerry"); + assertTrue("Non null", kerry1 != null); + assertTrue("Prototypes NOT equal", kerry1 != kerry2); + + lbf = new DefaultListableBeanFactory(); + p = new Properties(); + p.setProperty("kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty("kerry.(scope)", "singleton"); + p.setProperty("kerry.age", "35"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + kerry1 = (TestBean) lbf.getBean("kerry"); + kerry2 = (TestBean) lbf.getBean("kerry"); + assertTrue("Non null", kerry1 != null); + assertTrue("Specified singletons equal", kerry1 == kerry2); + } + + public void testPrototypeCircleLeadsToException() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty("kerry.(singleton)", "false"); + p.setProperty("kerry.age", "35"); + p.setProperty("kerry.spouse", "*rod"); + p.setProperty("rod.(class)", "org.springframework.beans.TestBean"); + p.setProperty("rod.(singleton)", "false"); + p.setProperty("rod.age", "34"); + p.setProperty("rod.spouse", "*kerry"); + + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + try { + lbf.getBean("kerry"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + assertTrue(ex.contains(BeanCurrentlyInCreationException.class)); + } + } + + public void testPrototypeExtendsPrototype() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("wife.(class)", "org.springframework.beans.TestBean"); + p.setProperty("wife.name", "kerry"); + + p.setProperty("kerry.(parent)", "wife"); + p.setProperty("kerry.age", "35"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + TestBean kerry1 = (TestBean) lbf.getBean("kerry"); + TestBean kerry2 = (TestBean) lbf.getBean("kerry"); + assertEquals("kerry", kerry1.getName()); + assertNotNull("Non null", kerry1); + assertTrue("Singletons equal", kerry1 == kerry2); + + lbf = new DefaultListableBeanFactory(); + p = new Properties(); + p.setProperty("wife.(class)", "org.springframework.beans.TestBean"); + p.setProperty("wife.name", "kerry"); + p.setProperty("wife.(singleton)", "false"); + p.setProperty("kerry.(parent)", "wife"); + p.setProperty("kerry.(singleton)", "false"); + p.setProperty("kerry.age", "35"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + assertFalse(lbf.isSingleton("kerry")); + kerry1 = (TestBean) lbf.getBean("kerry"); + kerry2 = (TestBean) lbf.getBean("kerry"); + assertTrue("Non null", kerry1 != null); + assertTrue("Prototypes NOT equal", kerry1 != kerry2); + + lbf = new DefaultListableBeanFactory(); + p = new Properties(); + p.setProperty("kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty("kerry.(singleton)", "true"); + p.setProperty("kerry.age", "35"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + kerry1 = (TestBean) lbf.getBean("kerry"); + kerry2 = (TestBean) lbf.getBean("kerry"); + assertTrue("Non null", kerry1 != null); + assertTrue("Specified singletons equal", kerry1 == kerry2); + } + + public void testCanReferenceParentBeanFromChildViaAlias() { + final String EXPECTED_NAME = "Juergen"; + final int EXPECTED_AGE = 41; + + RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class); + parentDefinition.setAbstract(true); + parentDefinition.getPropertyValues().addPropertyValue("name", EXPECTED_NAME); + parentDefinition.getPropertyValues().addPropertyValue("age", new Integer(EXPECTED_AGE)); + + ChildBeanDefinition childDefinition = new ChildBeanDefinition("alias"); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("parent", parentDefinition); + factory.registerBeanDefinition("child", childDefinition); + factory.registerAlias("parent", "alias"); + + TestBean child = (TestBean) factory.getBean("child"); + assertEquals(EXPECTED_NAME, child.getName()); + assertEquals(EXPECTED_AGE, child.getAge()); + + assertEquals("Use cached merged bean definition", + factory.getMergedBeanDefinition("child"), factory.getMergedBeanDefinition("child")); + } + + public void testNameAlreadyBound() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("kerry.(class)", "org.springframework.beans.TestBean"); + p.setProperty("kerry.age", "35"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + try { + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + } + catch (BeanDefinitionStoreException ex) { + assertEquals("kerry", ex.getBeanName()); + // expected + } + } + + private void testSingleTestBean(ListableBeanFactory lbf) { + assertTrue("1 beans defined", lbf.getBeanDefinitionCount() == 1); + String[] names = lbf.getBeanDefinitionNames(); + assertTrue("Array length == 1", names.length == 1); + assertTrue("0th element == test", names[0].equals("test")); + TestBean tb = (TestBean) lbf.getBean("test"); + assertTrue("Test is non null", tb != null); + assertTrue("Test bean name is Tony", "Tony".equals(tb.getName())); + assertTrue("Test bean age is 48", tb.getAge() == 48); + } + + public void testBeanDefinitionOverriding() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); + lbf.registerBeanDefinition("test", new RootBeanDefinition(NestedTestBean.class)); + lbf.registerAlias("otherTest", "test2"); + lbf.registerAlias("test", "test2"); + assertTrue(lbf.getBean("test") instanceof NestedTestBean); + assertTrue(lbf.getBean("test2") instanceof NestedTestBean); + } + + public void testBeanDefinitionRemoval() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.setAllowBeanDefinitionOverriding(false); + lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); + lbf.registerAlias("test", "test2"); + lbf.preInstantiateSingletons(); + lbf.removeBeanDefinition("test"); + lbf.removeAlias("test2"); + lbf.registerBeanDefinition("test", new RootBeanDefinition(NestedTestBean.class)); + lbf.registerAlias("test", "test2"); + assertTrue(lbf.getBean("test") instanceof NestedTestBean); + assertTrue(lbf.getBean("test2") instanceof NestedTestBean); + } + + public void testBeanDefinitionOverridingNotAllowed() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.setAllowBeanDefinitionOverriding(false); + lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); + try { + lbf.registerBeanDefinition("test", new RootBeanDefinition(NestedTestBean.class)); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + assertEquals("test", ex.getBeanName()); + // expected + } + } + + public void testBeanDefinitionOverridingWithAlias() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); + lbf.registerAlias("test", "testAlias"); + lbf.registerBeanDefinition("test", new RootBeanDefinition(NestedTestBean.class)); + lbf.registerAlias("test", "testAlias"); + assertTrue(lbf.getBean("test") instanceof NestedTestBean); + assertTrue(lbf.getBean("testAlias") instanceof NestedTestBean); + } + + public void testAliasChaining() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(NestedTestBean.class)); + lbf.registerAlias("test", "testAlias"); + lbf.registerAlias("testAlias", "testAlias2"); + lbf.registerAlias("testAlias2", "testAlias3"); + Object bean = lbf.getBean("test"); + assertSame(bean, lbf.getBean("testAlias")); + assertSame(bean, lbf.getBean("testAlias2")); + assertSame(bean, lbf.getBean("testAlias3")); + } + + public void testBeanReferenceWithNewSyntax() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("r.(class)", TestBean.class.getName()); + p.setProperty("r.name", "rod"); + p.setProperty("k.(class)", TestBean.class.getName()); + p.setProperty("k.name", "kerry"); + p.setProperty("k.spouse", "*r"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + TestBean k = (TestBean) lbf.getBean("k"); + TestBean r = (TestBean) lbf.getBean("r"); + assertTrue(k.getSpouse() == r); + } + + public void testCanEscapeBeanReferenceSyntax() { + String name = "*name"; + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("r.(class)", TestBean.class.getName()); + p.setProperty("r.name", "*" + name); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + TestBean r = (TestBean) lbf.getBean("r"); + assertTrue(r.getName().equals(name)); + } + + public void testCustomEditor() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN); + lbf.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, nf, true)); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("myFloat", "1,1"); + lbf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class, pvs)); + TestBean testBean = (TestBean) lbf.getBean("testBean"); + assertTrue(testBean.getMyFloat().floatValue() == 1.1f); + } + + public void testCustomEditorWithBeanReference() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN); + lbf.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, nf, true)); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("myFloat", new RuntimeBeanReference("myFloat")); + lbf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class, pvs)); + lbf.registerSingleton("myFloat", "1,1"); + TestBean testBean = (TestBean) lbf.getBean("testBean"); + assertTrue(testBean.getMyFloat().floatValue() == 1.1f); + } + + public void testCustomTypeConverter() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN); + lbf.setTypeConverter(new CustomTypeConverter(nf)); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("myFloat", "1,1"); + ConstructorArgumentValues cav = new ConstructorArgumentValues(); + cav.addIndexedArgumentValue(0, "myName"); + cav.addIndexedArgumentValue(1, "myAge"); + lbf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class, cav, pvs)); + TestBean testBean = (TestBean) lbf.getBean("testBean"); + assertEquals("myName", testBean.getName()); + assertEquals(5, testBean.getAge()); + assertTrue(testBean.getMyFloat().floatValue() == 1.1f); + } + + public void testCustomTypeConverterWithBeanReference() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN); + lbf.setTypeConverter(new CustomTypeConverter(nf)); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("myFloat", new RuntimeBeanReference("myFloat")); + ConstructorArgumentValues cav = new ConstructorArgumentValues(); + cav.addIndexedArgumentValue(0, "myName"); + cav.addIndexedArgumentValue(1, "myAge"); + lbf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class, cav, pvs)); + lbf.registerSingleton("myFloat", "1,1"); + TestBean testBean = (TestBean) lbf.getBean("testBean"); + assertEquals("myName", testBean.getName()); + assertEquals(5, testBean.getAge()); + assertTrue(testBean.getMyFloat().floatValue() == 1.1f); + } + + public void testRegisterExistingSingletonWithReference() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("test.(class)", "org.springframework.beans.TestBean"); + p.setProperty("test.name", "Tony"); + p.setProperty("test.age", "48"); + p.setProperty("test.spouse(ref)", "singletonObject"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + Object singletonObject = new TestBean(); + lbf.registerSingleton("singletonObject", singletonObject); + + assertTrue(lbf.isSingleton("singletonObject")); + assertEquals(TestBean.class, lbf.getType("singletonObject")); + TestBean test = (TestBean) lbf.getBean("test"); + assertEquals(singletonObject, lbf.getBean("singletonObject")); + assertEquals(singletonObject, test.getSpouse()); + + Map beansOfType = lbf.getBeansOfType(TestBean.class, false, true); + assertEquals(2, beansOfType.size()); + assertTrue(beansOfType.containsValue(test)); + assertTrue(beansOfType.containsValue(singletonObject)); + + beansOfType = lbf.getBeansOfType(null, false, true); + assertEquals(2, beansOfType.size()); + } + + public void testRegisterExistingSingletonWithNameOverriding() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Properties p = new Properties(); + p.setProperty("test.(class)", "org.springframework.beans.TestBean"); + p.setProperty("test.name", "Tony"); + p.setProperty("test.age", "48"); + p.setProperty("test.spouse(ref)", "singletonObject"); + p.setProperty("singletonObject.(class)", "org.springframework.beans.factory.config.PropertiesFactoryBean"); + (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p); + Object singletonObject = new TestBean(); + lbf.registerSingleton("singletonObject", singletonObject); + lbf.preInstantiateSingletons(); + + assertTrue(lbf.isSingleton("singletonObject")); + assertEquals(TestBean.class, lbf.getType("singletonObject")); + TestBean test = (TestBean) lbf.getBean("test"); + assertEquals(singletonObject, lbf.getBean("singletonObject")); + assertEquals(singletonObject, test.getSpouse()); + + Map beansOfType = lbf.getBeansOfType(TestBean.class, false, true); + assertEquals(2, beansOfType.size()); + assertTrue(beansOfType.containsValue(test)); + assertTrue(beansOfType.containsValue(singletonObject)); + + beansOfType = lbf.getBeansOfType(null, false, true); + assertEquals(2, beansOfType.size()); + } + + public void testRegisterExistingSingletonWithAutowire() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Tony"); + pvs.addPropertyValue("age", "48"); + RootBeanDefinition bd = new RootBeanDefinition(DependenciesBean.class, pvs); + bd.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS); + bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE); + lbf.registerBeanDefinition("test", bd); + Object singletonObject = new TestBean(); + lbf.registerSingleton("singletonObject", singletonObject); + + assertTrue(lbf.containsBean("singletonObject")); + assertTrue(lbf.isSingleton("singletonObject")); + assertEquals(TestBean.class, lbf.getType("singletonObject")); + assertEquals(0, lbf.getAliases("singletonObject").length); + DependenciesBean test = (DependenciesBean) lbf.getBean("test"); + assertEquals(singletonObject, lbf.getBean("singletonObject")); + assertEquals(singletonObject, test.getSpouse()); + } + + public void testRegisterExistingSingletonWithAlreadyBound() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + Object singletonObject = new TestBean(); + lbf.registerSingleton("singletonObject", singletonObject); + try { + lbf.registerSingleton("singletonObject", singletonObject); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testReregisterBeanDefinition() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); + bd1.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + lbf.registerBeanDefinition("testBean", bd1); + assertTrue(lbf.getBean("testBean") instanceof TestBean); + RootBeanDefinition bd2 = new RootBeanDefinition(NestedTestBean.class); + bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + lbf.registerBeanDefinition("testBean", bd2); + assertTrue(lbf.getBean("testBean") instanceof NestedTestBean); + } + + public void testArrayPropertyWithAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); + bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); + + RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + bf.registerBeanDefinition("arrayBean", rbd); + ArrayBean ab = (ArrayBean) bf.getBean("arrayBean"); + + assertEquals(new UrlResource("http://localhost:8080"), ab.getResourceArray()[0]); + assertEquals(new UrlResource("http://localhost:9090"), ab.getResourceArray()[1]); + } + + public void testArrayPropertyWithOptionalAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + + RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + bf.registerBeanDefinition("arrayBean", rbd); + ArrayBean ab = (ArrayBean) bf.getBean("arrayBean"); + + assertNull(ab.getResourceArray()); + } + + public void testArrayConstructorWithAutowiring() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("integer1", new Integer(4)); + bf.registerSingleton("integer2", new Integer(5)); + + RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("arrayBean", rbd); + ArrayBean ab = (ArrayBean) bf.getBean("arrayBean"); + + assertEquals(new Integer(4), ab.getIntegerArray()[0]); + assertEquals(new Integer(5), ab.getIntegerArray()[1]); + } + + public void testArrayConstructorWithOptionalAutowiring() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + + RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("arrayBean", rbd); + ArrayBean ab = (ArrayBean) bf.getBean("arrayBean"); + + assertNull(ab.getIntegerArray()); + } + + public void testDoubleArrayConstructorWithAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("integer1", new Integer(4)); + bf.registerSingleton("integer2", new Integer(5)); + bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); + bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); + + RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("arrayBean", rbd); + ArrayBean ab = (ArrayBean) bf.getBean("arrayBean"); + + assertEquals(new Integer(4), ab.getIntegerArray()[0]); + assertEquals(new Integer(5), ab.getIntegerArray()[1]); + assertEquals(new UrlResource("http://localhost:8080"), ab.getResourceArray()[0]); + assertEquals(new UrlResource("http://localhost:9090"), ab.getResourceArray()[1]); + } + + public void testDoubleArrayConstructorWithOptionalAutowiring() throws MalformedURLException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); + bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); + + RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bf.registerBeanDefinition("arrayBean", rbd); + ArrayBean ab = (ArrayBean) bf.getBean("arrayBean"); + + assertNull(ab.getIntegerArray()); + assertNull(ab.getResourceArray()); + } + + public void testAutowireWithNoDependencies() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("rod", bd); + assertEquals(1, lbf.getBeanDefinitionCount()); + Object registered = lbf.autowire(NoDependencies.class, AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, false); + assertEquals(1, lbf.getBeanDefinitionCount()); + assertTrue(registered instanceof NoDependencies); + } + + public void testAutowireWithSatisfiedJavaBeanDependency() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, pvs); + lbf.registerBeanDefinition("rod", bd); + assertEquals(1, lbf.getBeanDefinitionCount()); + // Depends on age, name and spouse (TestBean) + Object registered = lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, true); + assertEquals(1, lbf.getBeanDefinitionCount()); + DependenciesBean kerry = (DependenciesBean) registered; + TestBean rod = (TestBean) lbf.getBean("rod"); + assertSame(rod, kerry.getSpouse()); + } + + public void testAutowireWithSatisfiedConstructorDependency() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, pvs); + lbf.registerBeanDefinition("rod", bd); + assertEquals(1, lbf.getBeanDefinitionCount()); + Object registered = lbf.autowire(ConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, false); + assertEquals(1, lbf.getBeanDefinitionCount()); + ConstructorDependency kerry = (ConstructorDependency) registered; + TestBean rod = (TestBean) lbf.getBean("rod"); + assertSame(rod, kerry.spouse); + } + + public void testAutowireWithTwoMatchesForConstructorDependency() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + lbf.registerBeanDefinition("rod", bd); + RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class); + lbf.registerBeanDefinition("rod2", bd2); + try { + lbf.autowire(ConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, false); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + // expected + assertTrue(ex.getMessage().indexOf("rod") != -1); + assertTrue(ex.getMessage().indexOf("rod2") != -1); + } + } + + public void testAutowireWithUnsatisfiedConstructorDependency() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("name", "Rod")); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, pvs); + lbf.registerBeanDefinition("rod", bd); + assertEquals(1, lbf.getBeanDefinitionCount()); + try { + lbf.autowire(UnsatisfiedConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, true); + fail("Should have unsatisfied constructor dependency on SideEffectBean"); + } + catch (UnsatisfiedDependencyException ex) { + // expected + } + } + + public void testAutowireConstructor() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spouse", bd); + ConstructorDependenciesBean bean = (ConstructorDependenciesBean) + lbf.autowire(ConstructorDependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true); + Object spouse = lbf.getBean("spouse"); + assertTrue(bean.getSpouse1() == spouse); + assertTrue(BeanFactoryUtils.beanOfType(lbf, TestBean.class) == spouse); + } + + public void testAutowireBeanByName() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spouse", bd); + DependenciesBean bean = (DependenciesBean) + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true); + TestBean spouse = (TestBean) lbf.getBean("spouse"); + assertEquals(spouse, bean.getSpouse()); + assertTrue(BeanFactoryUtils.beanOfType(lbf, TestBean.class) == spouse); + } + + public void testAutowireBeanByNameWithDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spous", bd); + try { + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + // expected + } + } + + public void testAutowireBeanByNameWithNoDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spous", bd); + DependenciesBean bean = (DependenciesBean) + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false); + assertNull(bean.getSpouse()); + } + + public void testAutowireBeanByType() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("test", bd); + DependenciesBean bean = (DependenciesBean) + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + TestBean test = (TestBean) lbf.getBean("test"); + assertEquals(test, bean.getSpouse()); + } + + /** + * Verifies that a dependency on a {@link FactoryBean} can be autowired + * by type, specifically addressing the JIRA issue raised in SPR-4040. + */ + public void testAutowireBeanWithFactoryBeanByType() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("factoryBean", bd); + LazyInitFactory factoryBean = (LazyInitFactory) lbf.getBean("&factoryBean"); + assertNotNull("The FactoryBean should have been registered.", factoryBean); + FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class, + AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + assertEquals("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.", + factoryBean, bean.getFactoryBean()); + } + + /** + * Verifies that a dependency on a {@link FactoryBean} can not + * be autowired by name, as & is an illegal character in + * Java method names. In other words, you can't name a method + * set&FactoryBean(...). + */ + public void testAutowireBeanWithFactoryBeanByName() { + new AssertThrows(TypeMismatchException.class) { + public void test() throws Exception { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("factoryBean", bd); + LazyInitFactory factoryBean = (LazyInitFactory) lbf.getBean("&factoryBean"); + assertNotNull("The FactoryBean should have been registered.", factoryBean); + lbf.autowire(FactoryBeanDependentBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true); + } + }.runTest(); + } + + public void testAutowireBeanByTypeWithTwoMatches() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("test", bd); + lbf.registerBeanDefinition("test2", bd2); + try { + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + // expected + assertTrue(ex.getMessage().indexOf("test") != -1); + assertTrue(ex.getMessage().indexOf("test2") != -1); + } + } + + public void testAutowireBeanByTypeWithDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + try { + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + // expected + } + } + + public void testAutowireBeanByTypeWithNoDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + DependenciesBean bean = (DependenciesBean) + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); + assertNull(bean.getSpouse()); + } + + public void testAutowireExistingBeanByName() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spouse", bd); + DependenciesBean existingBean = new DependenciesBean(); + lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true); + TestBean spouse = (TestBean) lbf.getBean("spouse"); + assertEquals(existingBean.getSpouse(), spouse); + assertSame(spouse, BeanFactoryUtils.beanOfType(lbf, TestBean.class)); + } + + public void testAutowireExistingBeanByNameWithDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spous", bd); + DependenciesBean existingBean = new DependenciesBean(); + try { + lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + // expected + } + } + + public void testAutowireExistingBeanByNameWithNoDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spous", bd); + DependenciesBean existingBean = new DependenciesBean(); + lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false); + assertNull(existingBean.getSpouse()); + } + + public void testAutowireExistingBeanByType() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("test", bd); + DependenciesBean existingBean = new DependenciesBean(); + lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + TestBean test = (TestBean) lbf.getBean("test"); + assertEquals(existingBean.getSpouse(), test); + } + + public void testAutowireExistingBeanByTypeWithDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + DependenciesBean existingBean = new DependenciesBean(); + try { + lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testAutowireExistingBeanByTypeWithNoDependencyCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + DependenciesBean existingBean = new DependenciesBean(); + lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); + assertNull(existingBean.getSpouse()); + } + + public void testInvalidAutowireMode() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + try { + lbf.autowireBeanProperties(new TestBean(), AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testApplyBeanPropertyValues() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "99"); + lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class, pvs)); + TestBean tb = new TestBean(); + assertEquals(0, tb.getAge()); + lbf.applyBeanPropertyValues(tb, "test"); + assertEquals(99, tb.getAge()); + } + + public void testApplyBeanPropertyValuesWithIncompleteDefinition() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "99"); + lbf.registerBeanDefinition("test", new RootBeanDefinition(null, pvs)); + TestBean tb = new TestBean(); + assertEquals(0, tb.getAge()); + lbf.applyBeanPropertyValues(tb, "test"); + assertEquals(99, tb.getAge()); + assertNull(tb.getBeanFactory()); + assertNull(tb.getSpouse()); + } + + public void testConfigureBean() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "99"); + lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class, pvs)); + TestBean tb = new TestBean(); + assertEquals(0, tb.getAge()); + lbf.configureBean(tb, "test"); + assertEquals(99, tb.getAge()); + assertSame(lbf, tb.getBeanFactory()); + assertNull(tb.getSpouse()); + } + + public void testConfigureBeanWithAutowiring() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, new MutablePropertyValues()); + lbf.registerBeanDefinition("spouse", bd); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "99"); + lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class, RootBeanDefinition.AUTOWIRE_BY_NAME)); + TestBean tb = new TestBean(); + lbf.configureBean(tb, "test"); + assertSame(lbf, tb.getBeanFactory()); + TestBean spouse = (TestBean) lbf.getBean("spouse"); + assertEquals(spouse, tb.getSpouse()); + } + + public void testExtensiveCircularReference() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + for (int i = 0; i < 1000; i++) { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("spouse", new RuntimeBeanReference("bean" + (i < 99 ? i + 1 : 0)))); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, pvs); + lbf.registerBeanDefinition("bean" + i, bd); + } + lbf.preInstantiateSingletons(); + for (int i = 0; i < 1000; i++) { + TestBean bean = (TestBean) lbf.getBean("bean" + i); + TestBean otherBean = (TestBean) lbf.getBean("bean" + (i < 99 ? i + 1 : 0)); + assertTrue(bean.getSpouse() == otherBean); + } + } + + public void testCircularReferenceThroughAutowiring() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(ConstructorDependencyBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)); + try { + lbf.preInstantiateSingletons(); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testCircularReferenceThroughFactoryBeanAutowiring() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(ConstructorDependencyFactoryBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)); + try { + lbf.preInstantiateSingletons(); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testCircularReferenceThroughFactoryBeanTypeCheck() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(ConstructorDependencyFactoryBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)); + try { + lbf.getBeansOfType(String.class); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testAvoidCircularReferenceThroughAutowiring() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(ConstructorDependencyFactoryBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)); + lbf.registerBeanDefinition("string", + new RootBeanDefinition(String.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)); + lbf.preInstantiateSingletons(); + } + + public void testBeanDefinitionWithInterface() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(ITestBean.class)); + try { + lbf.getBean("test"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertEquals("test", ex.getBeanName()); + assertTrue(ex.getMessage().toLowerCase().indexOf("interface") != -1); + } + } + + public void testBeanDefinitionWithAbstractClass() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(AbstractBeanFactory.class)); + try { + lbf.getBean("test"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertEquals("test", ex.getBeanName()); + assertTrue(ex.getMessage().toLowerCase().indexOf("abstract") != -1); + } + } + + public void testPrototypeFactoryBeanNotEagerlyCalled() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class)); + lbf.preInstantiateSingletons(); + } + + public void testLazyInitFactory() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(LazyInitFactory.class)); + lbf.preInstantiateSingletons(); + LazyInitFactory factory = (LazyInitFactory) lbf.getBean("&test"); + assertFalse(factory.initialized); + } + + public void testSmartInitFactory() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", new RootBeanDefinition(EagerInitFactory.class)); + lbf.preInstantiateSingletons(); + EagerInitFactory factory = (EagerInitFactory) lbf.getBean("&test"); + assertTrue(factory.initialized); + } + + public void testPrototypeFactoryBeanNotEagerlyCalledInCaseOfBeanClassName() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.registerBeanDefinition("test", + new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class.getName(), null, null)); + lbf.preInstantiateSingletons(); + } + + public void testPrototypeWithArrayConversionForConstructor() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + List list = new ManagedList(); + list.add("myName"); + list.add("myBeanName"); + RootBeanDefinition bd = new RootBeanDefinition(DerivedTestBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.getConstructorArgumentValues().addGenericArgumentValue(list); + lbf.registerBeanDefinition("test", bd); + DerivedTestBean tb = (DerivedTestBean) lbf.getBean("test"); + assertEquals("myName", tb.getName()); + assertEquals("myBeanName", tb.getBeanName()); + DerivedTestBean tb2 = (DerivedTestBean) lbf.getBean("test"); + assertTrue(tb != tb2); + assertEquals("myName", tb2.getName()); + assertEquals("myBeanName", tb2.getBeanName()); + } + + public void testPrototypeWithArrayConversionForFactoryMethod() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + List list = new ManagedList(); + list.add("myName"); + list.add("myBeanName"); + RootBeanDefinition bd = new RootBeanDefinition(DerivedTestBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setFactoryMethodName("create"); + bd.getConstructorArgumentValues().addGenericArgumentValue(list); + lbf.registerBeanDefinition("test", bd); + DerivedTestBean tb = (DerivedTestBean) lbf.getBean("test"); + assertEquals("myName", tb.getName()); + assertEquals("myBeanName", tb.getBeanName()); + DerivedTestBean tb2 = (DerivedTestBean) lbf.getBean("test"); + assertTrue(tb != tb2); + assertEquals("myName", tb2.getName()); + assertEquals("myBeanName", tb2.getBeanName()); + } + + public void testPrototypeCreationIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + lbf.registerBeanDefinition("test", rbd); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + lbf.getBean("test"); + } + sw.stop(); + // System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000); + } + + public void testPrototypeCreationWithDependencyCheckIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(LifecycleBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS); + lbf.registerBeanDefinition("test", rbd); + lbf.addBeanPostProcessor(new LifecycleBean.PostProcessor()); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + lbf.getBean("test"); + } + sw.stop(); + // System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000); + } + + /** + * public void testPrototypeCreationIsFastEnough2() throws Exception { + * if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + * // Skip this test: Trace logging blows the time limit. + * return; + * } + * DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + * Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class); + * Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class); + * StopWatch sw = new StopWatch(); + * sw.start("prototype"); + * for (int i = 0; i < 100000; i++) { + * TestBean tb = TestBean.class.newInstance(); + * setBeanNameMethod.invoke(tb, "test"); + * setBeanFactoryMethod.invoke(tb, lbf); + * } + * sw.stop(); + * // System.out.println(sw.getTotalTimeMillis()); + * assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 500); + * } + */ + + public void testPrototypeCreationWithConstructorArgumentsIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getConstructorArgumentValues().addGenericArgumentValue("juergen"); + rbd.getConstructorArgumentValues().addGenericArgumentValue("99"); + lbf.registerBeanDefinition("test", rbd); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) lbf.getBean("test"); + assertEquals("juergen", tb.getName()); + assertEquals(99, tb.getAge()); + } + sw.stop(); + // System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000); + } + + /** + * public void testPrototypeCreationWithConstructorArgumentsIsFastEnough2() throws Exception { + * if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + * // Skip this test: Trace logging blows the time limit. + * return; + * } + * DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + * Constructor ctor = TestBean.class.getConstructor(String.class, int.class); + * Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class); + * Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class); + * StopWatch sw = new StopWatch(); + * sw.start("prototype"); + * for (int i = 0; i < 100000; i++) { + * TestBean tb = ctor.newInstance("juergen", 99); + * setBeanNameMethod.invoke(tb, "test"); + * setBeanFactoryMethod.invoke(tb, lbf); + * assertEquals("juergen", tb.getName()); + * assertEquals(99, tb.getAge()); + * } + * sw.stop(); + * // System.out.println(sw.getTotalTimeMillis()); + * assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 1500); + * } + */ + + public void testPrototypeCreationWithResolvedConstructorArgumentsIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("spouse")); + lbf.registerBeanDefinition("test", rbd); + lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); + TestBean spouse = (TestBean) lbf.getBean("spouse"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) lbf.getBean("test"); + assertSame(spouse, tb.getSpouse()); + } + sw.stop(); + // System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + public void testPrototypeCreationWithPropertiesIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getPropertyValues().addPropertyValue("name", "juergen"); + rbd.getPropertyValues().addPropertyValue("age", "99"); + lbf.registerBeanDefinition("test", rbd); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) lbf.getBean("test"); + assertEquals("juergen", tb.getName()); + assertEquals(99, tb.getAge()); + } + sw.stop(); + // System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000); + } + + /** + * public void testPrototypeCreationWithPropertiesIsFastEnough2() throws Exception { + * if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + * // Skip this test: Trace logging blows the time limit. + * return; + * } + * DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + * StopWatch sw = new StopWatch(); + * Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class); + * Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class); + * Method setNameMethod = TestBean.class.getMethod("setName", String.class); + * Method setAgeMethod = TestBean.class.getMethod("setAge", int.class); + * sw.start("prototype"); + * for (int i = 0; i < 100000; i++) { + * TestBean tb = TestBean.class.newInstance(); + * setBeanNameMethod.invoke(tb, "test"); + * setBeanFactoryMethod.invoke(tb, lbf); + * setNameMethod.invoke(tb, "juergen"); + * setAgeMethod.invoke(tb, 99); + * } + * sw.stop(); + * // System.out.println(sw.getTotalTimeMillis()); + * assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 750); + * } + */ + + public void testPrototypeCreationWithResolvedPropertiesIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getPropertyValues().addPropertyValue("spouse", new RuntimeBeanReference("spouse")); + lbf.registerBeanDefinition("test", rbd); + lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); + TestBean spouse = (TestBean) lbf.getBean("spouse"); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) lbf.getBean("test"); + assertSame(spouse, tb.getSpouse()); + } + sw.stop(); + // System.out.println(sw.getTotalTimeMillis()); + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); + } + + public void testBeanPostProcessorWithWrappedObjectAndDisposableBean() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(BeanWithDisposableBean.class); + lbf.registerBeanDefinition("test", bd); + lbf.addBeanPostProcessor(new BeanPostProcessor() { + public Object postProcessBeforeInitialization(Object bean, String beanName) { + return new TestBean(); + } + + public Object postProcessAfterInitialization(Object bean, String beanName) { + return bean; + } + }); + BeanWithDisposableBean.closed = false; + lbf.preInstantiateSingletons(); + lbf.destroySingletons(); + assertTrue("Destroy method invoked", BeanWithDisposableBean.closed); + } + + public void testBeanPostProcessorWithWrappedObjectAndDestroyMethod() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class); + bd.setDestroyMethodName("close"); + lbf.registerBeanDefinition("test", bd); + lbf.addBeanPostProcessor(new BeanPostProcessor() { + public Object postProcessBeforeInitialization(Object bean, String beanName) { + return new TestBean(); + } + + public Object postProcessAfterInitialization(Object bean, String beanName) { + return bean; + } + }); + BeanWithDestroyMethod.closed = false; + lbf.preInstantiateSingletons(); + lbf.destroySingletons(); + assertTrue("Destroy method invoked", BeanWithDestroyMethod.closed); + } + + public void testFindTypeOfSingletonFactoryMethodOnBeanInstance() { + findTypeOfPrototypeFactoryMethodOnBeanInstance(true); + } + + public void testFindTypeOfPrototypeFactoryMethodOnBeanInstance() { + findTypeOfPrototypeFactoryMethodOnBeanInstance(false); + } + + /** + * @param singleton whether the bean created from the factory method on + * the bean instance should be a singleton or prototype. This flag is + * used to allow checking of the new ability in 1.2.4 to determine the type + * of a prototype created from invoking a factory method on a bean instance + * in the factory. + */ + private void findTypeOfPrototypeFactoryMethodOnBeanInstance(boolean singleton) { + String expectedNameFromProperties = "tony"; + String expectedNameFromArgs = "gordon"; + + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition instanceFactoryDefinition = new RootBeanDefinition(BeanWithFactoryMethod.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", expectedNameFromProperties); + instanceFactoryDefinition.setPropertyValues(pvs); + lbf.registerBeanDefinition("factoryBeanInstance", instanceFactoryDefinition); + + RootBeanDefinition factoryMethodDefinitionWithProperties = new RootBeanDefinition(); + factoryMethodDefinitionWithProperties.setFactoryBeanName("factoryBeanInstance"); + factoryMethodDefinitionWithProperties.setFactoryMethodName("create"); + if (!singleton) { + factoryMethodDefinitionWithProperties.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + } + lbf.registerBeanDefinition("fmWithProperties", factoryMethodDefinitionWithProperties); + + RootBeanDefinition factoryMethodDefinitionGeneric = new RootBeanDefinition(); + factoryMethodDefinitionGeneric.setFactoryBeanName("factoryBeanInstance"); + factoryMethodDefinitionGeneric.setFactoryMethodName("createGeneric"); + if (!singleton) { + factoryMethodDefinitionGeneric.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + } + lbf.registerBeanDefinition("fmGeneric", factoryMethodDefinitionGeneric); + + RootBeanDefinition factoryMethodDefinitionWithArgs = new RootBeanDefinition(); + factoryMethodDefinitionWithArgs.setFactoryBeanName("factoryBeanInstance"); + factoryMethodDefinitionWithArgs.setFactoryMethodName("createWithArgs"); + ConstructorArgumentValues cvals = new ConstructorArgumentValues(); + cvals.addGenericArgumentValue(expectedNameFromArgs); + factoryMethodDefinitionWithArgs.setConstructorArgumentValues(cvals); + if (!singleton) { + factoryMethodDefinitionWithArgs.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + } + lbf.registerBeanDefinition("fmWithArgs", factoryMethodDefinitionWithArgs); + + assertEquals(4, lbf.getBeanDefinitionCount()); + List tbNames = Arrays.asList(lbf.getBeanNamesForType(TestBean.class)); + assertTrue(tbNames.contains("fmWithProperties")); + assertTrue(tbNames.contains("fmWithArgs")); + assertEquals(2, tbNames.size()); + + TestBean tb = (TestBean) lbf.getBean("fmWithProperties"); + TestBean second = (TestBean) lbf.getBean("fmWithProperties"); + if (singleton) { + assertSame(tb, second); + } + else { + assertNotSame(tb, second); + } + assertEquals(expectedNameFromProperties, tb.getName()); + + tb = (TestBean) lbf.getBean("fmGeneric"); + second = (TestBean) lbf.getBean("fmGeneric"); + if (singleton) { + assertSame(tb, second); + } + else { + assertNotSame(tb, second); + } + assertEquals(expectedNameFromProperties, tb.getName()); + + TestBean tb2 = (TestBean) lbf.getBean("fmWithArgs"); + second = (TestBean) lbf.getBean("fmWithArgs"); + if (singleton) { + assertSame(tb2, second); + } + else { + assertNotSame(tb2, second); + } + assertEquals(expectedNameFromArgs, tb2.getName()); + } + + public void testScopingBeanToUnregisteredScopeResultsInAnException() throws Exception { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); + AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); + beanDefinition.setScope("he put himself so low could hardly look me in the face"); + + final DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("testBean", beanDefinition); + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + factory.getBean("testBean"); + } + }.runTest(); + } + + public void testExplicitScopeInheritanceForChildBeanDefinitions() throws Exception { + String theChildScope = "bonanza!"; + + RootBeanDefinition parent = new RootBeanDefinition(); + parent.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + + AbstractBeanDefinition child = BeanDefinitionBuilder + .childBeanDefinition("parent").getBeanDefinition(); + child.setBeanClass(TestBean.class); + child.setScope(theChildScope); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("parent", parent); + factory.registerBeanDefinition("child", child); + + AbstractBeanDefinition def = (AbstractBeanDefinition) factory.getBeanDefinition("child"); + assertEquals("Child 'scope' not overriding parent scope (it must).", theChildScope, def.getScope()); + } + + public void testImplicitScopeInheritanceForChildBeanDefinitions() throws Exception { + RootBeanDefinition parent = new RootBeanDefinition(); + parent.setScope("bonanza!"); + + AbstractBeanDefinition child = new ChildBeanDefinition("parent"); + child.setBeanClass(TestBean.class); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("parent", parent); + factory.registerBeanDefinition("child", child); + + BeanDefinition def = factory.getMergedBeanDefinition("child"); + assertTrue("Child 'scope' not overriding parent scope (it must).", def.isSingleton()); + } + + public void testFieldSettingWithInstantiationAwarePostProcessorNoShortCircuit() { + doTestFieldSettingWithInstantiationAwarePostProcessor(false); + } + + public void testFieldSettingWithInstantiationAwarePostProcessorWithShortCircuit() { + doTestFieldSettingWithInstantiationAwarePostProcessor(true); + } + + private void doTestFieldSettingWithInstantiationAwarePostProcessor(final boolean skipPropertyPopulation) { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + int ageSetByPropertyValue = 27; + bd.getPropertyValues().addPropertyValue(new PropertyValue("age", new Integer(ageSetByPropertyValue))); + lbf.registerBeanDefinition("test", bd); + final String nameSetOnField = "nameSetOnField"; + lbf.addBeanPostProcessor(new InstantiationAwareBeanPostProcessorAdapter() { + public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { + TestBean tb = (TestBean) bean; + try { + Field f = TestBean.class.getDeclaredField("name"); + f.setAccessible(true); + f.set(tb, nameSetOnField); + return !skipPropertyPopulation; + } + catch (Exception ex) { + fail("Unexpected exception: " + ex); + // Keep compiler happy about return + throw new IllegalStateException(); + } + } + }); + lbf.preInstantiateSingletons(); + TestBean tb = (TestBean) lbf.getBean("test"); + assertEquals("Name was set on field by IAPP", nameSetOnField, tb.getName()); + if (!skipPropertyPopulation) { + assertEquals("Property value still set", ageSetByPropertyValue, tb.getAge()); + } + else { + assertEquals("Property value was NOT set and still has default value", 0, tb.getAge()); + } + } + + public void testInitSecurityAwarePrototypeBean() { + final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestSecuredBean.class); + bd.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE); + bd.setInitMethodName("init"); + lbf.registerBeanDefinition("test", bd); + final Subject subject = new Subject(); + subject.getPrincipals().add(new TestPrincipal("user1")); + TestSecuredBean bean = (TestSecuredBean) Subject.doAsPrivileged(subject, + new PrivilegedAction() { + public Object run() { + return lbf.getBean("test"); + } + }, null); + assertNotNull(bean); + assertEquals("user1", bean.getUserName()); + } + + + public static class NoDependencies { + + private NoDependencies() { + } + } + + + public static class ConstructorDependency { + + public TestBean spouse; + + public ConstructorDependency(TestBean spouse) { + this.spouse = spouse; + } + + private ConstructorDependency(TestBean spouse, TestBean otherSpouse) { + throw new IllegalArgumentException("Should never be called"); + } + } + + + public static class UnsatisfiedConstructorDependency { + + public UnsatisfiedConstructorDependency(TestBean t, SideEffectBean b) { + } + } + + + public static class ConstructorDependencyBean { + + public ConstructorDependencyBean(ConstructorDependencyBean dependency) { + } + } + + + public static class ConstructorDependencyFactoryBean implements FactoryBean { + + public ConstructorDependencyFactoryBean(String dependency) { + } + + public Object getObject() { + return "test"; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + } + + + public static class BeanWithDisposableBean implements DisposableBean { + + private static boolean closed; + + public void destroy() { + closed = true; + } + } + + + public static class BeanWithDestroyMethod { + + private static boolean closed; + + public void close() { + closed = true; + } + } + + + public static class BeanWithFactoryMethod { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public TestBean create() { + TestBean tb = new TestBean(); + tb.setName(this.name); + return tb; + } + + public TestBean createWithArgs(String arg) { + TestBean tb = new TestBean(); + tb.setName(arg); + return tb; + } + + public Object createGeneric() { + return create(); + } + } + + + public static class FactoryBeanThatShouldntBeCalled implements FactoryBean { + + public Object getObject() { + throw new IllegalStateException(); + } + + public Class getObjectType() { + return null; + } + + public boolean isSingleton() { + return false; + } + } + + + public static class LazyInitFactory implements FactoryBean { + + public boolean initialized = false; + + public Object getObject() throws Exception { + this.initialized = true; + return ""; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + } + + + public static class EagerInitFactory implements SmartFactoryBean { + + public boolean initialized = false; + + public Object getObject() throws Exception { + this.initialized = true; + return ""; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + + public boolean isPrototype() { + return false; + } + + public boolean isEagerInit() { + return true; + } + } + + + public static class TestBeanFactory { + + public static boolean initialized = false; + + public TestBeanFactory() { + initialized = true; + } + + public static TestBean createTestBean() { + return new TestBean(); + } + + public TestBean createTestBeanNonStatic() { + return new TestBean(); + } + } + + + public static class ArrayBean { + + private Integer[] integerArray; + + private Resource[] resourceArray; + + public ArrayBean() { + } + + public ArrayBean(Integer[] integerArray) { + this.integerArray = integerArray; + } + + public ArrayBean(Integer[] integerArray, Resource[] resourceArray) { + this.integerArray = integerArray; + this.resourceArray = resourceArray; + } + + public Integer[] getIntegerArray() { + return this.integerArray; + } + + public void setResourceArray(Resource[] resourceArray) { + this.resourceArray = resourceArray; + } + + public Resource[] getResourceArray() { + return this.resourceArray; + } + } + + + /** + * Bean with a dependency on a {@link FactoryBean}. + */ + private static class FactoryBeanDependentBean { + + private FactoryBean factoryBean; + + + public final FactoryBean getFactoryBean() { + return this.factoryBean; + } + + public final void setFactoryBean(final FactoryBean factoryBean) { + this.factoryBean = factoryBean; + } + } + + + private static class CustomTypeConverter implements TypeConverter { + + private final NumberFormat numberFormat; + + public CustomTypeConverter(NumberFormat numberFormat) { + this.numberFormat = numberFormat; + } + + public Object convertIfNecessary(Object value, Class requiredType) { + return convertIfNecessary(value, requiredType, null); + } + + public Object convertIfNecessary(Object value, Class requiredType, MethodParameter methodParam) { + if (value instanceof String && Float.class.isAssignableFrom(requiredType)) { + try { + return new Float(this.numberFormat.parse((String) value).floatValue()); + } + catch (ParseException ex) { + throw new TypeMismatchException(value, requiredType, ex); + } + } + else if (value instanceof String && int.class.isAssignableFrom(requiredType)) { + return new Integer(5); + } + else { + return value; + } + } + } + + + private static class TestPrincipal implements Principal { + + private String name; + + public TestPrincipal(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof TestPrincipal)) { + return false; + } + TestPrincipal p = (TestPrincipal) obj; + return this.name.equals(p.name); + } + + public int hashCode() { + return this.name.hashCode(); + } + } + + + private static class TestSecuredBean { + + private String userName; + + public void init() { + Subject subject = Subject.getSubject(AccessController.getContext()); + if (subject == null) { + return; + } + setNameFromPrincipal(subject.getPrincipals()); + } + + private void setNameFromPrincipal(Set principals) { + if (principals == null) { + return; + } + for (Iterator it = principals.iterator(); it.hasNext();) { + Principal p = (Principal) it.next(); + this.userName = p.getName(); + return; + } + } + + public String getUserName() { + return this.userName; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DummyFactory.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DummyFactory.java new file mode 100644 index 00000000000..020e683d7d8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/DummyFactory.java @@ -0,0 +1,172 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import org.springframework.beans.BeansException; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; + +/** + * Simple factory to allow testing of FactoryBean support in AbstractBeanFactory. + * Depending on whether its singleton property is set, it will return a singleton + * or a prototype instance. + * + *

Implements InitializingBean interface, so we can check that + * factories get this lifecycle callback if they want. + * + * @author Rod Johnson + * @since 10.03.2003 + */ +public class DummyFactory + implements FactoryBean, BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean { + + public static final String SINGLETON_NAME = "Factory singleton"; + + private static boolean prototypeCreated; + + /** + * Clear static state. + */ + public static void reset() { + prototypeCreated = false; + } + + + /** + * Default is for factories to return a singleton instance. + */ + private boolean singleton = true; + + private String beanName; + + private AutowireCapableBeanFactory beanFactory; + + private boolean postProcessed; + + private boolean initialized; + + private TestBean testBean; + + private TestBean otherTestBean; + + + public DummyFactory() { + this.testBean = new TestBean(); + this.testBean.setName(SINGLETON_NAME); + this.testBean.setAge(25); + } + + /** + * Return if the bean managed by this factory is a singleton. + * @see org.springframework.beans.factory.FactoryBean#isSingleton() + */ + public boolean isSingleton() { + return this.singleton; + } + + /** + * Set if the bean managed by this factory is a singleton. + */ + public void setSingleton(boolean singleton) { + this.singleton = singleton; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = (AutowireCapableBeanFactory) beanFactory; + this.beanFactory.applyBeanPostProcessorsBeforeInitialization(this.testBean, this.beanName); + } + + public BeanFactory getBeanFactory() { + return beanFactory; + } + + public void setPostProcessed(boolean postProcessed) { + this.postProcessed = postProcessed; + } + + public boolean isPostProcessed() { + return postProcessed; + } + + public void setOtherTestBean(TestBean otherTestBean) { + this.otherTestBean = otherTestBean; + this.testBean.setSpouse(otherTestBean); + } + + public TestBean getOtherTestBean() { + return otherTestBean; + } + + public void afterPropertiesSet() { + if (initialized) { + throw new RuntimeException("Cannot call afterPropertiesSet twice on the one bean"); + } + this.initialized = true; + } + + /** + * Was this initialized by invocation of the + * afterPropertiesSet() method from the InitializingBean interface? + */ + public boolean wasInitialized() { + return initialized; + } + + public static boolean wasPrototypeCreated() { + return prototypeCreated; + } + + + /** + * Return the managed object, supporting both singleton + * and prototype mode. + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + public Object getObject() throws BeansException { + if (isSingleton()) { + return this.testBean; + } + else { + TestBean prototype = new TestBean("prototype created at " + System.currentTimeMillis(), 11); + if (this.beanFactory != null) { + this.beanFactory.applyBeanPostProcessorsBeforeInitialization(prototype, this.beanName); + } + prototypeCreated = true; + return prototype; + } + } + + public Class getObjectType() { + return TestBean.class; + } + + + public void destroy() { + if (this.testBean != null) { + this.testBean.setName(null); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java new file mode 100644 index 00000000000..d2f306333b1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java @@ -0,0 +1,149 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.Assert; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class FactoryBeanTests extends TestCase { + + public void testFactoryBeanReturnsNull() throws Exception { + XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("factoryBeanReturnsNull.xml", getClass())); + Object result = factory.getBean("factoryBean"); + assertNull(result); + } + + public void testFactoryBeansWithAutowiring() throws Exception { + ClassPathXmlApplicationContext factory = + new ClassPathXmlApplicationContext("factoryBeansWithAutowiring.xml", getClass()); + Alpha alpha = (Alpha) factory.getBean("alpha"); + Beta beta = (Beta) factory.getBean("beta"); + Gamma gamma = (Gamma) factory.getBean("gamma"); + Gamma gamma2 = (Gamma) factory.getBean("gammaFactory"); + assertSame(beta, alpha.getBeta()); + assertSame(gamma, beta.getGamma()); + assertSame(gamma2, beta.getGamma()); + assertEquals("yourName", beta.getName()); + } + + public void testFactoryBeansWithIntermediateFactoryBeanAutowiringFailure() throws Exception { + ClassPathXmlApplicationContext factory = + new ClassPathXmlApplicationContext("factoryBeansWithAutowiring.xml", getClass()); + Beta beta = (Beta) factory.getBean("beta"); + Alpha alpha = (Alpha) factory.getBean("alpha"); + Gamma gamma = (Gamma) factory.getBean("gamma"); + assertSame(beta, alpha.getBeta()); + assertSame(gamma, beta.getGamma()); + } + + + public static class NullReturningFactoryBean implements FactoryBean { + + public Object getObject() { + return null; + } + + public Class getObjectType() { + return null; + } + + public boolean isSingleton() { + return true; + } + } + + + public static class Alpha implements InitializingBean { + + private Beta beta; + + public void setBeta(Beta beta) { + this.beta = beta; + } + + public Beta getBeta() { + return beta; + } + + public void afterPropertiesSet() { + Assert.notNull(beta, "'beta' property is required"); + } + } + + + public static class Beta implements InitializingBean { + + private Gamma gamma; + + private String name; + + public void setGamma(Gamma gamma) { + this.gamma = gamma; + } + + public Gamma getGamma() { + return gamma; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void afterPropertiesSet() { + Assert.notNull(gamma, "'gamma' property is required"); + } + } + + + public static class Gamma { + } + + + public static class BetaFactoryBean implements FactoryBean { + + private Beta beta; + + public void setBeta(Beta beta) { + this.beta = beta; + } + + public Object getObject() { + return this.beta; + } + + public Class getObjectType() { + return null; + } + + public boolean isSingleton() { + return true; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/HasMap.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/HasMap.java new file mode 100644 index 00000000000..3bac49498b5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/HasMap.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * Bean exposing a map. Used for bean factory tests. + * + * @author Rod Johnson + * @since 05.06.2003 + */ +public class HasMap { + + private Map map; + + private Set set; + + private Properties props; + + private Object[] objectArray; + + private Class[] classArray; + + private Integer[] intArray; + + private HasMap() { + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public Set getSet() { + return set; + } + + public void setSet(Set set) { + this.set = set; + } + + public Properties getProps() { + return props; + } + + public void setProps(Properties props) { + this.props = props; + } + + public Object[] getObjectArray() { + return objectArray; + } + + public void setObjectArray(Object[] objectArray) { + this.objectArray = objectArray; + } + + public Class[] getClassArray() { + return classArray; + } + + public void setClassArray(Class[] classArray) { + this.classArray = classArray; + } + + public Integer[] getIntegerArray() { + return intArray; + } + + public void setIntegerArray(Integer[] is) { + intArray = is; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/KnowsIfInstantiated.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/KnowsIfInstantiated.java new file mode 100644 index 00000000000..1bb269dfb7f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/KnowsIfInstantiated.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +public class KnowsIfInstantiated { + + private static boolean instantiated; + + public static void clearInstantiationRecord() { + instantiated = false; + } + + public static boolean wasInstantiated() { + return instantiated; + } + + public KnowsIfInstantiated() { + instantiated = true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/LifecycleBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/LifecycleBean.java new file mode 100644 index 00000000000..ebbbf1c7f86 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/LifecycleBean.java @@ -0,0 +1,158 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * Simple test of BeanFactory initialization and lifecycle callbacks. + * + * @author Rod Johnson + * @author Colin Sampaleanu + * @since 12.03.2003 + */ +public class LifecycleBean implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean { + + protected boolean initMethodDeclared = false; + + protected String beanName; + + protected BeanFactory owningFactory; + + protected boolean postProcessedBeforeInit; + + protected boolean inited; + + protected boolean initedViaDeclaredInitMethod; + + protected boolean postProcessedAfterInit; + + protected boolean destroyed; + + + public void setInitMethodDeclared(boolean initMethodDeclared) { + this.initMethodDeclared = initMethodDeclared; + } + + public boolean isInitMethodDeclared() { + return initMethodDeclared; + } + + public void setBeanName(String name) { + this.beanName = name; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanFactory(BeanFactory beanFactory) { + this.owningFactory = beanFactory; + } + + public void postProcessBeforeInit() { + if (this.inited || this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory called postProcessBeforeInit after afterPropertiesSet"); + } + if (this.postProcessedBeforeInit) { + throw new RuntimeException("Factory called postProcessBeforeInit twice"); + } + this.postProcessedBeforeInit = true; + } + + public void afterPropertiesSet() { + if (this.owningFactory == null) { + throw new RuntimeException("Factory didn't call setBeanFactory before afterPropertiesSet on lifecycle bean"); + } + if (!this.postProcessedBeforeInit) { + throw new RuntimeException("Factory didn't call postProcessBeforeInit before afterPropertiesSet on lifecycle bean"); + } + if (this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory initialized via declared init method before initializing via afterPropertiesSet"); + } + if (this.inited) { + throw new RuntimeException("Factory called afterPropertiesSet twice"); + } + this.inited = true; + } + + public void declaredInitMethod() { + if (!this.inited) { + throw new RuntimeException("Factory didn't call afterPropertiesSet before declared init method"); + } + + if (this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory called declared init method twice"); + } + this.initedViaDeclaredInitMethod = true; + } + + public void postProcessAfterInit() { + if (!this.inited) { + throw new RuntimeException("Factory called postProcessAfterInit before afterPropertiesSet"); + } + if (this.initMethodDeclared && !this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory called postProcessAfterInit before calling declared init method"); + } + if (this.postProcessedAfterInit) { + throw new RuntimeException("Factory called postProcessAfterInit twice"); + } + this.postProcessedAfterInit = true; + } + + /** + * Dummy business method that will fail unless the factory + * managed the bean's lifecycle correctly + */ + public void businessMethod() { + if (!this.inited || (this.initMethodDeclared && !this.initedViaDeclaredInitMethod) || + !this.postProcessedAfterInit) { + throw new RuntimeException("Factory didn't initialize lifecycle object correctly"); + } + } + + public void destroy() { + if (this.destroyed) { + throw new IllegalStateException("Already destroyed"); + } + this.destroyed = true; + } + + public boolean isDestroyed() { + return destroyed; + } + + + public static class PostProcessor implements BeanPostProcessor { + + public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException { + if (bean instanceof LifecycleBean) { + ((LifecycleBean) bean).postProcessBeforeInit(); + } + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String name) throws BeansException { + if (bean instanceof LifecycleBean) { + ((LifecycleBean) bean).postProcessAfterInit(); + } + return bean; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/MustBeInitialized.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/MustBeInitialized.java new file mode 100644 index 00000000000..1dedf6624c2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/MustBeInitialized.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +/** + * Simple test of BeanFactory initialization + * @author Rod Johnson + * @since 12.03.2003 + */ +public class MustBeInitialized implements InitializingBean { + + private boolean inited; + + /** + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + this.inited = true; + } + + /** + * Dummy business method that will fail unless the factory + * managed the bean's lifecycle correctly + */ + public void businessMethod() { + if (!this.inited) + throw new RuntimeException("Factory didn't call afterPropertiesSet() on MustBeInitialized object"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/PackageLevelVisibleBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/PackageLevelVisibleBean.java new file mode 100644 index 00000000000..6172590caab --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/PackageLevelVisibleBean.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +/** + * Used in the tests for the FieldRetrievingFactoryBean class + * (c.f. FieldRetrievingFactoryBeanTests) + * + * @author Rick Evans + */ +class PackageLevelVisibleBean { + + public static final String CONSTANT = "Wuby"; +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/SharedBeanRegistryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/SharedBeanRegistryTests.java new file mode 100644 index 00000000000..0b960a36eab --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/SharedBeanRegistryTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory; + +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.springframework.beans.BeansException; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry; + +/** + * @author Juergen Hoeller + * @since 04.07.2006 + */ +public class SharedBeanRegistryTests extends TestCase { + + public void testSingletons() { + DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry(); + + TestBean tb = new TestBean(); + beanRegistry.registerSingleton("tb", tb); + assertSame(tb, beanRegistry.getSingleton("tb")); + + TestBean tb2 = (TestBean) beanRegistry.getSingleton("tb2", new ObjectFactory() { + public Object getObject() throws BeansException { + return new TestBean(); + } + }); + assertSame(tb2, beanRegistry.getSingleton("tb2")); + + assertSame(tb, beanRegistry.getSingleton("tb")); + assertSame(tb2, beanRegistry.getSingleton("tb2")); + assertEquals(2, beanRegistry.getSingletonCount()); + assertEquals(2, beanRegistry.getSingletonNames().length); + assertTrue(Arrays.asList(beanRegistry.getSingletonNames()).contains("tb")); + assertTrue(Arrays.asList(beanRegistry.getSingletonNames()).contains("tb2")); + + beanRegistry.destroySingletons(); + assertEquals(0, beanRegistry.getSingletonCount()); + assertEquals(0, beanRegistry.getSingletonNames().length); + } + + public void testDisposableBean() { + DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry(); + + DerivedTestBean tb = new DerivedTestBean(); + beanRegistry.registerSingleton("tb", tb); + beanRegistry.registerDisposableBean("tb", tb); + assertSame(tb, beanRegistry.getSingleton("tb")); + + assertSame(tb, beanRegistry.getSingleton("tb")); + assertEquals(1, beanRegistry.getSingletonCount()); + assertEquals(1, beanRegistry.getSingletonNames().length); + assertTrue(Arrays.asList(beanRegistry.getSingletonNames()).contains("tb")); + assertFalse(tb.wasDestroyed()); + + beanRegistry.destroySingletons(); + assertEquals(0, beanRegistry.getSingletonCount()); + assertEquals(0, beanRegistry.getSingletonNames().length); + assertTrue(tb.wasDestroyed()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java new file mode 100644 index 00000000000..cf9f7f071b8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java @@ -0,0 +1,186 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.access; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.util.ClassUtils; + +/** + * @author Colin Sampaleanu + */ +public class SingletonBeanFactoryLocatorTests extends TestCase { + + public void testBaseBeanFactoryDefs() { + // Just test the base BeanFactory/AppContext defs we are going to work with + // in other tests. + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "/org/springframework/beans/factory/access/beans*.xml"); + } + + public void testBasicFunctionality() { + SingletonBeanFactoryLocator facLoc = new SingletonBeanFactoryLocator( + "classpath*:" + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + + basicFunctionalityTest(facLoc); + } + + /** + * Worker method so subclass can use it too. + */ + protected void basicFunctionalityTest(SingletonBeanFactoryLocator facLoc) { + BeanFactoryReference bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + BeanFactory fac = bfr.getFactory(); + BeanFactoryReference bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + TestBean tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + BeanFactoryReference bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + BeanFactoryReference bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + // Now verify that we can call release in any order. + // Unfortunately this doesn't validate complete release after the last one. + bfr2.release(); + bfr3.release(); + bfr.release(); + bfr4.release(); + } + + /** + * This test can run multiple times, but due to static keyed lookup of the locators, + * 2nd and subsequent calls will actuall get back same locator instance. This is not + * an issue really, since the contained beanfactories will still be loaded and released. + */ + public void testGetInstance() { + // Try with and without 'classpath*:' prefix, and with 'classpath:' prefix. + BeanFactoryLocator facLoc = SingletonBeanFactoryLocator.getInstance( + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + getInstanceTest1(facLoc); + + facLoc = SingletonBeanFactoryLocator.getInstance( + "classpath*:/" + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + getInstanceTest2(facLoc); + + // This will actually get another locator instance, as the key is the resource name. + facLoc = SingletonBeanFactoryLocator.getInstance( + "classpath:" + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + getInstanceTest3(facLoc); + + } + + /** + * Worker method so subclass can use it too + */ + protected void getInstanceTest1(BeanFactoryLocator facLoc) { + BeanFactoryReference bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + BeanFactory fac = bfr.getFactory(); + BeanFactoryReference bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + TestBean tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + BeanFactoryReference bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + + BeanFactoryReference bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + + bfr.release(); + bfr3.release(); + bfr2.release(); + bfr4.release(); + } + + /** + * Worker method so subclass can use it too + */ + protected void getInstanceTest2(BeanFactoryLocator facLoc) { + BeanFactoryReference bfr; + BeanFactory fac; + BeanFactoryReference bfr2; + TestBean tb; + BeanFactoryReference bfr3; + BeanFactoryReference bfr4; + bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + fac = bfr.getFactory(); + bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr.release(); + bfr2.release(); + bfr4.release(); + bfr3.release(); + } + + /** + * Worker method so subclass can use it too + */ + protected void getInstanceTest3(BeanFactoryLocator facLoc) { + BeanFactoryReference bfr; + BeanFactory fac; + BeanFactoryReference bfr2; + TestBean tb; + BeanFactoryReference bfr3; + BeanFactoryReference bfr4; + bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + fac = bfr.getFactory(); + bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr4.release(); + bfr3.release(); + bfr2.release(); + bfr.release(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/TestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/TestBean.java new file mode 100644 index 00000000000..27cccb45603 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/TestBean.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.access; + +import java.util.List; + +/** + * Scrap bean for use in tests. + * + * @author Colin Sampaleanu + */ +public class TestBean { + + private String name; + + private List list; + + private Object objRef; + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return Returns the list. + */ + public List getList() { + return list; + } + + /** + * @param list The list to set. + */ + public void setList(List list) { + this.list = list; + } + + /** + * @return Returns the object. + */ + public Object getObjRef() { + return objRef; + } + + /** + * @param object The object to set. + */ + public void setObjRef(Object object) { + this.objRef = object; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans1.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans1.xml new file mode 100644 index 00000000000..10581610497 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans1.xml @@ -0,0 +1,16 @@ + + + + + + + + beans1.bean1 + + + + bean2 + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans2.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans2.xml new file mode 100644 index 00000000000..a5167f6bfe6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/beans2.xml @@ -0,0 +1,16 @@ + + + + + + + + beans2.bean1 + + + + beans2.bean2 + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/ref1.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/ref1.xml new file mode 100644 index 00000000000..a90e6063ed6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/access/ref1.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/concurrent.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/concurrent.xml new file mode 100644 index 00000000000..c88fd668a30 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/concurrent.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/BeanFactoryPostProcessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/BeanFactoryPostProcessorTests.java new file mode 100644 index 00000000000..71382d98470 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/BeanFactoryPostProcessorTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import junit.framework.TestCase; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.StaticApplicationContext; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @since 02.10.2003 + */ +public class BeanFactoryPostProcessorTests extends TestCase { + + public void testRegisteredBeanFactoryPostProcessor() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb1", TestBean.class); + ac.registerSingleton("tb2", TestBean.class); + TestBeanFactoryPostProcessor bfpp = new TestBeanFactoryPostProcessor(); + ac.addBeanFactoryPostProcessor(bfpp); + assertFalse(bfpp.wasCalled); + ac.refresh(); + assertTrue(bfpp.wasCalled); + } + + public void testDefinedBeanFactoryPostProcessor() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb1", TestBean.class); + ac.registerSingleton("tb2", TestBean.class); + ac.registerSingleton("bfpp", TestBeanFactoryPostProcessor.class); + ac.refresh(); + TestBeanFactoryPostProcessor bfpp = (TestBeanFactoryPostProcessor) ac.getBean("bfpp"); + assertTrue(bfpp.wasCalled); + } + + public void testMultipleDefinedBeanFactoryPostProcessors() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb1", TestBean.class); + ac.registerSingleton("tb2", TestBean.class); + MutablePropertyValues pvs1 = new MutablePropertyValues(); + pvs1.addPropertyValue("initValue", "${key}"); + ac.registerSingleton("bfpp1", TestBeanFactoryPostProcessor.class, pvs1); + MutablePropertyValues pvs2 = new MutablePropertyValues(); + pvs2.addPropertyValue("properties", "key=value"); + ac.registerSingleton("bfpp2", PropertyPlaceholderConfigurer.class, pvs2); + ac.refresh(); + TestBeanFactoryPostProcessor bfpp = (TestBeanFactoryPostProcessor) ac.getBean("bfpp1"); + assertEquals("value", bfpp.initValue); + assertTrue(bfpp.wasCalled); + } + + public void testBeanFactoryPostProcessorNotExecutedByBeanFactory() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("tb1", new RootBeanDefinition(TestBean.class)); + bf.registerBeanDefinition("tb2", new RootBeanDefinition(TestBean.class)); + bf.registerBeanDefinition("bfpp", new RootBeanDefinition(TestBeanFactoryPostProcessor.class)); + TestBeanFactoryPostProcessor bfpp = (TestBeanFactoryPostProcessor) bf.getBean("bfpp"); + assertFalse(bfpp.wasCalled); + } + + + public static class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + public String initValue; + + public void setInitValue(String initValue) { + this.initValue = initValue; + } + + public boolean wasCalled = false; + + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + wasCalled = true; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CommonsLogFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CommonsLogFactoryBeanTests.java new file mode 100644 index 00000000000..b7afe8f4d0e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CommonsLogFactoryBeanTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link CommonsLogFactoryBean} class. + * + * @author Rick Evans + */ +public final class CommonsLogFactoryBeanTests extends TestCase { + + public void testIsSingleton() throws Exception { + CommonsLogFactoryBean factory = new CommonsLogFactoryBean(); + assertTrue(factory.isSingleton()); + } + + public void testGetObjectTypeDefaultsToPlainResourceInterfaceifLookupResourceIsNotSupplied() throws Exception { + CommonsLogFactoryBean factory = new CommonsLogFactoryBean(); + assertEquals(Log.class, factory.getObjectType()); + } + + public void testWhenLogNameIsMissing() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + CommonsLogFactoryBean factory = new CommonsLogFactoryBean(); + factory.afterPropertiesSet(); + } + }.runTest(); + } + + public void testSunnyDayPath() throws Exception { + CommonsLogFactoryBean factory = new CommonsLogFactoryBean(); + factory.setLogName("The Tin Drum"); + factory.afterPropertiesSet(); + Object object = factory.getObject(); + + assertNotNull("As per FactoryBean contract, the return value of getObject() cannot be null.", object); + assertTrue("Obviously not getting a Log back", Log.class.isAssignableFrom(object.getClass())); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java new file mode 100644 index 00000000000..df3faa10a56 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java @@ -0,0 +1,171 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.beans.PropertyEditorSupport; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.propertyeditors.CustomDateEditor; + +/** + * @author Juergen Hoeller + * @since 31.07.2004 + */ +public class CustomEditorConfigurerTests extends TestCase { + + public void testCustomEditorConfigurerWithRequiredTypeAsClassName() throws ParseException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CustomEditorConfigurer cec = new CustomEditorConfigurer(); + Map editors = new HashMap(); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN); + editors.put(Date.class.getName(), new CustomDateEditor(df, true)); + cec.setCustomEditors(editors); + cec.postProcessBeanFactory(bf); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("date", "2.12.1975"); + bf.registerBeanDefinition("tb1", new RootBeanDefinition(TestBean.class, pvs)); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("someMap[myKey]", new TypedStringValue("2.12.1975", Date.class)); + bf.registerBeanDefinition("tb2", new RootBeanDefinition(TestBean.class, pvs)); + + TestBean tb1 = (TestBean) bf.getBean("tb1"); + assertEquals(df.parse("2.12.1975"), tb1.getDate()); + TestBean tb2 = (TestBean) bf.getBean("tb2"); + assertEquals(df.parse("2.12.1975"), tb2.getSomeMap().get("myKey")); + } + + public void testCustomEditorConfigurerWithRequiredTypeAsClass() throws ParseException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CustomEditorConfigurer cec = new CustomEditorConfigurer(); + Map editors = new HashMap(); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN); + editors.put(Date.class, new CustomDateEditor(df, true)); + cec.setCustomEditors(editors); + cec.postProcessBeanFactory(bf); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("date", "2.12.1975"); + bf.registerBeanDefinition("tb", new RootBeanDefinition(TestBean.class, pvs)); + + TestBean tb = (TestBean) bf.getBean("tb"); + assertEquals(df.parse("2.12.1975"), tb.getDate()); + } + + public void testCustomEditorConfigurerWithEditorAsClassName() throws ParseException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CustomEditorConfigurer cec = new CustomEditorConfigurer(); + Map editors = new HashMap(); + editors.put(Date.class, MyDateEditor.class.getName()); + cec.setCustomEditors(editors); + cec.postProcessBeanFactory(bf); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("date", "2.12.1975"); + bf.registerBeanDefinition("tb", new RootBeanDefinition(TestBean.class, pvs)); + + TestBean tb = (TestBean) bf.getBean("tb"); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN); + assertEquals(df.parse("2.12.1975"), tb.getDate()); + } + + public void testCustomEditorConfigurerWithEditorAsClass() throws ParseException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CustomEditorConfigurer cec = new CustomEditorConfigurer(); + Map editors = new HashMap(); + editors.put(Date.class, MyDateEditor.class); + cec.setCustomEditors(editors); + cec.postProcessBeanFactory(bf); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("date", "2.12.1975"); + bf.registerBeanDefinition("tb", new RootBeanDefinition(TestBean.class, pvs)); + + TestBean tb = (TestBean) bf.getBean("tb"); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN); + assertEquals(df.parse("2.12.1975"), tb.getDate()); + } + + public void testCustomEditorConfigurerWithRequiredTypeArray() throws ParseException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CustomEditorConfigurer cec = new CustomEditorConfigurer(); + Map editors = new HashMap(); + editors.put("java.lang.String[]", new PropertyEditorSupport() { + public void setAsText(String text) { + setValue(new String[] {"test"}); + } + }); + cec.setCustomEditors(editors); + cec.postProcessBeanFactory(bf); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("stringArray", "xxx"); + bf.registerBeanDefinition("tb", new RootBeanDefinition(TestBean.class, pvs)); + + TestBean tb = (TestBean) bf.getBean("tb"); + assertTrue(tb.getStringArray() != null && tb.getStringArray().length == 1); + assertEquals("test", tb.getStringArray()[0]); + } + + public void testCustomEditorConfigurerWithUnresolvableEditor() throws ParseException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CustomEditorConfigurer cec = new CustomEditorConfigurer(); + Map editors = new HashMap(); + editors.put(Date.class, "MyNonExistingEditor"); + editors.put("MyNonExistingType", "MyNonExistingEditor"); + cec.setCustomEditors(editors); + try { + cec.postProcessBeanFactory(bf); + fail("Should have thrown FatalBeanException"); + } + catch (FatalBeanException ex) { + assertTrue(ex.getCause() instanceof ClassNotFoundException); + } + } + + public void testCustomEditorConfigurerWithIgnoredUnresolvableEditor() throws ParseException { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + CustomEditorConfigurer cec = new CustomEditorConfigurer(); + Map editors = new HashMap(); + editors.put(Date.class, "MyNonExistingEditor"); + editors.put("MyNonExistingType", "MyNonExistingEditor"); + cec.setCustomEditors(editors); + cec.setIgnoreUnresolvableEditors(true); + cec.postProcessBeanFactory(bf); + } + + + public static class MyDateEditor extends CustomDateEditor { + + public MyDateEditor() { + super(DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN), true); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomScopeConfigurerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomScopeConfigurerTests.java new file mode 100644 index 00000000000..4c727011112 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/CustomScopeConfigurerTests.java @@ -0,0 +1,155 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.mock.easymock.AbstractScalarMockTemplate; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class CustomScopeConfigurerTests extends TestCase { + + private static final String FOO_SCOPE = "fooScope"; + + + public void testWithNoScopes() throws Exception { + new ConfigurableListableBeanFactoryMockTemplate() { + protected void doTest(ConfigurableListableBeanFactory factory) { + CustomScopeConfigurer figurer = new CustomScopeConfigurer(); + figurer.postProcessBeanFactory(factory); + } + }.test(); + } + + public void testSunnyDayWithBonaFideScopeInstance() throws Exception { + MockControl mockScope = MockControl.createControl(Scope.class); + final Scope scope = (Scope) mockScope.getMock(); + mockScope.replay(); + new ConfigurableListableBeanFactoryMockTemplate() { + public void setupExpectations(MockControl mockControl, ConfigurableListableBeanFactory factory) { + factory.registerScope(FOO_SCOPE, scope); + } + protected void doTest(ConfigurableListableBeanFactory factory) { + Map scopes = new HashMap(); + scopes.put(FOO_SCOPE, scope); + CustomScopeConfigurer figurer = new CustomScopeConfigurer(); + figurer.setScopes(scopes); + figurer.postProcessBeanFactory(factory); + } + }.test(); + mockScope.verify(); + } + + public void testSunnyDayWithBonaFideScopeClass() throws Exception { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + Map scopes = new HashMap(); + scopes.put(FOO_SCOPE, NoOpScope.class); + CustomScopeConfigurer figurer = new CustomScopeConfigurer(); + figurer.setScopes(scopes); + figurer.postProcessBeanFactory(factory); + assertTrue(factory.getRegisteredScope(FOO_SCOPE) instanceof NoOpScope); + } + + public void testSunnyDayWithBonaFideScopeClassname() throws Exception { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + Map scopes = new HashMap(); + scopes.put(FOO_SCOPE, NoOpScope.class.getName()); + CustomScopeConfigurer figurer = new CustomScopeConfigurer(); + figurer.setScopes(scopes); + figurer.postProcessBeanFactory(factory); + assertTrue(factory.getRegisteredScope(FOO_SCOPE) instanceof NoOpScope); + } + + public void testWhereScopeMapHasNullScopeValueInEntrySet() throws Exception { + new ConfigurableListableBeanFactoryMockTemplate() { + protected void doTest(final ConfigurableListableBeanFactory factory) { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Map scopes = new HashMap(); + scopes.put(FOO_SCOPE, null); + CustomScopeConfigurer figurer = new CustomScopeConfigurer(); + figurer.setScopes(scopes); + figurer.postProcessBeanFactory(factory); + } + }.runTest(); + } + }.test(); + } + + public void testWhereScopeMapHasNonScopeInstanceInEntrySet() throws Exception { + new ConfigurableListableBeanFactoryMockTemplate() { + protected void doTest(final ConfigurableListableBeanFactory factory) { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Map scopes = new HashMap(); + scopes.put(FOO_SCOPE, this); // <-- not a valid value... + CustomScopeConfigurer figurer = new CustomScopeConfigurer(); + figurer.setScopes(scopes); + figurer.postProcessBeanFactory(factory); + } + }.runTest(); + } + }.test(); + } + + public void testWhereScopeMapHasNonStringTypedScopeNameInKeySet() throws Exception { + new ConfigurableListableBeanFactoryMockTemplate() { + protected void doTest(final ConfigurableListableBeanFactory factory) { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Map scopes = new HashMap(); + scopes.put(this, new NoOpScope()); // <-- not a valid value (the key)... + CustomScopeConfigurer figurer = new CustomScopeConfigurer(); + figurer.setScopes(scopes); + figurer.postProcessBeanFactory(factory); + } + }.runTest(); + } + }.test(); + } + + + private abstract class ConfigurableListableBeanFactoryMockTemplate extends AbstractScalarMockTemplate { + + public ConfigurableListableBeanFactoryMockTemplate() { + super(ConfigurableListableBeanFactory.class); + } + + public final void setupExpectations(MockControl mockControl, Object mockObject) throws Exception { + setupExpectations(mockControl, (ConfigurableListableBeanFactory) mockObject); + } + + public final void doTest(Object mockObject) throws Exception { + doTest((ConfigurableListableBeanFactory) mockObject); + } + + public void setupExpectations(MockControl mockControl, ConfigurableListableBeanFactory factory) throws Exception { + } + + protected abstract void doTest(ConfigurableListableBeanFactory factory) throws Exception; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java new file mode 100644 index 00000000000..a51b2a662fe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java @@ -0,0 +1,123 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.sql.Connection; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + * @since 31.07.2004 + */ +public class FieldRetrievingFactoryBeanTests extends TestCase { + + public void testStaticField() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setStaticField("java.sql.Connection.TRANSACTION_SERIALIZABLE"); + fr.afterPropertiesSet(); + assertEquals(new Integer(Connection.TRANSACTION_SERIALIZABLE), fr.getObject()); + } + + public void testStaticFieldWithWhitespace() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setStaticField(" java.sql.Connection.TRANSACTION_SERIALIZABLE "); + fr.afterPropertiesSet(); + assertEquals(new Integer(Connection.TRANSACTION_SERIALIZABLE), fr.getObject()); + } + + public void testStaticFieldViaClassAndFieldName() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setTargetClass(Connection.class); + fr.setTargetField("TRANSACTION_SERIALIZABLE"); + fr.afterPropertiesSet(); + assertEquals(new Integer(Connection.TRANSACTION_SERIALIZABLE), fr.getObject()); + } + + public void testNonStaticField() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + PublicFieldHolder target = new PublicFieldHolder(); + fr.setTargetObject(target); + fr.setTargetField("publicField"); + fr.afterPropertiesSet(); + assertEquals(target.publicField, fr.getObject()); + } + + public void testNothingButBeanName() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setBeanName("java.sql.Connection.TRANSACTION_SERIALIZABLE"); + fr.afterPropertiesSet(); + assertEquals(new Integer(Connection.TRANSACTION_SERIALIZABLE), fr.getObject()); + } + + public void testJustTargetField() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setTargetField("TRANSACTION_SERIALIZABLE"); + try { + fr.afterPropertiesSet(); + } + catch (IllegalArgumentException expected) { + } + } + + public void testJustTargetClass() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setTargetClass(Connection.class); + try { + fr.afterPropertiesSet(); + } + catch (IllegalArgumentException expected) { + } + } + + public void testJustTargetObject() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setTargetObject(new PublicFieldHolder()); + try { + fr.afterPropertiesSet(); + } + catch (IllegalArgumentException expected) { + } + } + + public void testWithConstantOnClassWithPackageLevelVisibility() throws Exception { + FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); + fr.setBeanName("org.springframework.beans.factory.PackageLevelVisibleBean.CONSTANT"); + fr.afterPropertiesSet(); + assertEquals("Wuby", fr.getObject()); + } + + public void testBeanNameSyntaxWithBeanFactory() throws Exception { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("fieldRetrieving.xml", getClass())); + TestBean testBean = (TestBean) bf.getBean("testBean"); + assertEquals(new Integer(Connection.TRANSACTION_SERIALIZABLE), testBean.getSomeIntegerArray()[0]); + assertEquals(new Integer(Connection.TRANSACTION_SERIALIZABLE), testBean.getSomeIntegerArray()[1]); + } + + + private static class PublicFieldHolder { + + public String publicField = "test"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java new file mode 100644 index 00000000000..7ef5d085704 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/MethodInvokingFactoryBeanTests.java @@ -0,0 +1,339 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.util.ArrayList; + +import junit.framework.TestCase; + +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.beans.support.ArgumentConvertingMethodInvoker; +import org.springframework.util.MethodInvoker; +import org.springframework.util.MethodInvokerTests; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @since 21.11.2003 + */ +public class MethodInvokingFactoryBeanTests extends TestCase { + + public void testParameterValidation() throws Exception { + String validationError = "improper validation of input properties"; + + // assert that only static OR non static are set, but not both or none + MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); + try { + mcfb.afterPropertiesSet(); + fail(validationError); + } + catch (IllegalArgumentException ex) { + // expected + } + + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetObject(this); + mcfb.setTargetMethod("whatever"); + try { + mcfb.afterPropertiesSet(); + fail(validationError); + } + catch (NoSuchMethodException ex) { + // expected + } + + // bogus static method + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("some.bogus.Method.name"); + try { + mcfb.afterPropertiesSet(); + fail(validationError); + } + catch (NoSuchMethodException ex) { + // expected + } + + // bogus static method + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("method1"); + try { + mcfb.afterPropertiesSet(); + fail(validationError); + } + catch (IllegalArgumentException ex) { + // expected + } + + // missing method + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetObject(this); + try { + mcfb.afterPropertiesSet(); + fail(validationError); + } + catch (IllegalArgumentException ex) { + // expected + } + + // bogus method + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetObject(this); + mcfb.setTargetMethod("bogus"); + try { + mcfb.afterPropertiesSet(); + fail(validationError); + } + catch (NoSuchMethodException ex) { + // expected + } + + // static method + MethodInvokerTests.TestClass1._staticField1 = 0; + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("staticMethod1"); + mcfb.afterPropertiesSet(); + + // non-static method + MethodInvokerTests.TestClass1 tc1 = new MethodInvokerTests.TestClass1(); + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetObject(tc1); + mcfb.setTargetMethod("method1"); + mcfb.afterPropertiesSet(); + } + + public void testGetObjectType() throws Exception { + MethodInvokerTests.TestClass1 tc1 = new MethodInvokerTests.TestClass1(); + MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetObject(tc1); + mcfb.setTargetMethod("method1"); + mcfb.afterPropertiesSet(); + assertTrue(int.class.equals(mcfb.getObjectType())); + + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("voidRetvalMethod"); + mcfb.afterPropertiesSet(); + Class objType = mcfb.getObjectType(); + assertTrue(objType.equals(void.class)); + + // verify that we can call a method with args that are subtypes of the + // target method arg types + MethodInvokerTests.TestClass1._staticField1 = 0; + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("supertypes"); + mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello"}); + mcfb.afterPropertiesSet(); + mcfb.getObjectType(); + + // fail on improper argument types at afterPropertiesSet + mcfb = new MethodInvokingFactoryBean(); + mcfb.registerCustomEditor(String.class, new StringTrimmerEditor(false)); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("supertypes"); + mcfb.setArguments(new Object[] {"1", new Object()}); + try { + mcfb.afterPropertiesSet(); + fail("Should have thrown NoSuchMethodException"); + } + catch (NoSuchMethodException ex) { + // expected + } + } + + public void testGetObject() throws Exception { + // singleton, non-static + MethodInvokerTests.TestClass1 tc1 = new MethodInvokerTests.TestClass1(); + MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetObject(tc1); + mcfb.setTargetMethod("method1"); + mcfb.afterPropertiesSet(); + Integer i = (Integer) mcfb.getObject(); + assertEquals(1, i.intValue()); + i = (Integer) mcfb.getObject(); + assertEquals(1, i.intValue()); + + // non-singleton, non-static + tc1 = new MethodInvokerTests.TestClass1(); + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetObject(tc1); + mcfb.setTargetMethod("method1"); + mcfb.setSingleton(false); + mcfb.afterPropertiesSet(); + i = (Integer) mcfb.getObject(); + assertEquals(1, i.intValue()); + i = (Integer) mcfb.getObject(); + assertEquals(2, i.intValue()); + + // singleton, static + MethodInvokerTests.TestClass1._staticField1 = 0; + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("staticMethod1"); + mcfb.afterPropertiesSet(); + i = (Integer) mcfb.getObject(); + assertEquals(1, i.intValue()); + i = (Integer) mcfb.getObject(); + assertEquals(1, i.intValue()); + + // non-singleton, static + MethodInvokerTests.TestClass1._staticField1 = 0; + mcfb = new MethodInvokingFactoryBean(); + mcfb.setStaticMethod("org.springframework.util.MethodInvokerTests$TestClass1.staticMethod1"); + mcfb.setSingleton(false); + mcfb.afterPropertiesSet(); + i = (Integer) mcfb.getObject(); + assertEquals(1, i.intValue()); + i = (Integer) mcfb.getObject(); + assertEquals(2, i.intValue()); + + // void return value + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("voidRetvalMethod"); + mcfb.afterPropertiesSet(); + assertNull(mcfb.getObject()); + + // now see if we can match methods with arguments that have supertype arguments + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("supertypes"); + mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello"}); + // should pass + mcfb.afterPropertiesSet(); + } + + public void testArgumentConversion() throws Exception { + MethodInvokingFactoryBean mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("supertypes"); + mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello", "bogus"}); + try { + mcfb.afterPropertiesSet(); + fail("Matched method with wrong number of args"); + } + catch (NoSuchMethodException ex) { + // expected + } + + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("supertypes"); + mcfb.setArguments(new Object[] {new Integer(1), new Object()}); + try { + mcfb.afterPropertiesSet(); + mcfb.getObject(); + fail("Should have failed on getObject with mismatched argument types"); + } + catch (NoSuchMethodException ex) { + // expected + } + + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("supertypes2"); + mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello", "bogus"}); + mcfb.afterPropertiesSet(); + assertEquals("hello", mcfb.getObject()); + + mcfb = new MethodInvokingFactoryBean(); + mcfb.setTargetClass(MethodInvokerTests.TestClass1.class); + mcfb.setTargetMethod("supertypes2"); + mcfb.setArguments(new Object[] {new ArrayList(), new ArrayList(), new Object()}); + try { + mcfb.afterPropertiesSet(); + fail("Matched method when shouldn't have matched"); + } + catch (NoSuchMethodException ex) { + // expected + } + } + + public void testInvokeWithNullArgument() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("nullArgument"); + methodInvoker.setArguments(new Object[] {null}); + methodInvoker.prepare(); + methodInvoker.invoke(); + } + + public void testInvokeWithIntArgument() throws Exception { + ArgumentConvertingMethodInvoker methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArgument"); + methodInvoker.setArguments(new Object[] {new Integer(5)}); + methodInvoker.prepare(); + methodInvoker.invoke(); + + methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArgument"); + methodInvoker.setArguments(new Object[] {"5"}); + methodInvoker.prepare(); + methodInvoker.invoke(); + } + + public void testInvokeWithIntArguments() throws Exception { + ArgumentConvertingMethodInvoker methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArguments"); + methodInvoker.setArguments(new Object[] {new Integer[] {new Integer(5), new Integer(10)}}); + methodInvoker.prepare(); + methodInvoker.invoke(); + + methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArguments"); + methodInvoker.setArguments(new Object[] {new String[] {"5", "10"}}); + methodInvoker.prepare(); + methodInvoker.invoke(); + + methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArguments"); + methodInvoker.setArguments(new Integer[] {new Integer(5), new Integer(10)}); + methodInvoker.prepare(); + methodInvoker.invoke(); + + methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArguments"); + methodInvoker.setArguments(new String[] {"5", "10"}); + methodInvoker.prepare(); + methodInvoker.invoke(); + + methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArguments"); + methodInvoker.setArguments(new Object[] {new Integer(5), new Integer(10)}); + methodInvoker.prepare(); + methodInvoker.invoke(); + + methodInvoker = new ArgumentConvertingMethodInvoker(); + methodInvoker.setTargetClass(MethodInvokerTests.TestClass1.class); + methodInvoker.setTargetMethod("intArguments"); + methodInvoker.setArguments(new Object[] {"5", "10"}); + methodInvoker.prepare(); + methodInvoker.invoke(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/NoOpScope.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/NoOpScope.java new file mode 100644 index 00000000000..c681dabc7a1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/NoOpScope.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import org.springframework.beans.factory.ObjectFactory; + +/** + * @author Juergen Hoeller + */ +public class NoOpScope implements Scope { + + public Object get(String name, ObjectFactory objectFactory) { + throw new UnsupportedOperationException(); + } + + public Object remove(String name) { + throw new UnsupportedOperationException(); + } + + public void registerDestructionCallback(String name, Runnable callback) { + } + + public String getConversationId() { + return null; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java new file mode 100644 index 00000000000..b5a2d687b86 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java @@ -0,0 +1,127 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.util.Date; + +import junit.framework.TestCase; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.easymock.MockControl; + +/** + * Unit tests for the ObjectFactoryCreatingFactoryBean class. + * + * @author Colin Sampaleanu + * @author Rick Evans + * @since 2004-05-11 + */ +public final class ObjectFactoryCreatingFactoryBeanTests extends TestCase { + + private BeanFactory beanFactory; + + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource( + "ObjectFactoryCreatingFactoryBeanTests.xml", getClass())); + } + + + public void testBasicOperation() throws BeansException { + TestBean testBean = (TestBean) beanFactory.getBean("testBean"); + ObjectFactory objectFactory = testBean.getObjectFactory(); + + Date date1 = (Date) objectFactory.getObject(); + Date date2 = (Date) objectFactory.getObject(); + assertTrue(date1 != date2); + } + + public void testDoesNotComplainWhenTargetBeanNameRefersToSingleton() throws Exception { + final String targetBeanName = "singleton"; + final String expectedSingleton = "Alicia Keys"; + + MockControl mock = MockControl.createControl(BeanFactory.class); + BeanFactory beanFactory = (BeanFactory) mock.getMock(); + beanFactory.getBean(targetBeanName); + mock.setReturnValue(expectedSingleton); + mock.replay(); + + ObjectFactoryCreatingFactoryBean factory = new ObjectFactoryCreatingFactoryBean(); + factory.setTargetBeanName(targetBeanName); + factory.setBeanFactory(beanFactory); + factory.afterPropertiesSet(); + ObjectFactory objectFactory = (ObjectFactory) factory.getObject(); + Object actualSingleton = objectFactory.getObject(); + assertSame(expectedSingleton, actualSingleton); + + mock.verify(); + } + + public void testWhenTargetBeanNameIsNull() throws Exception { + try { + new ObjectFactoryCreatingFactoryBean().afterPropertiesSet(); + fail("Must have thrown an IllegalArgumentException; 'targetBeanName' property not set."); + } + catch (IllegalArgumentException expected) {} + } + + public void testWhenTargetBeanNameIsEmptyString() throws Exception { + try { + ObjectFactoryCreatingFactoryBean factory = new ObjectFactoryCreatingFactoryBean(); + factory.setTargetBeanName(""); + factory.afterPropertiesSet(); + fail("Must have thrown an IllegalArgumentException; 'targetBeanName' property set to (invalid) empty string."); + } + catch (IllegalArgumentException expected) {} + } + + public void testWhenTargetBeanNameIsWhitespacedString() throws Exception { + try { + ObjectFactoryCreatingFactoryBean factory = new ObjectFactoryCreatingFactoryBean(); + factory.setTargetBeanName(" \t"); + factory.afterPropertiesSet(); + fail("Must have thrown an IllegalArgumentException; 'targetBeanName' property set to (invalid) only-whitespace string."); + } + catch (IllegalArgumentException expected) {} + } + + public void testEnsureOFBFBReportsThatItActuallyCreatesObjectFactoryInstances() throws Exception { + assertEquals("Must be reporting that it creates ObjectFactory instances (as per class contract).", + ObjectFactory.class, new ObjectFactoryCreatingFactoryBean().getObjectType()); + } + + + public static class TestBean { + + public ObjectFactory objectFactory; + + + public ObjectFactory getObjectFactory() { + return objectFactory; + } + + public void setObjectFactory(ObjectFactory objectFactory) { + this.objectFactory = objectFactory; + } + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.xml new file mode 100644 index 00000000000..92a011c3437 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java new file mode 100644 index 00000000000..d01ef9002fb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java @@ -0,0 +1,135 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.util.Properties; + +import junit.framework.TestCase; + +import org.springframework.core.JdkVersion; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + * @since 01.11.2003 + */ +public class PropertiesFactoryBeanTests extends TestCase { + + public void testWithPropertiesFile() throws Exception { + PropertiesFactoryBean pfb = new PropertiesFactoryBean(); + pfb.setLocation(new ClassPathResource("/org/springframework/beans/factory/config/test.properties")); + pfb.afterPropertiesSet(); + Properties props = (Properties) pfb.getObject(); + assertEquals("99", props.getProperty("tb.array[0].age")); + } + + public void testWithPropertiesXmlFile() throws Exception { + // ignore for JDK < 1.5 + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + + PropertiesFactoryBean pfb = new PropertiesFactoryBean(); + pfb.setLocation(new ClassPathResource("/org/springframework/beans/factory/config/test-properties.xml")); + pfb.afterPropertiesSet(); + Properties props = (Properties) pfb.getObject(); + assertEquals("99", props.getProperty("tb.array[0].age")); + } + + public void testWithLocalProperties() throws Exception { + PropertiesFactoryBean pfb = new PropertiesFactoryBean(); + Properties localProps = new Properties(); + localProps.setProperty("key2", "value2"); + pfb.setProperties(localProps); + pfb.afterPropertiesSet(); + Properties props = (Properties) pfb.getObject(); + assertEquals("value2", props.getProperty("key2")); + } + + public void testWithPropertiesFileAndLocalProperties() throws Exception { + PropertiesFactoryBean pfb = new PropertiesFactoryBean(); + pfb.setLocation(new ClassPathResource("/org/springframework/beans/factory/config/test.properties")); + Properties localProps = new Properties(); + localProps.setProperty("key2", "value2"); + localProps.setProperty("tb.array[0].age", "0"); + pfb.setProperties(localProps); + pfb.afterPropertiesSet(); + Properties props = (Properties) pfb.getObject(); + assertEquals("99", props.getProperty("tb.array[0].age")); + assertEquals("value2", props.getProperty("key2")); + } + + public void testWithPropertiesFileAndMultipleLocalProperties() throws Exception { + PropertiesFactoryBean pfb = new PropertiesFactoryBean(); + pfb.setLocation(new ClassPathResource("/org/springframework/beans/factory/config/test.properties")); + + Properties props1 = new Properties(); + props1.setProperty("key2", "value2"); + props1.setProperty("tb.array[0].age", "0"); + + Properties props2 = new Properties(); + props2.setProperty("spring", "framework"); + props2.setProperty("Don", "Mattingly"); + + Properties props3 = new Properties(); + props3.setProperty("spider", "man"); + props3.setProperty("bat", "man"); + + pfb.setPropertiesArray(new Properties[] {props1, props2, props3}); + pfb.afterPropertiesSet(); + + Properties props = (Properties) pfb.getObject(); + assertEquals("99", props.getProperty("tb.array[0].age")); + assertEquals("value2", props.getProperty("key2")); + assertEquals("framework", props.getProperty("spring")); + assertEquals("Mattingly", props.getProperty("Don")); + assertEquals("man", props.getProperty("spider")); + assertEquals("man", props.getProperty("bat")); + } + + public void testWithPropertiesFileAndLocalPropertiesAndLocalOverride() throws Exception { + PropertiesFactoryBean pfb = new PropertiesFactoryBean(); + pfb.setLocation(new ClassPathResource("/org/springframework/beans/factory/config/test.properties")); + Properties localProps = new Properties(); + localProps.setProperty("key2", "value2"); + localProps.setProperty("tb.array[0].age", "0"); + pfb.setProperties(localProps); + pfb.setLocalOverride(true); + pfb.afterPropertiesSet(); + Properties props = (Properties) pfb.getObject(); + assertEquals("0", props.getProperty("tb.array[0].age")); + assertEquals("value2", props.getProperty("key2")); + } + + public void testWithPrototype() throws Exception { + PropertiesFactoryBean pfb = new PropertiesFactoryBean(); + pfb.setSingleton(false); + pfb.setLocation(new ClassPathResource("/org/springframework/beans/factory/config/test.properties")); + Properties localProps = new Properties(); + localProps.setProperty("key2", "value2"); + pfb.setProperties(localProps); + pfb.afterPropertiesSet(); + Properties props = (Properties) pfb.getObject(); + assertEquals("99", props.getProperty("tb.array[0].age")); + assertEquals("value2", props.getProperty("key2")); + Properties newProps = (Properties) pfb.getObject(); + assertTrue(props != newProps); + assertEquals("99", newProps.getProperty("tb.array[0].age")); + assertEquals("value2", newProps.getProperty("key2")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java new file mode 100644 index 00000000000..ec6fae46b5e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + * @since 04.10.2004 + */ +public class PropertyPathFactoryBeanTests extends TestCase { + + public void testPropertyPathFactoryBeanWithSingletonResult() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("propertyPath.xml", getClass())); + assertEquals(new Integer(12), xbf.getBean("propertyPath1")); + assertEquals(new Integer(11), xbf.getBean("propertyPath2")); + assertEquals(new Integer(10), xbf.getBean("tb.age")); + assertEquals(ITestBean.class, xbf.getType("otb.spouse")); + Object result1 = xbf.getBean("otb.spouse"); + Object result2 = xbf.getBean("otb.spouse"); + assertTrue(result1 instanceof TestBean); + assertTrue(result1 == result2); + assertEquals(99, ((TestBean) result1).getAge()); + } + + public void testPropertyPathFactoryBeanWithPrototypeResult() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("propertyPath.xml", getClass())); + assertNull(xbf.getType("tb.spouse")); + assertEquals(TestBean.class, xbf.getType("propertyPath3")); + Object result1 = xbf.getBean("tb.spouse"); + Object result2 = xbf.getBean("propertyPath3"); + Object result3 = xbf.getBean("propertyPath3"); + assertTrue(result1 instanceof TestBean); + assertTrue(result2 instanceof TestBean); + assertTrue(result3 instanceof TestBean); + assertEquals(11, ((TestBean) result1).getAge()); + assertEquals(11, ((TestBean) result2).getAge()); + assertEquals(11, ((TestBean) result3).getAge()); + assertTrue(result1 != result2); + assertTrue(result1 != result3); + assertTrue(result2 != result3); + } + + public void testPropertyPathFactoryBeanWithNullResult() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("propertyPath.xml", getClass())); + assertNull(xbf.getType("tb.spouse.spouse")); + assertNull(xbf.getBean("tb.spouse.spouse")); + } + + public void testPropertyPathFactoryBeanAsInnerBean() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("propertyPath.xml", getClass())); + TestBean spouse = (TestBean) xbf.getBean("otb.spouse"); + TestBean tbWithInner = (TestBean) xbf.getBean("tbWithInner"); + assertSame(spouse, tbWithInner.getSpouse()); + assertTrue(!tbWithInner.getFriends().isEmpty()); + assertSame(spouse, tbWithInner.getFriends().iterator().next()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java new file mode 100644 index 00000000000..2296d5bcf27 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java @@ -0,0 +1,715 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.io.FileNotFoundException; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.prefs.Preferences; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactoryBean; +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.support.ChildBeanDefinition; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.ManagedSet; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.JdkVersion; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.util.StringUtils; + +/** + * @author Juergen Hoeller + * @since 02.10.2003 + */ +public class PropertyResourceConfigurerTests extends TestCase { + + public void testPropertyOverrideConfigurer() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb1", TestBean.class); + ac.registerSingleton("tb2", TestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb1.age=99\ntb2.name=test"); + ac.registerSingleton("configurer1", PropertyOverrideConfigurer.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb2.age=99\ntb2.name=test2"); + pvs.addPropertyValue("order", "0"); + ac.registerSingleton("configurer2", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + TestBean tb1 = (TestBean) ac.getBean("tb1"); + TestBean tb2 = (TestBean) ac.getBean("tb2"); + assertEquals(99, tb1.getAge()); + assertEquals(99, tb2.getAge()); + assertEquals(null, tb1.getName()); + assertEquals("test", tb2.getName()); + } + + public void testPropertyOverrideConfigurerWithNestedProperty() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb", IndexedTestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb.array[0].age=99\ntb.list[1].name=test"); + ac.registerSingleton("configurer", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + IndexedTestBean tb = (IndexedTestBean) ac.getBean("tb"); + assertEquals(99, tb.getArray()[0].getAge()); + assertEquals("test", ((TestBean) tb.getList().get(1)).getName()); + } + + public void testPropertyOverrideConfigurerWithNestedPropertyAndDotInBeanName() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("my.tb", IndexedTestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "my.tb_array[0].age=99\nmy.tb_list[1].name=test"); + pvs.addPropertyValue("beanNameSeparator", "_"); + ac.registerSingleton("configurer", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + IndexedTestBean tb = (IndexedTestBean) ac.getBean("my.tb"); + assertEquals(99, tb.getArray()[0].getAge()); + assertEquals("test", ((TestBean) tb.getList().get(1)).getName()); + } + + public void testPropertyOverrideConfigurerWithNestedMapPropertyAndDotInMapKey() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb", IndexedTestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb.map[key1]=99\ntb.map[key2.ext]=test"); + ac.registerSingleton("configurer", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + IndexedTestBean tb = (IndexedTestBean) ac.getBean("tb"); + assertEquals("99", tb.getMap().get("key1")); + assertEquals("test", tb.getMap().get("key2.ext")); + } + + public void testPropertyOverrideConfigurerWithJavaMailProperties() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb", JavaMailSenderImpl.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb.javaMailProperties[mail.smtp.auth]=true"); + ac.registerSingleton("configurer", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + JavaMailSenderImpl tb = (JavaMailSenderImpl) ac.getBean("tb"); + assertEquals("true", tb.getJavaMailProperties().getProperty("mail.smtp.auth")); + } + + public void testPropertyOverrideConfigurerWithPropertiesFile() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb", IndexedTestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("location", "classpath:org/springframework/beans/factory/config/test.properties"); + ac.registerSingleton("configurer", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + IndexedTestBean tb = (IndexedTestBean) ac.getBean("tb"); + assertEquals(99, tb.getArray()[0].getAge()); + assertEquals("test", ((TestBean) tb.getList().get(1)).getName()); + } + + public void testPropertyOverrideConfigurerWithInvalidPropertiesFile() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb", IndexedTestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("locations", + new String[] {"classpath:org/springframework/beans/factory/config/test.properties", + "classpath:org/springframework/beans/factory/config/xtest.properties"}); + pvs.addPropertyValue("ignoreResourceNotFound", Boolean.TRUE); + ac.registerSingleton("configurer", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + IndexedTestBean tb = (IndexedTestBean) ac.getBean("tb"); + assertEquals(99, tb.getArray()[0].getAge()); + assertEquals("test", ((TestBean) tb.getList().get(1)).getName()); + } + + public void testPropertyOverrideConfigurerWithPropertiesXmlFile() { + // ignore for JDK < 1.5 + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb", IndexedTestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("location", "classpath:org/springframework/beans/factory/config/test-properties.xml"); + ac.registerSingleton("configurer", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + IndexedTestBean tb = (IndexedTestBean) ac.getBean("tb"); + assertEquals(99, tb.getArray()[0].getAge()); + assertEquals("test", ((TestBean) tb.getList().get(1)).getName()); + } + + public void testPropertyOverrideConfigurerWithConvertProperties() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb", IndexedTestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb.array[0].name=99\ntb.list[1].name=test"); + ac.registerSingleton("configurer", ConvertingOverrideConfigurer.class, pvs); + ac.refresh(); + IndexedTestBean tb = (IndexedTestBean) ac.getBean("tb"); + assertEquals("X99", tb.getArray()[0].getName()); + assertEquals("Xtest", ((TestBean) tb.getList().get(1)).getName()); + } + + public void testPropertyOverrideConfigurerWithInvalidKey() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb1", TestBean.class); + ac.registerSingleton("tb2", TestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "argh=hgra\ntb1.age=99\ntb2.name=test"); + pvs.addPropertyValue("ignoreInvalidKeys", "true"); + ac.registerSingleton("configurer1", PropertyOverrideConfigurer.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb2.age=99\ntb2.name=test2"); + pvs.addPropertyValue("order", "0"); + ac.registerSingleton("configurer2", PropertyOverrideConfigurer.class, pvs); + try { + ac.refresh(); + } + catch (BeanInitializationException ex) { + assertTrue(ex.getMessage().toLowerCase().indexOf("argh") != -1); + } + } + + public void testPropertyOverrideConfigurerWithIgnoreInvalidKeys() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("tb1", TestBean.class); + ac.registerSingleton("tb2", TestBean.class); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "argh=hgra\ntb1.age=99\ntb2.name=test"); + pvs.addPropertyValue("ignoreInvalidKeys", "true"); + ac.registerSingleton("configurer1", PropertyOverrideConfigurer.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "tb2.age=99\ntb2.name=test2"); + pvs.addPropertyValue("order", "0"); + ac.registerSingleton("configurer2", PropertyOverrideConfigurer.class, pvs); + ac.refresh(); + TestBean tb1 = (TestBean) ac.getBean("tb1"); + TestBean tb2 = (TestBean) ac.getBean("tb2"); + assertEquals(99, tb1.getAge()); + assertEquals(99, tb2.getAge()); + assertEquals(null, tb1.getName()); + assertEquals("test", tb2.getName()); + } + + public void testPropertyPlaceholderConfigurer() { + doTestPropertyPlaceholderConfigurer(false); + } + + public void testPropertyPlaceholderConfigurerWithParentChildSeparation() { + doTestPropertyPlaceholderConfigurer(true); + } + + private void doTestPropertyPlaceholderConfigurer(boolean parentChildSeparation) { + StaticApplicationContext ac = new StaticApplicationContext(); + + if (parentChildSeparation) { + MutablePropertyValues pvs1 = new MutablePropertyValues(); + pvs1.addPropertyValue("age", "${age}"); + MutablePropertyValues pvs2 = new MutablePropertyValues(); + pvs2.addPropertyValue("name", "name${var}${var}${"); + pvs2.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + + RootBeanDefinition parent = new RootBeanDefinition(TestBean.class, pvs1); + ChildBeanDefinition bd = new ChildBeanDefinition("${parent}", pvs2); + ac.getDefaultListableBeanFactory().registerBeanDefinition("parent1", parent); + ac.getDefaultListableBeanFactory().registerBeanDefinition("tb1", bd); + } + else { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "${age}"); + pvs.addPropertyValue("name", "name${var}${var}${"); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, pvs); + ac.getDefaultListableBeanFactory().registerBeanDefinition("tb1", bd); + } + + ConstructorArgumentValues cas = new ConstructorArgumentValues(); + cas.addIndexedArgumentValue(1, "${age}"); + cas.addGenericArgumentValue("${var}name${age}"); + + MutablePropertyValues pvs = new MutablePropertyValues(); + List friends = new ManagedList(); + friends.add("na${age}me"); + friends.add(new RuntimeBeanReference("${ref}")); + pvs.addPropertyValue("friends", friends); + + Set someSet = new ManagedSet(); + someSet.add("na${age}me"); + someSet.add(new RuntimeBeanReference("${ref}")); + someSet.add(new TypedStringValue("${age}", Integer.class)); + pvs.addPropertyValue("someSet", someSet); + + Map someMap = new ManagedMap(); + someMap.put(new TypedStringValue("key${age}"), new TypedStringValue("${age}")); + someMap.put(new TypedStringValue("key${age}ref"), new RuntimeBeanReference("${ref}")); + someMap.put("key1", new RuntimeBeanReference("${ref}")); + someMap.put("key2", "${age}name"); + MutablePropertyValues innerPvs = new MutablePropertyValues(); + innerPvs.addPropertyValue("touchy", "${os.name}"); + someMap.put("key3", new RootBeanDefinition(TestBean.class, innerPvs)); + MutablePropertyValues innerPvs2 = new MutablePropertyValues(innerPvs); + someMap.put("${key4}", new BeanDefinitionHolder(new ChildBeanDefinition("tb1", innerPvs2), "child")); + pvs.addPropertyValue("someMap", someMap); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, cas, pvs); + ac.getDefaultListableBeanFactory().registerBeanDefinition("tb2", bd); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "age=98\nvar=${m}var\nref=tb2\nm=my\nkey4=mykey4\nparent=parent1"); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + + TestBean tb1 = (TestBean) ac.getBean("tb1"); + TestBean tb2 = (TestBean) ac.getBean("tb2"); + assertEquals(98, tb1.getAge()); + assertEquals(98, tb2.getAge()); + assertEquals("namemyvarmyvar${", tb1.getName()); + assertEquals("myvarname98", tb2.getName()); + assertEquals(tb2, tb1.getSpouse()); + assertEquals(2, tb2.getFriends().size()); + assertEquals("na98me", tb2.getFriends().iterator().next()); + assertEquals(tb2, tb2.getFriends().toArray()[1]); + assertEquals(3, tb2.getSomeSet().size()); + assertTrue(tb2.getSomeSet().contains("na98me")); + assertTrue(tb2.getSomeSet().contains(tb2)); + assertTrue(tb2.getSomeSet().contains(new Integer(98))); + assertEquals(6, tb2.getSomeMap().size()); + assertEquals("98", tb2.getSomeMap().get("key98")); + assertEquals(tb2, tb2.getSomeMap().get("key98ref")); + assertEquals(tb2, tb2.getSomeMap().get("key1")); + assertEquals("98name", tb2.getSomeMap().get("key2")); + TestBean inner1 = (TestBean) tb2.getSomeMap().get("key3"); + TestBean inner2 = (TestBean) tb2.getSomeMap().get("mykey4"); + assertEquals(0, inner1.getAge()); + assertEquals(null, inner1.getName()); + assertEquals(System.getProperty("os.name"), inner1.getTouchy()); + assertEquals(98, inner2.getAge()); + assertEquals("namemyvarmyvar${", inner2.getName()); + assertEquals(System.getProperty("os.name"), inner2.getTouchy()); + } + + public void testPropertyPlaceholderConfigurerWithSystemPropertyFallback() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", "${os.name}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals(System.getProperty("os.name"), tb.getTouchy()); + } + + public void testPropertyPlaceholderConfigurerWithSystemPropertyNotUsed() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", "${os.name}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("os.name", "myos"); + pvs.addPropertyValue("properties", props); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("myos", tb.getTouchy()); + } + + public void testPropertyPlaceholderConfigurerWithOverridingSystemProperty() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", "${os.name}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("os.name", "myos"); + pvs.addPropertyValue("properties", props); + pvs.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_OVERRIDE"); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals(System.getProperty("os.name"), tb.getTouchy()); + } + + public void testPropertyPlaceholderConfigurerWithUnresolvableSystemProperty() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", "${user.dir}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_NEVER"); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + try { + ac.refresh(); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + assertTrue(ex.getMessage().indexOf("user.dir") != -1); + } + } + + public void testPropertyPlaceholderConfigurerWithUnresolvablePlaceholder() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "${ref}"); + ac.registerSingleton("tb", TestBean.class, pvs); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, null); + try { + ac.refresh(); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + assertTrue(ex.getMessage().indexOf("ref") != -1); + } + } + + public void testPropertyPlaceholderConfigurerWithIgnoreUnresolvablePlaceholder() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "${ref}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("ignoreUnresolvablePlaceholders", Boolean.TRUE); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("${ref}", tb.getName()); + } + + public void testPropertyPlaceholderConfigurerWithEmptyStringAsNull() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", ""); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("nullValue", ""); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertNull(tb.getName()); + } + + public void testPropertyPlaceholderConfigurerWithEmptyStringInPlaceholderAsNull() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "${ref}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("nullValue", ""); + Properties props = new Properties(); + props.put("ref", ""); + pvs.addPropertyValue("properties", props); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertNull(tb.getName()); + } + + public void testPropertyPlaceholderConfigurerWithNestedPlaceholderInKey() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "${my${key}key}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("key", "new"); + props.put("mynewkey", "myname"); + pvs.addPropertyValue("properties", props); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("myname", tb.getName()); + } + + public void testPropertyPlaceholderConfigurerWithSystemPropertyInLocation() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("location", "${user.dir}/test"); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + try { + ac.refresh(); + fail("Should have thrown BeanInitializationException"); + } + catch (BeanInitializationException ex) { + // expected + assertTrue(ex.getCause() instanceof FileNotFoundException); + // slight hack for Linux/Unix systems + String userDir = StringUtils.cleanPath(System.getProperty("user.dir")); + if (userDir.startsWith("/")) { + userDir = userDir.substring(1); + } + assertTrue(ex.getMessage().indexOf(userDir) != -1); + } + } + + public void testPropertyPlaceholderConfigurerWithSystemPropertiesInLocation() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("location", "${user.dir}/test/${user.dir}"); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + try { + ac.refresh(); + fail("Should have thrown BeanInitializationException"); + } + catch (BeanInitializationException ex) { + // expected + assertTrue(ex.getCause() instanceof FileNotFoundException); + // slight hack for Linux/Unix systems + String userDir = StringUtils.cleanPath(System.getProperty("user.dir")); + if (userDir.startsWith("/")) { + userDir = userDir.substring(1); + } + /* the above hack doesn't work since the exception message is created without + the leading / stripped so the test fails. Changed 17/11/04. DD */ + //assertTrue(ex.getMessage().indexOf(userDir + "/test/" + userDir) != -1); + assertTrue(ex.getMessage().indexOf(userDir + "/test/" + userDir) != -1 || + ex.getMessage().indexOf(userDir + "/test//" + userDir) != -1); + } + } + + public void testPropertyPlaceholderConfigurerWithUnresolvableSystemPropertiesInLocation() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("location", "${myprop}/test/${myprop}"); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + try { + ac.refresh(); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanInitializationException ex) { + // expected + assertTrue(ex.getCause() instanceof FileNotFoundException); + assertTrue(ex.getMessage().indexOf("myprop") != -1); + } + } + + public void testPropertyPlaceholderConfigurerWithCircularReference() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "${age}"); + pvs.addPropertyValue("name", "name${var}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "age=99\nvar=${m}var\nm=${var}"); + ac.registerSingleton("configurer1", PropertyPlaceholderConfigurer.class, pvs); + try { + ac.refresh(); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + } + } + + public void testPropertyPlaceholderConfigurerWithMultiLevelCircularReference() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "name${var}"); + ac.registerSingleton("tb1", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "var=${m}var\nm=${var2}\nvar2=${var}"); + ac.registerSingleton("configurer1", PropertyPlaceholderConfigurer.class, pvs); + try { + ac.refresh(); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + } + } + + public void testPropertyPlaceholderConfigurerWithNestedCircularReference() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "name${var}"); + ac.registerSingleton("tb1", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "var=${m}var\nm=${var2}\nvar2=${m}"); + ac.registerSingleton("configurer1", PropertyPlaceholderConfigurer.class, pvs); + try { + ac.refresh(); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + } + } + + public void testPropertyPlaceholderConfigurerWithDefaultProperties() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", "${test}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("test", "mytest"); + pvs.addPropertyValue("properties", new Properties(props)); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("mytest", tb.getTouchy()); + } + + public void testPropertyPlaceholderConfigurerWithAutowireByType() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", "${test}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("target", new RuntimeBeanReference("tb")); + ac.registerSingleton("tbProxy", ProxyFactoryBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("test", "mytest"); + pvs.addPropertyValue("properties", new Properties(props)); + RootBeanDefinition ppcDef = new RootBeanDefinition(PropertyPlaceholderConfigurer.class, pvs); + ppcDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE); + ac.registerBeanDefinition("configurer", ppcDef); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("mytest", tb.getTouchy()); + } + + public void testPropertyPlaceholderConfigurerWithAliases() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", "${test}"); + ac.registerSingleton("tb", TestBean.class, pvs); + ac.registerAlias("tb", "${myAlias}"); + ac.registerAlias("${myTarget}", "alias2"); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("test", "mytest"); + props.put("myAlias", "alias"); + props.put("myTarget", "tb"); + pvs.addPropertyValue("properties", new Properties(props)); + ac.registerSingleton("configurer", PropertyPlaceholderConfigurer.class, pvs); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("mytest", tb.getTouchy()); + tb = (TestBean) ac.getBean("alias"); + assertEquals("mytest", tb.getTouchy()); + tb = (TestBean) ac.getBean("alias2"); + assertEquals("mytest", tb.getTouchy()); + } + + public void testPreferencesPlaceholderConfigurer() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "${myName}"); + pvs.addPropertyValue("age", "${myAge}"); + pvs.addPropertyValue("touchy", "${myTouchy}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("myAge", "99"); + pvs.addPropertyValue("properties", props); + ac.registerSingleton("configurer", PreferencesPlaceholderConfigurer.class, pvs); + Preferences.systemRoot().put("myName", "myNameValue"); + Preferences.systemRoot().put("myTouchy", "myTouchyValue"); + Preferences.userRoot().put("myTouchy", "myOtherTouchyValue"); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("myNameValue", tb.getName()); + assertEquals(99, tb.getAge()); + assertEquals("myOtherTouchyValue", tb.getTouchy()); + Preferences.userRoot().remove("myTouchy"); + Preferences.systemRoot().remove("myTouchy"); + Preferences.systemRoot().remove("myName"); + } + + public void testPreferencesPlaceholderConfigurerWithCustomTreePaths() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "${myName}"); + pvs.addPropertyValue("age", "${myAge}"); + pvs.addPropertyValue("touchy", "${myTouchy}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("myAge", "99"); + pvs.addPropertyValue("properties", props); + pvs.addPropertyValue("systemTreePath", "mySystemPath"); + pvs.addPropertyValue("userTreePath", "myUserPath"); + ac.registerSingleton("configurer", PreferencesPlaceholderConfigurer.class, pvs); + Preferences.systemRoot().node("mySystemPath").put("myName", "myNameValue"); + Preferences.systemRoot().node("mySystemPath").put("myTouchy", "myTouchyValue"); + Preferences.userRoot().node("myUserPath").put("myTouchy", "myOtherTouchyValue"); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("myNameValue", tb.getName()); + assertEquals(99, tb.getAge()); + assertEquals("myOtherTouchyValue", tb.getTouchy()); + Preferences.userRoot().node("myUserPath").remove("myTouchy"); + Preferences.systemRoot().node("mySystemPath").remove("myTouchy"); + Preferences.systemRoot().node("mySystemPath").remove("myName"); + } + + public void testPreferencesPlaceholderConfigurerWithPathInPlaceholder() { + StaticApplicationContext ac = new StaticApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "${mypath/myName}"); + pvs.addPropertyValue("age", "${myAge}"); + pvs.addPropertyValue("touchy", "${myotherpath/myTouchy}"); + ac.registerSingleton("tb", TestBean.class, pvs); + pvs = new MutablePropertyValues(); + Properties props = new Properties(); + props.put("myAge", "99"); + pvs.addPropertyValue("properties", props); + pvs.addPropertyValue("systemTreePath", "mySystemPath"); + pvs.addPropertyValue("userTreePath", "myUserPath"); + ac.registerSingleton("configurer", PreferencesPlaceholderConfigurer.class, pvs); + Preferences.systemRoot().node("mySystemPath").node("mypath").put("myName", "myNameValue"); + Preferences.systemRoot().node("mySystemPath/myotherpath").put("myTouchy", "myTouchyValue"); + Preferences.userRoot().node("myUserPath/myotherpath").put("myTouchy", "myOtherTouchyValue"); + ac.refresh(); + TestBean tb = (TestBean) ac.getBean("tb"); + assertEquals("myNameValue", tb.getName()); + assertEquals(99, tb.getAge()); + assertEquals("myOtherTouchyValue", tb.getTouchy()); + Preferences.userRoot().node("myUserPath/myotherpath").remove("myTouchy"); + Preferences.systemRoot().node("mySystemPath/myotherpath").remove("myTouchy"); + Preferences.systemRoot().node("mySystemPath/mypath").remove("myName"); + } + + + private static class ConvertingOverrideConfigurer extends PropertyOverrideConfigurer { + + protected String convertPropertyValue(String originalValue) { + return "X" + originalValue; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBeanTests.java new file mode 100644 index 00000000000..f093bffe9fe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBeanTests.java @@ -0,0 +1,346 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.NestedCheckedException; +import org.springframework.core.NestedRuntimeException; +import org.springframework.test.AssertThrows; + +/** + * @author Colin Sampaleanu + * @author Rick Evans + */ +public class ServiceLocatorFactoryBeanTests extends TestCase { + + public void testNoArgGetter() { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.registerSingleton("testService", TestService.class, new MutablePropertyValues()); + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestServiceLocator.class)); + ctx.registerSingleton("factory", ServiceLocatorFactoryBean.class, mpv); + ctx.refresh(); + + TestServiceLocator factory = (TestServiceLocator) ctx.getBean("factory"); + TestService testService = factory.getTestService(); + assertNotNull(testService); + } + + public void testErrorOnTooManyOrTooFew() throws Exception { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.registerSingleton("testService", TestService.class, new MutablePropertyValues()); + ctx.registerSingleton("testServiceInstance2", TestService.class, new MutablePropertyValues()); + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestServiceLocator.class)); + ctx.registerSingleton("factory", ServiceLocatorFactoryBean.class, mpv); + mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestServiceLocator2.class)); + ctx.registerSingleton("factory2", ServiceLocatorFactoryBean.class, mpv); + mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestService2Locator.class)); + ctx.registerSingleton("factory3", ServiceLocatorFactoryBean.class, mpv); + ctx.refresh(); + + final TestServiceLocator factory = (TestServiceLocator) ctx.getBean("factory"); + new AssertThrows(NoSuchBeanDefinitionException.class, "Must fail on more than one matching type") { + public void test() throws Exception { + factory.getTestService(); + } + }.runTest(); + + final TestServiceLocator2 factory2 = (TestServiceLocator2) ctx.getBean("factory2"); + new AssertThrows(NoSuchBeanDefinitionException.class, "Must fail on more than one matching type") { + public void test() throws Exception { + factory2.getTestService(null); + } + }.runTest(); + final TestService2Locator factory3 = (TestService2Locator) ctx.getBean("factory3"); + new AssertThrows(NoSuchBeanDefinitionException.class, "Must fail on no matching types") { + public void test() throws Exception { + factory3.getTestService(); + } + }.runTest(); + } + + public void testErrorOnTooManyOrTooFewWithCustomServiceLocatorException() { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.registerSingleton("testService", TestService.class, new MutablePropertyValues()); + ctx.registerSingleton("testServiceInstance2", TestService.class, new MutablePropertyValues()); + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestServiceLocator.class)); + mpv.addPropertyValue(new PropertyValue("serviceLocatorExceptionClass", CustomServiceLocatorException1.class)); + ctx.registerSingleton("factory", ServiceLocatorFactoryBean.class, mpv); + mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestServiceLocator2.class)); + mpv.addPropertyValue(new PropertyValue("serviceLocatorExceptionClass", CustomServiceLocatorException2.class)); + ctx.registerSingleton("factory2", ServiceLocatorFactoryBean.class, mpv); + mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestService2Locator.class)); + mpv.addPropertyValue(new PropertyValue("serviceLocatorExceptionClass", CustomServiceLocatorException3.class)); + ctx.registerSingleton("factory3", ServiceLocatorFactoryBean.class, mpv); + ctx.refresh(); + + TestServiceLocator factory = (TestServiceLocator) ctx.getBean("factory"); + try { + factory.getTestService(); + fail("Must fail on more than one matching type"); + } + catch (CustomServiceLocatorException1 expected) { + assertTrue(expected.getCause() instanceof NoSuchBeanDefinitionException); + } + TestServiceLocator2 factory2 = (TestServiceLocator2) ctx.getBean("factory2"); + try { + factory2.getTestService(null); + fail("Must fail on more than one matching type"); + } + catch (CustomServiceLocatorException2 expected) { + assertTrue(expected.getCause() instanceof NoSuchBeanDefinitionException); + } + final TestService2Locator factory3 = (TestService2Locator) ctx.getBean("factory3"); + new AssertThrows(CustomServiceLocatorException3.class, "Must fail on no matching types") { + public void test() throws Exception { + factory3.getTestService(); + } + }.runTest(); + } + + public void testStringArgGetter() throws Exception { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.registerSingleton("testService", TestService.class, new MutablePropertyValues()); + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue(new PropertyValue("serviceLocatorInterface", TestServiceLocator2.class)); + ctx.registerSingleton("factory", ServiceLocatorFactoryBean.class, mpv); + ctx.refresh(); + + // test string-arg getter with null id + final TestServiceLocator2 factory = (TestServiceLocator2) ctx.getBean("factory"); + TestService testBean = factory.getTestService(null); + // now test with explicit id + testBean = factory.getTestService("testService"); + // now verify failure on bad id + new AssertThrows(NoSuchBeanDefinitionException.class, "Illegal operation allowed") { + public void test() throws Exception { + factory.getTestService("bogusTestService"); + } + }.runTest(); + } + + public void testCombinedLocatorInterface() { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.registerPrototype("testService", TestService.class, new MutablePropertyValues()); + ctx.registerAlias("testService", "1"); + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue("serviceLocatorInterface", TestServiceLocator3.class); + ctx.registerSingleton("factory", ServiceLocatorFactoryBean.class, mpv); + ctx.refresh(); + + TestServiceLocator3 factory = (TestServiceLocator3) ctx.getBean("factory"); + TestService testBean1 = factory.getTestService(); + TestService testBean2 = factory.getTestService("testService"); + TestService testBean3 = factory.getTestService(1); + TestService testBean4 = factory.someFactoryMethod(); + assertNotSame(testBean1, testBean2); + assertNotSame(testBean1, testBean3); + assertNotSame(testBean1, testBean4); + assertNotSame(testBean2, testBean3); + assertNotSame(testBean2, testBean4); + assertNotSame(testBean3, testBean4); + + assertTrue(factory.toString().indexOf("TestServiceLocator3") != -1); + } + + public void testServiceMappings() { + StaticApplicationContext ctx = new StaticApplicationContext(); + ctx.registerPrototype("testService1", TestService.class, new MutablePropertyValues()); + ctx.registerPrototype("testService2", ExtendedTestService.class, new MutablePropertyValues()); + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue("serviceLocatorInterface", TestServiceLocator3.class); + mpv.addPropertyValue("serviceMappings", "=testService1\n1=testService1\n2=testService2"); + ctx.registerSingleton("factory", ServiceLocatorFactoryBean.class, mpv); + ctx.refresh(); + + TestServiceLocator3 factory = (TestServiceLocator3) ctx.getBean("factory"); + TestService testBean1 = factory.getTestService(); + TestService testBean2 = factory.getTestService("testService1"); + TestService testBean3 = factory.getTestService(1); + TestService testBean4 = factory.getTestService(2); + assertNotSame(testBean1, testBean2); + assertNotSame(testBean1, testBean3); + assertNotSame(testBean1, testBean4); + assertNotSame(testBean2, testBean3); + assertNotSame(testBean2, testBean4); + assertNotSame(testBean3, testBean4); + assertFalse(testBean1 instanceof ExtendedTestService); + assertFalse(testBean2 instanceof ExtendedTestService); + assertFalse(testBean3 instanceof ExtendedTestService); + assertTrue(testBean4 instanceof ExtendedTestService); + } + + public void testNoServiceLocatorInterfaceSupplied() throws Exception { + new AssertThrows(IllegalArgumentException.class, "No serviceLocator interface supplied") { + public void test() throws Exception { + new ServiceLocatorFactoryBean().afterPropertiesSet(); + } + }.runTest(); + } + + public void testWhenServiceLocatorInterfaceIsNotAnInterfaceType() throws Exception { + new AssertThrows(IllegalArgumentException.class, "Bad (non-interface-type) serviceLocator interface supplied") { + public void test() throws Exception { + ServiceLocatorFactoryBean factory = new ServiceLocatorFactoryBean(); + factory.setServiceLocatorInterface(getClass()); + factory.afterPropertiesSet(); + } + }.runTest(); + } + + public void testWhenServiceLocatorExceptionClassToExceptionTypeWithOnlyNoArgCtor() throws Exception { + new AssertThrows(IllegalArgumentException.class, "Bad (invalid-Exception-type) serviceLocatorException class supplied") { + public void test() throws Exception { + ServiceLocatorFactoryBean factory = new ServiceLocatorFactoryBean(); + factory.setServiceLocatorExceptionClass(ExceptionClassWithOnlyZeroArgCtor.class); + } + }.runTest(); + } + + public void testWhenServiceLocatorExceptionClassIsNotAnExceptionSubclass() throws Exception { + new AssertThrows(IllegalArgumentException.class, "Bad (non-Exception-type) serviceLocatorException class supplied") { + public void test() throws Exception { + ServiceLocatorFactoryBean factory = new ServiceLocatorFactoryBean(); + factory.setServiceLocatorExceptionClass(getClass()); + } + }.runTest(); + } + + public void testWhenServiceLocatorMethodCalledWithTooManyParameters() throws Exception { + ServiceLocatorFactoryBean factory = new ServiceLocatorFactoryBean(); + factory.setServiceLocatorInterface(ServiceLocatorInterfaceWithExtraNonCompliantMethod.class); + factory.afterPropertiesSet(); + final ServiceLocatorInterfaceWithExtraNonCompliantMethod locator = (ServiceLocatorInterfaceWithExtraNonCompliantMethod) factory.getObject(); + new AssertThrows(UnsupportedOperationException.class, "Bad method (too many args, doesn't obey class contract)") { + public void test() throws Exception { + locator.getTestService("not", "allowed"); + } + }.runTest(); + } + + public void testRequiresListableBeanFactoryAndChokesOnAnythingElse() throws Exception { + MockControl mockBeanFactory = MockControl.createControl(BeanFactory.class); + final BeanFactory beanFactory = (BeanFactory) mockBeanFactory.getMock(); + mockBeanFactory.replay(); + + new AssertThrows(FatalBeanException.class) { + public void test() throws Exception { + ServiceLocatorFactoryBean factory = new ServiceLocatorFactoryBean(); + factory.setBeanFactory(beanFactory); + } + }.runTest(); + + mockBeanFactory.verify(); + } + + + public static class TestService { + + } + + + public static class ExtendedTestService extends TestService { + + } + + + public static class TestService2 { + + } + + + public static interface TestServiceLocator { + + TestService getTestService(); + } + + + public static interface TestServiceLocator2 { + + TestService getTestService(String id) throws CustomServiceLocatorException2; + } + + + public static interface TestServiceLocator3 { + + TestService getTestService(); + + TestService getTestService(String id); + + TestService getTestService(int id); + + TestService someFactoryMethod(); + } + + + public static interface TestService2Locator { + + TestService2 getTestService() throws CustomServiceLocatorException3; + } + + + public static interface ServiceLocatorInterfaceWithExtraNonCompliantMethod { + + TestService2 getTestService(); + + TestService2 getTestService(String serviceName, String defaultNotAllowedParameter); + } + + + public static class CustomServiceLocatorException1 extends NestedRuntimeException { + + public CustomServiceLocatorException1(String message, Throwable cause) { + super(message, cause); + } + } + + + public static class CustomServiceLocatorException2 extends NestedCheckedException { + + public CustomServiceLocatorException2(Throwable cause) { + super("", cause); + } + } + + + public static class CustomServiceLocatorException3 extends NestedCheckedException { + + public CustomServiceLocatorException3(String message) { + super(message); + } + } + + + public static class ExceptionClassWithOnlyZeroArgCtor extends Exception { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleMapScope.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleMapScope.java new file mode 100644 index 00000000000..3aedfb8de71 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleMapScope.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.ObjectFactory; + +/** + * @author Juergen Hoeller + */ +public class SimpleMapScope implements Scope, Serializable { + + private final Map map = new HashMap(); + + private final List callbacks = new LinkedList(); + + + public SimpleMapScope() { + } + + public final Map getMap() { + return this.map; + } + + + public Object get(String name, ObjectFactory objectFactory) { + synchronized (this.map) { + Object scopedObject = this.map.get(name); + if (scopedObject == null) { + scopedObject = objectFactory.getObject(); + this.map.put(name, scopedObject); + } + return scopedObject; + } + } + + public Object remove(String name) { + synchronized (this.map) { + return this.map.remove(name); + } + } + + public void registerDestructionCallback(String name, Runnable callback) { + this.callbacks.add(callback); + } + + public void close() { + for (Iterator it = this.callbacks.iterator(); it.hasNext();) { + Runnable runnable = (Runnable) it.next(); + runnable.run(); + } + } + + public String getConversationId() { + return null; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java new file mode 100644 index 00000000000..26c41b74688 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.util.LinkedList; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.support.GenericApplicationContext; + +/** + * Simple test to illustrate and verify scope usage. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class SimpleScopeTests extends TestCase { + + private GenericApplicationContext applicationContext; + + protected void setUp() { + applicationContext = new GenericApplicationContext(); + Scope scope = new NoOpScope() { + private int index; + private List objects = new LinkedList(); { + objects.add(new TestBean()); + objects.add(new TestBean()); + } + public Object get(String name, ObjectFactory objectFactory) { + if (index >= objects.size()) { + index = 0; + } + return objects.get(index++); + } + }; + + applicationContext.getBeanFactory().registerScope("myScope", scope); + + String[] scopeNames = applicationContext.getBeanFactory().getRegisteredScopeNames(); + assertEquals(1, scopeNames.length); + assertEquals("myScope", scopeNames[0]); + assertSame(scope, applicationContext.getBeanFactory().getRegisteredScope("myScope")); + + XmlBeanDefinitionReader xbdr = new XmlBeanDefinitionReader(applicationContext); + xbdr.loadBeanDefinitions("org/springframework/beans/factory/config/simpleScope.xml"); + + applicationContext.refresh(); + } + + public void testCanGetScopedObject() { + TestBean tb1 = (TestBean) applicationContext.getBean("usesScope"); + TestBean tb2 = (TestBean) applicationContext.getBean("usesScope"); + assertNotSame(tb1, tb2); + TestBean tb3 = (TestBean) applicationContext.getBean("usesScope"); + assertSame(tb3, tb1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/fieldRetrieving.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/fieldRetrieving.xml new file mode 100644 index 00000000000..564920e6d3a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/fieldRetrieving.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/propertyPath.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/propertyPath.xml new file mode 100644 index 00000000000..ceacc6bc44b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/propertyPath.xml @@ -0,0 +1,62 @@ + + + + + + + 10 + + + 11 + + + + + + 98 + + + 99 + + + + + + + + 12 + + + age + + + + tb + spouse.age + + + + + + + + + + + + tb + spouse + org.springframework.beans.TestBean + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/simpleScope.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/simpleScope.xml new file mode 100644 index 00000000000..2bd9706f77e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/simpleScope.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test-properties.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test-properties.xml new file mode 100644 index 00000000000..e39b872c9fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test-properties.xml @@ -0,0 +1,9 @@ + + + + + + 99 + test + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test.properties new file mode 100644 index 00000000000..9affcba0135 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/test.properties @@ -0,0 +1,2 @@ +tb.array[0].age=99 +tb.list[1].name=test diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/util.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/util.properties new file mode 100644 index 00000000000..c9f0304f65e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/config/util.properties @@ -0,0 +1 @@ +foo=bar \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/dependentBeans.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/dependentBeans.xml new file mode 100644 index 00000000000..0dae03ee940 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/dependentBeans.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeanReturnsNull.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeanReturnsNull.xml new file mode 100644 index 00000000000..d9b583910ea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeanReturnsNull.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeansWithAutowiring.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeansWithAutowiring.xml new file mode 100644 index 00000000000..e650f8082a0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/factoryBeansWithAutowiring.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + yourName + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/leaf.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/leaf.xml new file mode 100644 index 00000000000..4183c20b691 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/leaf.xml @@ -0,0 +1,13 @@ + + + + + + + custom + 25 + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/middle.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/middle.xml new file mode 100644 index 00000000000..ced3b8f2ea1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/middle.xml @@ -0,0 +1,20 @@ + + + + + + + + custom + 666 + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CollectingReaderEventListener.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CollectingReaderEventListener.java new file mode 100644 index 00000000000..74d6b48540e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CollectingReaderEventListener.java @@ -0,0 +1,86 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.parsing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.core.CollectionFactory; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class CollectingReaderEventListener implements ReaderEventListener { + + private final List defaults = new LinkedList(); + + private final Map componentDefinitions = CollectionFactory.createLinkedMapIfPossible(8); + + private final Map aliasMap = CollectionFactory.createLinkedMapIfPossible(8); + + private final List imports = new LinkedList(); + + + public void defaultsRegistered(DefaultsDefinition defaultsDefinition) { + this.defaults.add(defaultsDefinition); + } + + public List getDefaults() { + return Collections.unmodifiableList(this.defaults); + } + + public void componentRegistered(ComponentDefinition componentDefinition) { + this.componentDefinitions.put(componentDefinition.getName(), componentDefinition); + } + + public ComponentDefinition getComponentDefinition(String name) { + return (ComponentDefinition) this.componentDefinitions.get(name); + } + + public ComponentDefinition[] getComponentDefinitions() { + Collection collection = this.componentDefinitions.values(); + return (ComponentDefinition[]) collection.toArray(new ComponentDefinition[collection.size()]); + } + + public void aliasRegistered(AliasDefinition aliasDefinition) { + List aliases = (List) this.aliasMap.get(aliasDefinition.getBeanName()); + if(aliases == null) { + aliases = new ArrayList(); + this.aliasMap.put(aliasDefinition.getBeanName(), aliases); + } + aliases.add(aliasDefinition); + } + + public List getAliases(String beanName) { + List aliases = (List) this.aliasMap.get(beanName); + return aliases == null ? null : Collections.unmodifiableList(aliases); + } + + public void importProcessed(ImportDefinition importDefinition) { + this.imports.add(importDefinition); + } + + public List getImports() { + return Collections.unmodifiableList(this.imports); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ConstructorArgumentEntryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ConstructorArgumentEntryTests.java new file mode 100644 index 00000000000..e102aa9f178 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ConstructorArgumentEntryTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.parsing; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link ConstructorArgumentEntry} class. + * + * @author Rick Evans + */ +public final class ConstructorArgumentEntryTests extends TestCase { + + public void testCtorBailsOnNegativeCtorIndexArgument() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ConstructorArgumentEntry(-1); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java new file mode 100644 index 00000000000..5581384221e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.parsing; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class CustomProblemReporterTests extends TestCase { + + private CollatingProblemReporter problemReporter; + + private DefaultListableBeanFactory beanFactory; + + private XmlBeanDefinitionReader reader; + + + protected void setUp() throws Exception { + this.problemReporter = new CollatingProblemReporter(); + this.beanFactory = new DefaultListableBeanFactory(); + this.reader = new XmlBeanDefinitionReader(this.beanFactory); + this.reader.setProblemReporter(this.problemReporter); + } + + public void testErrorsAreCollated() throws Exception { + this.reader.loadBeanDefinitions(new ClassPathResource("withErrors.xml", getClass())); + assertEquals("Incorrect number of errors collated", 4, this.problemReporter.getErrors().length); + + TestBean bean = (TestBean) this.beanFactory.getBean("validBean"); + assertNotNull(bean); + } + + + private static class CollatingProblemReporter implements ProblemReporter { + + private List errors = new ArrayList(); + + private List warnings = new ArrayList(); + + + public void fatal(Problem problem) { + throw new BeanDefinitionParsingException(problem); + } + + public void error(Problem problem) { + System.out.println(problem); + this.errors.add(problem); + } + + public Problem[] getErrors() { + return (Problem[]) this.errors.toArray(new Problem[this.errors.size()]); + } + + public void warning(Problem problem) { + System.out.println(problem); + this.warnings.add(problem); + } + + public Problem[] getWarnings() { + return (Problem[]) this.warnings.toArray(new Problem[this.warnings.size()]); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/FailFastProblemReporterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/FailFastProblemReporterTests.java new file mode 100644 index 00000000000..f41d11304bb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/FailFastProblemReporterTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.parsing; + +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.easymock.AbstractMatcher; +import org.easymock.MockControl; + +import org.springframework.core.io.DescriptiveResource; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public final class FailFastProblemReporterTests extends TestCase { + + public void testError() throws Exception { + new AssertThrows(BeanDefinitionParsingException.class) { + public void test() throws Exception { + FailFastProblemReporter reporter = new FailFastProblemReporter(); + reporter.error(new Problem("VGER", new Location(new DescriptiveResource("here")), + null, new IllegalArgumentException())); + } + }.runTest(); + } + + public void testWarn() throws Exception { + IllegalArgumentException rootCause = new IllegalArgumentException(); + Problem problem = new Problem("VGER", new Location(new DescriptiveResource("here")), + null, new IllegalArgumentException()); + + MockControl mockLog = MockControl.createControl(Log.class); + Log log = (Log) mockLog.getMock(); + log.warn(null, rootCause); + mockLog.setMatcher(new AbstractMatcher() { + public boolean matches(Object[] expected, Object[] actual) { + Assert.assertEquals(2, actual.length); + Assert.assertTrue(actual[1] instanceof IllegalArgumentException); + return true; + } + }); + mockLog.replay(); + + FailFastProblemReporter reporter = new FailFastProblemReporter(); + reporter.setLogger(log); + reporter.warning(problem); + + mockLog.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/NullSourceExtractorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/NullSourceExtractorTests.java new file mode 100644 index 00000000000..708331ed73c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/NullSourceExtractorTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.parsing; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + */ +public final class NullSourceExtractorTests extends TestCase { + + public void testPassThroughContract() throws Exception { + Object source = new Object(); + Object extractedSource = new NullSourceExtractor().extractSource(source, null); + assertNull("The contract of NullSourceExtractor states that the extraction *always* return null", extractedSource); + } + + public void testPassThroughContractEvenWithNull() throws Exception { + Object extractedSource = new NullSourceExtractor().extractSource(null, null); + assertNull("The contract of NullSourceExtractor states that the extraction *always* return null", extractedSource); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ParseStateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ParseStateTests.java new file mode 100644 index 00000000000..8a2b58788c6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/ParseStateTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.parsing; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.parsing.ParseState; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class ParseStateTests extends TestCase { + + public void testSimple() throws Exception { + MockEntry entry = new MockEntry(); + + ParseState parseState = new ParseState(); + parseState.push(entry); + assertEquals("Incorrect peek value.", entry, parseState.peek()); + parseState.pop(); + assertNull("Should get null on peek()", parseState.peek()); + } + + public void testNesting() throws Exception { + MockEntry one = new MockEntry(); + MockEntry two = new MockEntry(); + MockEntry three = new MockEntry(); + + ParseState parseState = new ParseState(); + parseState.push(one); + assertEquals(one, parseState.peek()); + parseState.push(two); + assertEquals(two, parseState.peek()); + parseState.push(three); + assertEquals(three, parseState.peek()); + + parseState.pop(); + assertEquals(two, parseState.peek()); + parseState.pop(); + assertEquals(one, parseState.peek()); + } + + public void testSnapshot() throws Exception { + MockEntry entry = new MockEntry(); + + ParseState original = new ParseState(); + original.push(entry); + + ParseState snapshot = original.snapshot(); + original.push(new MockEntry()); + assertEquals("Snapshot should not have been modified.", entry, snapshot.peek()); + } + + + private static class MockEntry implements ParseState.Entry { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PassThroughSourceExtractorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PassThroughSourceExtractorTests.java new file mode 100644 index 00000000000..b65e047b473 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PassThroughSourceExtractorTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.parsing; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + */ +public final class PassThroughSourceExtractorTests extends TestCase { + + public void testPassThroughContract() throws Exception { + Object source = new Object(); + Object extractedSource = new PassThroughSourceExtractor().extractSource(source, null); + assertSame("The contract of PassThroughSourceExtractor states that the supplied source object *must* be returned as-is", source, extractedSource); + } + + public void testPassThroughContractEvenWithNull() throws Exception { + Object extractedSource = new PassThroughSourceExtractor().extractSource(null, null); + assertNull("The contract of PassThroughSourceExtractor states that the supplied source object *must* be returned as-is (even if null)", extractedSource); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PropertyEntryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PropertyEntryTests.java new file mode 100644 index 00000000000..d94a8cebf7f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/PropertyEntryTests.java @@ -0,0 +1,37 @@ +package org.springframework.beans.factory.parsing; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link PropertyEntry} class. + * + * @author Rick Evans + */ +public final class PropertyEntryTests extends TestCase { + + public void testCtorBailsOnNullPropertyNameArgument() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new PropertyEntry(null); + } + }.runTest(); + } + + public void testCtorBailsOnEmptyPropertyNameArgument() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new PropertyEntry(""); + } + }.runTest(); + } + + public void testCtorBailsOnWhitespacedPropertyNameArgument() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new PropertyEntry("\t "); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/withErrors.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/withErrors.xml new file mode 100644 index 00000000000..218056302c7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/parsing/withErrors.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/root.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/root.xml new file mode 100644 index 00000000000..913a57378e2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/root.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + custom + 25 + + + + + + false + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java new file mode 100644 index 00000000000..0aedf79d322 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.PrototypeTargetTests.TestBean; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class BeanDefinitionBuilderTests extends TestCase { + + public void testBeanClassWithSimpleProperty() { + String[] dependsOn = new String[] { "A", "B", "C" }; + BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); + bdb.setSingleton(false).addPropertyReference("age", "15"); + for (int i = 0; i < dependsOn.length; i++) { + bdb.addDependsOn(dependsOn[i]); + } + + RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition(); + assertFalse(rbd.isSingleton()); + assertEquals(TestBean.class, rbd.getBeanClass()); + assertTrue("Depends on was added", Arrays.equals(dependsOn, rbd.getDependsOn())); + assertTrue(rbd.getPropertyValues().contains("age")); + } + + public void testBeanClassWithFactoryMethod() { + BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class, "create"); + RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition(); + assertTrue(rbd.hasBeanClass()); + assertEquals(TestBean.class, rbd.getBeanClass()); + assertEquals("create", rbd.getFactoryMethodName()); + } + + public void testBeanClassName() { + BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class.getName()); + RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition(); + assertFalse(rbd.hasBeanClass()); + assertEquals(TestBean.class.getName(), rbd.getBeanClassName()); + } + + public void testBeanClassNameWithFactoryMethod() { + BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class.getName(), "create"); + RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition(); + assertFalse(rbd.hasBeanClass()); + assertEquals(TestBean.class.getName(), rbd.getBeanClassName()); + assertEquals("create", rbd.getFactoryMethodName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java new file mode 100644 index 00000000000..786e41f08df --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java @@ -0,0 +1,134 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.BeanDefinitionHolder; + +/** + * @author Juergen Hoeller + */ +public class BeanDefinitionTests extends TestCase { + + public void testBeanDefinitionEquality() { + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.setAbstract(true); + bd.setLazyInit(true); + bd.setScope("request"); + RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.setAbstract(true); + otherBd.setLazyInit(true); + otherBd.setScope("request"); + assertTrue(bd.equals(otherBd)); + assertTrue(otherBd.equals(bd)); + assertTrue(bd.hashCode() == otherBd.hashCode()); + } + + public void testBeanDefinitionEqualityWithPropertyValues() { + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.getPropertyValues().addPropertyValue("name", "myName"); + bd.getPropertyValues().addPropertyValue("age", "99"); + RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class); + otherBd.getPropertyValues().addPropertyValue("name", "myName"); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.getPropertyValues().addPropertyValue("age", "11"); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.getPropertyValues().addPropertyValue("age", "99"); + assertTrue(bd.equals(otherBd)); + assertTrue(otherBd.equals(bd)); + assertTrue(bd.hashCode() == otherBd.hashCode()); + } + + public void testBeanDefinitionEqualityWithConstructorArguments() { + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.getConstructorArgumentValues().addGenericArgumentValue("test"); + bd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class); + otherBd.getConstructorArgumentValues().addGenericArgumentValue("test"); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(9)); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + assertTrue(bd.equals(otherBd)); + assertTrue(otherBd.equals(bd)); + assertTrue(bd.hashCode() == otherBd.hashCode()); + } + + public void testBeanDefinitionEqualityWithTypedConstructorArguments() { + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.getConstructorArgumentValues().addGenericArgumentValue("test", "int"); + bd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5), "long"); + RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class); + otherBd.getConstructorArgumentValues().addGenericArgumentValue("test", "int"); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5), "int"); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5), "long"); + assertTrue(bd.equals(otherBd)); + assertTrue(otherBd.equals(bd)); + assertTrue(bd.hashCode() == otherBd.hashCode()); + } + + public void testBeanDefinitionHolderEquality() { + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.setAbstract(true); + bd.setLazyInit(true); + bd.setScope("request"); + BeanDefinitionHolder holder = new BeanDefinitionHolder(bd, "bd"); + RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class); + assertTrue(!bd.equals(otherBd)); + assertTrue(!otherBd.equals(bd)); + otherBd.setAbstract(true); + otherBd.setLazyInit(true); + otherBd.setScope("request"); + BeanDefinitionHolder otherHolder = new BeanDefinitionHolder(bd, "bd"); + assertTrue(holder.equals(otherHolder)); + assertTrue(otherHolder.equals(holder)); + assertTrue(holder.hashCode() == otherHolder.hashCode()); + } + + public void testBeanDefinitionMerging() { + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.getConstructorArgumentValues().addGenericArgumentValue("test"); + bd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + bd.getPropertyValues().addPropertyValue("name", "myName"); + bd.getPropertyValues().addPropertyValue("age", "99"); + + ChildBeanDefinition childBd = new ChildBeanDefinition("bd"); + + RootBeanDefinition mergedBd = new RootBeanDefinition(bd); + mergedBd.overrideFrom(childBd); + assertEquals(2, mergedBd.getConstructorArgumentValues().getArgumentCount()); + assertEquals(2, mergedBd.getPropertyValues().size()); + assertEquals(bd, mergedBd); + + mergedBd.getConstructorArgumentValues().getArgumentValue(1, null).setValue(new Integer(9)); + assertEquals(new Integer(5), bd.getConstructorArgumentValues().getArgumentValue(1, null).getValue()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java new file mode 100644 index 00000000000..48985a82e32 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; + +/** + * @author Rob Harrop + */ +public class DefinitionMetadataEqualsHashCodeTests extends TestCase { + + public void testRootBeanDefinitionEqualsAndHashCode() throws Exception { + RootBeanDefinition master = new RootBeanDefinition(TestBean.class); + RootBeanDefinition equal = new RootBeanDefinition(TestBean.class); + RootBeanDefinition notEqual = new RootBeanDefinition(String.class); + RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {}; + setBaseProperties(master); + setBaseProperties(equal); + setBaseProperties(notEqual); + setBaseProperties(subclass); + + assertEqualsContract(master, equal, notEqual, subclass); + assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode()); + } + + public void testChildBeanDefinitionEqualsAndHashCode() throws Exception { + ChildBeanDefinition master = new ChildBeanDefinition("foo"); + ChildBeanDefinition equal = new ChildBeanDefinition("foo"); + ChildBeanDefinition notEqual = new ChildBeanDefinition("bar"); + ChildBeanDefinition subclass = new ChildBeanDefinition("foo"){}; + setBaseProperties(master); + setBaseProperties(equal); + setBaseProperties(notEqual); + setBaseProperties(subclass); + + assertEqualsContract(master, equal, notEqual, subclass); + assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode()); + } + + public void testRuntimeBeanReference() throws Exception { + RuntimeBeanReference master = new RuntimeBeanReference("name"); + RuntimeBeanReference equal = new RuntimeBeanReference("name"); + RuntimeBeanReference notEqual = new RuntimeBeanReference("someOtherName"); + RuntimeBeanReference subclass = new RuntimeBeanReference("name"){}; + assertEqualsContract(master, equal, notEqual, subclass); + } + private void setBaseProperties(AbstractBeanDefinition definition) { + definition.setAbstract(true); + definition.setAttribute("foo", "bar"); + definition.setAutowireCandidate(false); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + //definition.getConstructorArgumentValues().addGenericArgumentValue("foo"); + definition.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS); + definition.setDependsOn(new String[]{"foo", "bar"}); + definition.setDestroyMethodName("destroy"); + definition.setEnforceDestroyMethod(false); + definition.setEnforceInitMethod(true); + definition.setFactoryBeanName("factoryBean"); + definition.setFactoryMethodName("factoryMethod"); + definition.setInitMethodName("init"); + definition.setLazyInit(true); + definition.getMethodOverrides().addOverride(new LookupOverride("foo", "bar")); + definition.getMethodOverrides().addOverride(new ReplaceOverride("foo", "bar")); + definition.getPropertyValues().addPropertyValue("foo", "bar"); + definition.setResourceDescription("desc"); + definition.setRole(BeanDefinition.ROLE_APPLICATION); + definition.setScope(BeanDefinition.SCOPE_PROTOTYPE); + definition.setSource("foo"); + } + + private void assertEqualsContract(Object master, Object equal, Object notEqual, Object subclass) { + assertEquals("Should be equal", master, equal); + assertFalse("Should not be equal", master.equals(notEqual)); + assertEquals("Subclass should be equal", master, subclass); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedListTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedListTests.java new file mode 100644 index 00000000000..9dc27c7f373 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedListTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.util.List; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ManagedListTests extends TestCase { + + public void testMergeSunnyDay() { + ManagedList parent = new ManagedList(); + parent.add("one"); + parent.add("two"); + ManagedList child = new ManagedList(); + child.add("three"); + child.setMergeEnabled(true); + List mergedList = (List) child.merge(parent); + assertEquals("merge() obviously did not work.", 3, mergedList.size()); + } + + public void testMergeWithNullParent() { + ManagedList child = new ManagedList(); + child.add("one"); + child.setMergeEnabled(true); + assertSame(child, child.merge(null)); + } + + public void testMergeNotAllowedWhenMergeNotEnabled() { + ManagedList child = new ManagedList(); + try { + child.merge(null); + fail("Must have failed by this point (cannot merge() when the mergeEnabled property is false."); + } + catch (IllegalStateException expected) { + } + } + + public void testMergeWithNonCompatibleParentType() { + ManagedList child = new ManagedList(); + child.add("one"); + child.setMergeEnabled(true); + try { + child.merge("hello"); + fail("Must have failed by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testMergeEmptyChild() { + ManagedList parent = new ManagedList(); + parent.add("one"); + parent.add("two"); + ManagedList child = new ManagedList(); + child.setMergeEnabled(true); + List mergedList = (List) child.merge(parent); + assertEquals("merge() obviously did not work.", 2, mergedList.size()); + } + + public void testMergeChildValuesOverrideTheParents() { + // doesn't make a whole lotta sense in the context of a list... + ManagedList parent = new ManagedList(); + parent.add("one"); + parent.add("two"); + ManagedList child = new ManagedList(); + child.add("one"); + child.setMergeEnabled(true); + List mergedList = (List) child.merge(parent); + assertEquals("merge() obviously did not work.", 3, mergedList.size()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedMapTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedMapTests.java new file mode 100644 index 00000000000..c86752d8e9a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedMapTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.util.Map; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ManagedMapTests extends TestCase { + + public void testMergeSunnyDay() { + ManagedMap parent = new ManagedMap(); + parent.put("one", "one"); + parent.put("two", "two"); + ManagedMap child = new ManagedMap(); + child.put("three", "three"); + child.setMergeEnabled(true); + Map mergedMap = (Map) child.merge(parent); + assertEquals("merge() obviously did not work.", 3, mergedMap.size()); + } + + public void testMergeWithNullParent() { + ManagedMap child = new ManagedMap(); + child.setMergeEnabled(true); + assertSame(child, child.merge(null)); + } + + public void testMergeWithNonCompatibleParentType() { + ManagedMap map = new ManagedMap(); + map.setMergeEnabled(true); + try { + map.merge("hello"); + fail("Must have failed by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testMergeNotAllowedWhenMergeNotEnabled() { + ManagedMap map = new ManagedMap(); + try { + map.merge(null); + fail("Must have failed by this point (cannot merge() when the mergeEnabled property is false."); + } + catch (IllegalStateException expected) { + } + } + + public void testMergeEmptyChild() { + ManagedMap parent = new ManagedMap(); + parent.put("one", "one"); + parent.put("two", "two"); + ManagedMap child = new ManagedMap(); + child.setMergeEnabled(true); + Map mergedMap = (Map) child.merge(parent); + assertEquals("merge() obviously did not work.", 2, mergedMap.size()); + } + + public void testMergeChildValuesOverrideTheParents() { + ManagedMap parent = new ManagedMap(); + parent.put("one", "one"); + parent.put("two", "two"); + ManagedMap child = new ManagedMap(); + child.put("one", "fork"); + child.setMergeEnabled(true); + Map mergedMap = (Map) child.merge(parent); + // child value for 'one' must override parent value... + assertEquals("merge() obviously did not work.", 2, mergedMap.size()); + assertEquals("Parent value not being overridden during merge().", "fork", mergedMap.get("one")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedPropertiesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedPropertiesTests.java new file mode 100644 index 00000000000..7594ab6cddd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedPropertiesTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.util.Map; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ManagedPropertiesTests extends TestCase { + + public void testMergeSunnyDay() { + ManagedProperties parent = new ManagedProperties(); + parent.setProperty("one", "one"); + parent.setProperty("two", "two"); + ManagedProperties child = new ManagedProperties(); + child.setProperty("three", "three"); + child.setMergeEnabled(true); + Map mergedMap = (Map) child.merge(parent); + assertEquals("merge() obviously did not work.", 3, mergedMap.size()); + } + + public void testMergeWithNullParent() { + ManagedProperties child = new ManagedProperties(); + child.setMergeEnabled(true); + assertSame(child, child.merge(null)); + } + + public void testMergeWithNonCompatibleParentType() { + ManagedProperties map = new ManagedProperties(); + map.setMergeEnabled(true); + try { + map.merge("hello"); + fail("Must have failed by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testMergeNotAllowedWhenMergeNotEnabled() { + ManagedProperties map = new ManagedProperties(); + try { + map.merge(null); + fail("Must have failed by this point (cannot merge() when the mergeEnabled property is false."); + } + catch (IllegalStateException expected) { + } + } + + public void testMergeEmptyChild() { + ManagedProperties parent = new ManagedProperties(); + parent.setProperty("one", "one"); + parent.setProperty("two", "two"); + ManagedProperties child = new ManagedProperties(); + child.setMergeEnabled(true); + Map mergedMap = (Map) child.merge(parent); + assertEquals("merge() obviously did not work.", 2, mergedMap.size()); + } + + public void testMergeChildValuesOverrideTheParents() { + ManagedProperties parent = new ManagedProperties(); + parent.setProperty("one", "one"); + parent.setProperty("two", "two"); + ManagedProperties child = new ManagedProperties(); + child.setProperty("one", "fork"); + child.setMergeEnabled(true); + Map mergedMap = (Map) child.merge(parent); + // child value for 'one' must override parent value... + assertEquals("merge() obviously did not work.", 2, mergedMap.size()); + assertEquals("Parent value not being overridden during merge().", "fork", mergedMap.get("one")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedSetTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedSetTests.java new file mode 100644 index 00000000000..0eea409ab89 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/ManagedSetTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.util.Set; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ManagedSetTests extends TestCase { + + public void testMergeSunnyDay() { + ManagedSet parent = new ManagedSet(); + parent.add("one"); + parent.add("two"); + ManagedSet child = new ManagedSet(); + child.add("three"); + child.setMergeEnabled(true); + Set mergedSet = (Set) child.merge(parent); + assertEquals("merge() obviously did not work.", 3, mergedSet.size()); + } + + public void testMergeWithNullParent() { + ManagedSet child = new ManagedSet(); + child.add("one"); + child.setMergeEnabled(true); + assertSame(child, child.merge(null)); + } + + public void testMergeNotAllowedWhenMergeNotEnabled() { + ManagedSet child = new ManagedSet(); + try { + child.merge(null); + fail("Must have failed by this point (cannot merge() when the mergeEnabled property is false."); + } + catch (IllegalStateException expected) { + } + } + + public void testMergeWithNonCompatibleParentType() { + ManagedSet child = new ManagedSet(); + child.add("one"); + child.setMergeEnabled(true); + try { + child.merge("hello"); + fail("Must have failed by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testMergeEmptyChild() { + ManagedSet parent = new ManagedSet(); + parent.add("one"); + parent.add("two"); + ManagedSet child = new ManagedSet(); + child.setMergeEnabled(true); + Set mergedSet = (Set) child.merge(parent); + assertEquals("merge() obviously did not work.", 2, mergedSet.size()); + } + + public void testMergeChildValuesOverrideTheParents() { + // asserts that the set contract is not violated during a merge() operation... + ManagedSet parent = new ManagedSet(); + parent.add("one"); + parent.add("two"); + ManagedSet child = new ManagedSet(); + child.add("one"); + child.setMergeEnabled(true); + Set mergedSet = (Set) child.merge(parent); + assertEquals("merge() obviously did not work.", 2, mergedSet.size()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java new file mode 100644 index 00000000000..7f7618914d6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import junit.framework.TestCase; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.TestBean; + +/** + * @author Rob Harrop + */ +public class PropertiesBeanDefinitionReaderTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + private PropertiesBeanDefinitionReader reader; + + protected void setUp() throws Exception { + this.beanFactory = new DefaultListableBeanFactory(); + this.reader = new PropertiesBeanDefinitionReader(beanFactory); + } + + public void testWithSimpleConstructorArg() { + this.reader.loadBeanDefinitions(new ClassPathResource("simpleConstructorArg.properties", getClass())); + TestBean bean = (TestBean)this.beanFactory.getBean("testBean"); + assertEquals("Rob Harrop", bean.getName()); + } + + public void testWithConstructorArgRef() throws Exception { + this.reader.loadBeanDefinitions(new ClassPathResource("refConstructorArg.properties", getClass())); + TestBean rob = (TestBean)this.beanFactory.getBean("rob"); + TestBean sally = (TestBean)this.beanFactory.getBean("sally"); + assertEquals(sally, rob.getSpouse()); + } + + public void testWithMultipleConstructorsArgs() throws Exception { + this.reader.loadBeanDefinitions(new ClassPathResource("multiConstructorArgs.properties", getClass())); + TestBean bean = (TestBean)this.beanFactory.getBean("testBean"); + assertEquals("Rob Harrop", bean.getName()); + assertEquals(23, bean.getAge()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/multiConstructorArgs.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/multiConstructorArgs.properties new file mode 100644 index 00000000000..fa36ea20e7b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/multiConstructorArgs.properties @@ -0,0 +1,3 @@ +testBean.(class)=org.springframework.beans.TestBean +testBean.$0=Rob Harrop +testBean.$1=23 \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/refConstructorArg.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/refConstructorArg.properties new file mode 100644 index 00000000000..05b6f9a00e7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/refConstructorArg.properties @@ -0,0 +1,5 @@ +sally.(class)=org.springframework.beans.TestBean +sally.name=Sally + +rob.(class)=org.springframework.beans.TestBean +rob.$0(ref)=sally \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/simpleConstructorArg.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/simpleConstructorArg.properties new file mode 100644 index 00000000000..92a216ca41d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/support/simpleConstructorArg.properties @@ -0,0 +1,2 @@ +testBean.(class)=org.springframework.beans.TestBean +testBean.$0=Rob Harrop \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java new file mode 100644 index 00000000000..a381e50ed76 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java @@ -0,0 +1,136 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.wiring; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class BeanConfigurerSupportTests extends TestCase { + + public void testSupplyIncompatibleBeanFactoryImplementation() throws Exception { + MockControl mock = MockControl.createControl(BeanFactory.class); + mock.replay(); + try { + new StubBeanConfigurerSupport().setBeanFactory((BeanFactory) mock.getMock()); + fail("Must have thrown an IllegalArgumentException by this point (incompatible BeanFactory implementation supplied)"); + } + catch (IllegalArgumentException expected) { + } + mock.verify(); + } + + public void testConfigureBeanDoesNothingIfBeanWiringInfoResolverResolvesToNull() throws Exception { + TestBean beanInstance = new TestBean(); + + MockControl mock = MockControl.createControl(BeanWiringInfoResolver.class); + BeanWiringInfoResolver resolver = (BeanWiringInfoResolver) mock.getMock(); + resolver.resolveWiringInfo(beanInstance); + mock.setReturnValue(null); + mock.replay(); + + BeanConfigurerSupport configurer = new StubBeanConfigurerSupport(); + configurer.setBeanWiringInfoResolver(resolver); + configurer.setBeanFactory(new DefaultListableBeanFactory()); + configurer.configureBean(beanInstance); + mock.verify(); + assertNull(beanInstance.getName()); + } + + public void testConfigureBeanDoesNothingIfNoBeanFactoryHasBeenSet() throws Exception { + TestBean beanInstance = new TestBean(); + BeanConfigurerSupport configurer = new StubBeanConfigurerSupport(); + configurer.configureBean(beanInstance); + assertNull(beanInstance.getName()); + } + + public void testConfigureBeanReallyDoesDefaultToUsingTheFullyQualifiedClassNameOfTheSuppliedBeanInstance() throws Exception { + TestBean beanInstance = new TestBean(); + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); + builder.addPropertyValue("name", "Harriet Wheeler"); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(beanInstance.getClass().getName(), builder.getBeanDefinition()); + + BeanConfigurerSupport configurer = new StubBeanConfigurerSupport(); + configurer.setBeanFactory(factory); + configurer.afterPropertiesSet(); + configurer.configureBean(beanInstance); + assertEquals("Bean is evidently not being configured (for some reason)", "Harriet Wheeler", beanInstance.getName()); + } + + public void testConfigureBeanPerformsAutowiringByNameIfAppropriateBeanWiringInfoResolverIsPluggedIn() throws Exception { + TestBean beanInstance = new TestBean(); + // spouse for autowiring by name... + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); + builder.addConstructorArgValue("David Gavurin"); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("spouse", builder.getBeanDefinition()); + + MockControl mock = MockControl.createControl(BeanWiringInfoResolver.class); + BeanWiringInfoResolver resolver = (BeanWiringInfoResolver) mock.getMock(); + resolver.resolveWiringInfo(beanInstance); + mock.setReturnValue(new BeanWiringInfo(BeanWiringInfo.AUTOWIRE_BY_NAME, false)); + mock.replay(); + + BeanConfigurerSupport configurer = new StubBeanConfigurerSupport(); + configurer.setBeanFactory(factory); + configurer.setBeanWiringInfoResolver(resolver); + configurer.configureBean(beanInstance); + assertEquals("Bean is evidently not being configured (for some reason)", "David Gavurin", beanInstance.getSpouse().getName()); + + mock.verify(); + } + + public void testConfigureBeanPerformsAutowiringByTypeIfAppropriateBeanWiringInfoResolverIsPluggedIn() throws Exception { + TestBean beanInstance = new TestBean(); + // spouse for autowiring by type... + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); + builder.addConstructorArgValue("David Gavurin"); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("Mmm, I fancy a salad!", builder.getBeanDefinition()); + + MockControl mock = MockControl.createControl(BeanWiringInfoResolver.class); + BeanWiringInfoResolver resolver = (BeanWiringInfoResolver) mock.getMock(); + resolver.resolveWiringInfo(beanInstance); + mock.setReturnValue(new BeanWiringInfo(BeanWiringInfo.AUTOWIRE_BY_TYPE, false)); + mock.replay(); + + BeanConfigurerSupport configurer = new StubBeanConfigurerSupport(); + configurer.setBeanFactory(factory); + configurer.setBeanWiringInfoResolver(resolver); + configurer.configureBean(beanInstance); + assertEquals("Bean is evidently not being configured (for some reason)", "David Gavurin", beanInstance.getSpouse().getName()); + + mock.verify(); + } + + + private static class StubBeanConfigurerSupport extends BeanConfigurerSupport { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanWiringInfoTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanWiringInfoTests.java new file mode 100644 index 00000000000..18ab24bedfb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/BeanWiringInfoTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.wiring; + +import junit.framework.TestCase; + +/** + * Unit tests for the BeanWiringInfo class. + * + * @author Rick Evans + */ +public final class BeanWiringInfoTests extends TestCase { + + public void testCtorWithNullBeanName() throws Exception { + try { + new BeanWiringInfo(null); + fail("Must have thrown an IllegalArgumentException by this point (null argument)."); + } + catch (IllegalArgumentException ex) { + } + } + + public void testCtorWithWhitespacedBeanName() throws Exception { + try { + new BeanWiringInfo(" \t"); + fail("Must have thrown an IllegalArgumentException by this point (bean name has only whitespace)."); + } + catch (IllegalArgumentException ex) { + } + } + + public void testCtorWithEmptyBeanName() throws Exception { + try { + new BeanWiringInfo(""); + fail("Must have thrown an IllegalArgumentException by this point (bean name is empty)."); + } + catch (IllegalArgumentException ex) { + } + } + + public void testCtorWithNegativeIllegalAutowiringValue() throws Exception { + try { + new BeanWiringInfo(-1, true); + fail("Must have thrown an IllegalArgumentException by this point (out-of-range argument)."); + } + catch (IllegalArgumentException ex) { + } + } + + public void testCtorWithPositiveOutOfRangeAutowiringValue() throws Exception { + try { + new BeanWiringInfo(123871, true); + fail("Must have thrown an IllegalArgumentException by this point (out-of-range argument)."); + } + catch (IllegalArgumentException ex) { + } + } + + public void testUsingAutowireCtorIndicatesAutowiring() throws Exception { + BeanWiringInfo info = new BeanWiringInfo(BeanWiringInfo.AUTOWIRE_BY_NAME, true); + assertTrue(info.indicatesAutowiring()); + } + + public void testUsingBeanNameCtorDoesNotIndicateAutowiring() throws Exception { + BeanWiringInfo info = new BeanWiringInfo("fooService"); + assertFalse(info.indicatesAutowiring()); + } + + public void testNoDependencyCheckValueIsPreserved() throws Exception { + BeanWiringInfo info = new BeanWiringInfo(BeanWiringInfo.AUTOWIRE_BY_NAME, true); + assertTrue(info.getDependencyCheck()); + } + + public void testDependencyCheckValueIsPreserved() throws Exception { + BeanWiringInfo info = new BeanWiringInfo(BeanWiringInfo.AUTOWIRE_BY_TYPE, false); + assertFalse(info.getDependencyCheck()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/ClassNameBeanWiringInfoResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/ClassNameBeanWiringInfoResolverTests.java new file mode 100644 index 00000000000..6bacb2ce70d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/wiring/ClassNameBeanWiringInfoResolverTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.wiring; + +import junit.framework.TestCase; + +/** + * Unit tests for the ClassNameBeanWiringInfoResolver class. + * + * @author Rick Evans + */ +public final class ClassNameBeanWiringInfoResolverTests extends TestCase { + + public void testResolveWiringInfoWithNullBeanInstance() throws Exception { + try { + new ClassNameBeanWiringInfoResolver().resolveWiringInfo(null); + fail("Must have thrown an IllegalArgumentException by this point (null argument)."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testResolveWiringInfo() { + ClassNameBeanWiringInfoResolver resolver = new ClassNameBeanWiringInfoResolver(); + Long beanInstance = new Long(1); + BeanWiringInfo info = resolver.resolveWiringInfo(beanInstance); + assertNotNull(info); + assertEquals("Not resolving bean name to the class name of the supplied bean instance as per class contract.", + beanInstance.getClass().getName(), info.getBeanName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java new file mode 100644 index 00000000000..a376eac4908 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java @@ -0,0 +1,142 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.CountingFactory; +import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AutowireWithExclusionTests extends TestCase { + + public void testByTypeAutowireWithAutoSelfExclusion() throws Exception { + CountingFactory.reset(); + XmlBeanFactory beanFactory = getBeanFactory("autowire-with-exclusion.xml"); + beanFactory.preInstantiateSingletons(); + TestBean rob = (TestBean) beanFactory.getBean("rob"); + TestBean sally = (TestBean) beanFactory.getBean("sally"); + assertEquals(sally, rob.getSpouse()); + assertEquals(1, CountingFactory.getFactoryBeanInstanceCount()); + } + + public void testByTypeAutowireWithExclusion() throws Exception { + CountingFactory.reset(); + XmlBeanFactory beanFactory = getBeanFactory("autowire-with-exclusion.xml"); + beanFactory.preInstantiateSingletons(); + TestBean rob = (TestBean) beanFactory.getBean("rob"); + assertEquals("props1", rob.getSomeProperties().getProperty("name")); + assertEquals(1, CountingFactory.getFactoryBeanInstanceCount()); + } + + public void testByTypeAutowireWithExclusionInParentFactory() throws Exception { + CountingFactory.reset(); + XmlBeanFactory parent = getBeanFactory("autowire-with-exclusion.xml"); + parent.preInstantiateSingletons(); + DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent); + RootBeanDefinition robDef = new RootBeanDefinition(TestBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + robDef.getPropertyValues().addPropertyValue("spouse", new RuntimeBeanReference("sally")); + child.registerBeanDefinition("rob2", robDef); + TestBean rob = (TestBean) child.getBean("rob2"); + assertEquals("props1", rob.getSomeProperties().getProperty("name")); + assertEquals(1, CountingFactory.getFactoryBeanInstanceCount()); + } + + public void testByTypeAutowireWithPrimaryInParentFactory() throws Exception { + CountingFactory.reset(); + XmlBeanFactory parent = getBeanFactory("autowire-with-exclusion.xml"); + ((AbstractBeanDefinition) parent.getBeanDefinition("props1")).setPrimary(true); + parent.preInstantiateSingletons(); + DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent); + RootBeanDefinition robDef = new RootBeanDefinition(TestBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + robDef.getPropertyValues().addPropertyValue("spouse", new RuntimeBeanReference("sally")); + child.registerBeanDefinition("rob2", robDef); + RootBeanDefinition propsDef = new RootBeanDefinition(PropertiesFactoryBean.class); + propsDef.getPropertyValues().addPropertyValue("properties", "name=props3"); + child.registerBeanDefinition("props3", propsDef); + TestBean rob = (TestBean) child.getBean("rob2"); + assertEquals("props1", rob.getSomeProperties().getProperty("name")); + assertEquals(1, CountingFactory.getFactoryBeanInstanceCount()); + } + + public void testByTypeAutowireWithPrimaryOverridingParentFactory() throws Exception { + CountingFactory.reset(); + XmlBeanFactory parent = getBeanFactory("autowire-with-exclusion.xml"); + parent.preInstantiateSingletons(); + DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent); + RootBeanDefinition robDef = new RootBeanDefinition(TestBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE); + robDef.getPropertyValues().addPropertyValue("spouse", new RuntimeBeanReference("sally")); + child.registerBeanDefinition("rob2", robDef); + RootBeanDefinition propsDef = new RootBeanDefinition(PropertiesFactoryBean.class); + propsDef.getPropertyValues().addPropertyValue("properties", "name=props3"); + propsDef.setPrimary(true); + child.registerBeanDefinition("props3", propsDef); + TestBean rob = (TestBean) child.getBean("rob2"); + assertEquals("props3", rob.getSomeProperties().getProperty("name")); + assertEquals(1, CountingFactory.getFactoryBeanInstanceCount()); + } + + public void testByTypeAutowireWithInclusion() throws Exception { + CountingFactory.reset(); + XmlBeanFactory beanFactory = getBeanFactory("autowire-with-inclusion.xml"); + beanFactory.preInstantiateSingletons(); + TestBean rob = (TestBean) beanFactory.getBean("rob"); + assertEquals("props1", rob.getSomeProperties().getProperty("name")); + assertEquals(1, CountingFactory.getFactoryBeanInstanceCount()); + } + + public void testByTypeAutowireWithSelectiveInclusion() throws Exception { + CountingFactory.reset(); + XmlBeanFactory beanFactory = getBeanFactory("autowire-with-selective-inclusion.xml"); + beanFactory.preInstantiateSingletons(); + TestBean rob = (TestBean) beanFactory.getBean("rob"); + assertEquals("props1", rob.getSomeProperties().getProperty("name")); + assertEquals(1, CountingFactory.getFactoryBeanInstanceCount()); + } + + public void testConstructorAutowireWithAutoSelfExclusion() throws Exception { + XmlBeanFactory beanFactory = getBeanFactory("autowire-constructor-with-exclusion.xml"); + TestBean rob = (TestBean) beanFactory.getBean("rob"); + TestBean sally = (TestBean) beanFactory.getBean("sally"); + assertEquals(sally, rob.getSpouse()); + TestBean rob2 = (TestBean) beanFactory.getBean("rob"); + assertEquals(rob, rob2); + assertNotSame(rob, rob2); + assertEquals(rob.getSpouse(), rob2.getSpouse()); + assertNotSame(rob.getSpouse(), rob2.getSpouse()); + } + + public void testConstructorAutowireWithExclusion() throws Exception { + XmlBeanFactory beanFactory = getBeanFactory("autowire-constructor-with-exclusion.xml"); + TestBean rob = (TestBean) beanFactory.getBean("rob"); + assertEquals("props1", rob.getSomeProperties().getProperty("name")); + } + + private XmlBeanFactory getBeanFactory(String configPath) { + return new XmlBeanFactory(new ClassPathResource(configPath, getClass())); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/BeanNameGenerationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/BeanNameGenerationTests.java new file mode 100644 index 00000000000..ba05c516756 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/BeanNameGenerationTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class BeanNameGenerationTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + public void setUp() { + this.beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("beanNameGeneration.xml", getClass())); + } + + public void testNaming() { + String className = GeneratedNameBean.class.getName(); + + String targetName = className + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR + "0"; + GeneratedNameBean topLevel1 = (GeneratedNameBean) beanFactory.getBean(targetName); + assertNotNull(topLevel1); + + targetName = className + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR + "1"; + GeneratedNameBean topLevel2 = (GeneratedNameBean) beanFactory.getBean(targetName); + assertNotNull(topLevel2); + + GeneratedNameBean child1 = topLevel1.getChild(); + assertNotNull(child1.getBeanName()); + assertTrue(child1.getBeanName().startsWith(className)); + + GeneratedNameBean child2 = topLevel2.getChild(); + assertNotNull(child2.getBeanName()); + assertTrue(child2.getBeanName().startsWith(className)); + + assertFalse(child1.getBeanName().equals(child2.getBeanName())); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java new file mode 100644 index 00000000000..42fae8868da --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java @@ -0,0 +1,183 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * Unit and integration tests for the collection merging support. + * + * @author Rob Harrop + * @author Rick Evans + */ +public class CollectionMergingTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new DefaultListableBeanFactory(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.loadBeanDefinitions(new ClassPathResource("collectionMerging.xml", getClass())); + } + + public void testMergeList() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithList"); + List list = bean.getSomeList(); + assertEquals("Incorrect size", 3, list.size()); + assertEquals(list.get(0), "Rob Harrop"); + assertEquals(list.get(1), "Rod Johnson"); + assertEquals(list.get(2), "Juergen Hoeller"); + } + + public void testMergeListWithInnerBeanAsListElement() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithListOfRefs"); + List list = bean.getSomeList(); + assertNotNull(list); + assertEquals(3, list.size()); + assertNotNull(list.get(2)); + assertTrue(list.get(2) instanceof TestBean); + } + + public void testMergeSet() { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithSet"); + Set set = bean.getSomeSet(); + assertEquals("Incorrect size", 2, set.size()); + assertTrue(set.contains("Rob Harrop")); + assertTrue(set.contains("Sally Greenwood")); + } + + public void testMergeSetWithInnerBeanAsSetElement() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithSetOfRefs"); + Set set = bean.getSomeSet(); + assertNotNull(set); + assertEquals(2, set.size()); + Iterator it = set.iterator(); + it.next(); + Object o = it.next(); + assertNotNull(o); + assertTrue(o instanceof TestBean); + assertEquals("Sally", ((TestBean) o).getName()); + } + + public void testMergeMap() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithMap"); + Map map = bean.getSomeMap(); + assertEquals("Incorrect size", 3, map.size()); + assertEquals(map.get("Rob"), "Sally"); + assertEquals(map.get("Rod"), "Kerry"); + assertEquals(map.get("Juergen"), "Eva"); + } + + public void testMergeMapWithInnerBeanAsMapEntryValue() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithMapOfRefs"); + Map map = bean.getSomeMap(); + assertNotNull(map); + assertEquals(2, map.size()); + assertNotNull(map.get("Rob")); + assertTrue(map.get("Rob") instanceof TestBean); + assertEquals("Sally", ((TestBean) map.get("Rob")).getName()); + } + + public void testMergeProperties() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithProps"); + Properties props = bean.getSomeProperties(); + assertEquals("Incorrect size", 3, props.size()); + assertEquals(props.getProperty("Rob"), "Sally"); + assertEquals(props.getProperty("Rod"), "Kerry"); + assertEquals(props.getProperty("Juergen"), "Eva"); + } + + + public void testMergeListInConstructor() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithListInConstructor"); + List list = bean.getSomeList(); + assertEquals("Incorrect size", 3, list.size()); + assertEquals(list.get(0), "Rob Harrop"); + assertEquals(list.get(1), "Rod Johnson"); + assertEquals(list.get(2), "Juergen Hoeller"); + } + + public void testMergeListWithInnerBeanAsListElementInConstructor() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithListOfRefsInConstructor"); + List list = bean.getSomeList(); + assertNotNull(list); + assertEquals(3, list.size()); + assertNotNull(list.get(2)); + assertTrue(list.get(2) instanceof TestBean); + } + + public void testMergeSetInConstructor() { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithSetInConstructor"); + Set set = bean.getSomeSet(); + assertEquals("Incorrect size", 2, set.size()); + assertTrue(set.contains("Rob Harrop")); + assertTrue(set.contains("Sally Greenwood")); + } + + public void testMergeSetWithInnerBeanAsSetElementInConstructor() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithSetOfRefsInConstructor"); + Set set = bean.getSomeSet(); + assertNotNull(set); + assertEquals(2, set.size()); + Iterator it = set.iterator(); + it.next(); + Object o = it.next(); + assertNotNull(o); + assertTrue(o instanceof TestBean); + assertEquals("Sally", ((TestBean) o).getName()); + } + + public void testMergeMapInConstructor() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithMapInConstructor"); + Map map = bean.getSomeMap(); + assertEquals("Incorrect size", 3, map.size()); + assertEquals(map.get("Rob"), "Sally"); + assertEquals(map.get("Rod"), "Kerry"); + assertEquals(map.get("Juergen"), "Eva"); + } + + public void testMergeMapWithInnerBeanAsMapEntryValueInConstructor() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithMapOfRefsInConstructor"); + Map map = bean.getSomeMap(); + assertNotNull(map); + assertEquals(2, map.size()); + assertNotNull(map.get("Rob")); + assertTrue(map.get("Rob") instanceof TestBean); + assertEquals("Sally", ((TestBean) map.get("Rob")).getName()); + } + + public void testMergePropertiesInConstructor() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("childWithPropsInConstructor"); + Properties props = bean.getSomeProperties(); + assertEquals("Incorrect size", 3, props.size()); + assertEquals(props.getProperty("Rob"), "Sally"); + assertEquals(props.getProperty("Rod"), "Kerry"); + assertEquals(props.getProperty("Juergen"), "Eva"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java new file mode 100644 index 00000000000..ae298609c1f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java @@ -0,0 +1,59 @@ +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.TestBean; + +import java.util.List; +import java.util.Set; +import java.util.Iterator; +import java.util.Map; + +/** + * @author Rob Harrop + */ +public class CollectionsWithDefaultTypesTests extends TestCase { + + private XmlBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource("collectionsWithDefaultTypes.xml", getClass())); + } + + public void testListHasDefaultType() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); + List list = bean.getSomeList(); + for (int i = 0; i < list.size(); i++) { + Object o = list.get(i); + assertEquals("Value type is incorrect", Integer.class, o.getClass()); + } + } + + public void testSetHasDefaultType() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); + Set set = bean.getSomeSet(); + Iterator iterator = set.iterator(); + while (iterator.hasNext()) { + Object o = iterator.next(); + assertEquals("Value type is incorrect", Integer.class, o.getClass()); + } + } + + public void testMapHasDefaultKeyAndValueType() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); + assertMap(bean.getSomeMap()); + } + + public void testMapWithNestedElementsHasDefaultKeyAndValueType() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("testBean2"); + assertMap(bean.getSomeMap()); + } + + private void assertMap(Map map) { + for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + assertEquals("Key type is incorrect", Integer.class, entry.getKey().getClass()); + assertEquals("Value type is incorrect", Boolean.class, entry.getValue().getClass()); + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java new file mode 100644 index 00000000000..2d9f4a2b46b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java @@ -0,0 +1,99 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.io.Serializable; + +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.TestBean; + +/** + * Simple bean used to check constructor dependency checking. + * + * @author Juergen Hoeller + * @since 09.11.2003 + */ +public class ConstructorDependenciesBean implements Serializable { + + private int age; + + private String name; + + private TestBean spouse1; + + private TestBean spouse2; + + private IndexedTestBean other; + + public ConstructorDependenciesBean(int age) { + this.age = age; + } + + public ConstructorDependenciesBean(String name) { + this.name = name; + } + + public ConstructorDependenciesBean(TestBean spouse1) { + this.spouse1 = spouse1; + } + + public ConstructorDependenciesBean(TestBean spouse1, TestBean spouse2) { + this.spouse1 = spouse1; + this.spouse2 = spouse2; + } + + public ConstructorDependenciesBean(TestBean spouse1, TestBean spouse2, int age) { + this.spouse1 = spouse1; + this.spouse2 = spouse2; + this.age = age; + } + + public ConstructorDependenciesBean(TestBean spouse1, TestBean spouse2, IndexedTestBean other) { + this.spouse1 = spouse1; + this.spouse2 = spouse2; + this.other = other; + } + + public int getAge() { + return age; + } + + public String getName() { + return name; + } + + public TestBean getSpouse1() { + return spouse1; + } + + public TestBean getSpouse2() { + return spouse2; + } + + public IndexedTestBean getOther() { + return other; + } + + public void setAge(int age) { + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorInjectedOverrides.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorInjectedOverrides.java new file mode 100644 index 00000000000..3bed86420ab --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ConstructorInjectedOverrides.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.ITestBean; + +/** + * Bean testing the ability to use both lookup method overrides + * and constructor injection. + * There is also a property ("setterString") to be set via + * Setter Injection. + * + * @author Rod Johnson + */ +public abstract class ConstructorInjectedOverrides { + + private ITestBean tb; + + private String setterString; + + public ConstructorInjectedOverrides(ITestBean tb) { + this.tb = tb; + } + + public ITestBean getTestBean() { + return this.tb; + } + + + protected abstract FactoryMethods createFactoryMethods(); + + /** + * @return Returns the setterString. + */ + public String getSetterString() { + return setterString; + } + /** + * @param setterString The setterString to set. + */ + public void setSetterString(String setterString) { + this.setterString = setterString; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DefaultLifecycleMethodsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DefaultLifecycleMethodsTests.java new file mode 100644 index 00000000000..8662e52c782 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DefaultLifecycleMethodsTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; + +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + */ +public class DefaultLifecycleMethodsTests extends TestCase { + + private XmlBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource("defaultLifecycleMethods.xml", getClass())); + } + + public void testLifecycleMethodsInvoked() { + LifecycleAwareBean bean = (LifecycleAwareBean) this.beanFactory.getBean("lifecycleAware"); + assertTrue("Bean not initialized", bean.isInitCalled()); + assertFalse("Bean destroyed too early", bean.isDestroyCalled()); + this.beanFactory.destroySingletons(); + assertTrue("Bean not destroyed", bean.isDestroyCalled()); + } + + public void testLifecycleMethodsDisabled() throws Exception { + LifecycleAwareBean bean = (LifecycleAwareBean) this.beanFactory.getBean("lifecycleMethodsDisabled"); + assertFalse("Bean init method called incorrectly", bean.isInitCalled()); + this.beanFactory.destroySingletons(); + assertFalse("Bean destroy method called incorrectly", bean.isDestroyCalled()); + } + + public void testIgnoreDefaultLifecycleMethods() throws Exception { + try { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("ignoreDefaultLifecycleMethods.xml", getClass())); + bf.preInstantiateSingletons(); + bf.destroySingletons(); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Should ignore non-existent default lifecycle methods"); + } + } + + public void testOverrideDefaultLifecycleMethods() throws Exception { + LifecycleAwareBean bean = (LifecycleAwareBean) this.beanFactory.getBean("overrideLifecycleMethods"); + assertFalse("Default init method called incorrectly.", bean.isInitCalled()); + assertTrue("Custom init method not called.", bean.isCustomInitCalled()); + this.beanFactory.destroySingletons(); + assertFalse("Default destory method called incorrectly.", bean.isDestroyCalled()); + assertTrue("Custom destory method not called.", bean.isCustomDestroyCalled()); + } + + + public static class LifecycleAwareBean { + + private boolean initCalled; + + private boolean destroyCalled; + + private boolean customInitCalled; + + private boolean customDestroyCalled; + + public void init() { + this.initCalled = true; + } + + public void destroy() { + this.destroyCalled = true; + } + + public void customInit() { + this.customInitCalled = true; + } + + public void customDestroy() { + this.customDestroyCalled = true; + } + + public boolean isInitCalled() { + return initCalled; + } + + public boolean isDestroyCalled() { + return destroyCalled; + } + + public boolean isCustomInitCalled() { + return customInitCalled; + } + + public boolean isCustomDestroyCalled() { + return customDestroyCalled; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DelegatingEntityResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DelegatingEntityResolverTests.java new file mode 100644 index 00000000000..25c95972987 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DelegatingEntityResolverTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; + +/** + * Unit tests for the {@link DelegatingEntityResolver} class. + * + * @author Rick Evans + */ +public final class DelegatingEntityResolverTests extends TestCase { + + public void testCtorWhereDtdEntityResolverIsNull() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new DelegatingEntityResolver(null, new NoOpEntityResolver()); + } + }.runTest(); + } + + public void testCtorWhereSchemaEntityResolverIsNull() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new DelegatingEntityResolver(new NoOpEntityResolver(), null); + } + }.runTest(); + } + + public void testCtorWhereEntityResolversAreBothNull() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new DelegatingEntityResolver(null, null); + } + }.runTest(); + } + + + private static final class NoOpEntityResolver implements EntityResolver { + + public InputSource resolveEntity(String publicId, String systemId) { + return null; + } + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DependenciesBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DependenciesBean.java new file mode 100644 index 00000000000..0ca614e051f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DependenciesBean.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; + +/** + * Simple bean used to test dependency checking. + * + * @author Rod Johnson + * @since 04.09.2003 + */ +public class DependenciesBean implements BeanFactoryAware { + + private int age; + + private String name; + + private TestBean spouse; + + private BeanFactory beanFactory; + + + public void setAge(int age) { + this.age = age; + } + + public int getAge() { + return age; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setSpouse(TestBean spouse) { + this.spouse = spouse; + } + + public TestBean getSpouse() { + return spouse; + } + + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + public BeanFactory getBeanFactory() { + return beanFactory; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DerivedConstructorDependenciesBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DerivedConstructorDependenciesBean.java new file mode 100644 index 00000000000..50bd0e368ff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DerivedConstructorDependenciesBean.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.TestBean; + +/** + * Simple bean used to check constructor dependency checking. + * + * @author Juergen Hoeller + * @since 09.11.2003 + */ +class DerivedConstructorDependenciesBean extends ConstructorDependenciesBean { + + boolean initialized; + boolean destroyed; + + DerivedConstructorDependenciesBean(TestBean spouse1, TestBean spouse2, IndexedTestBean other) { + super(spouse1, spouse2, other); + } + + private DerivedConstructorDependenciesBean(TestBean spouse1, Object spouse2, IndexedTestBean other) { + super(spouse1, null, other); + } + + protected DerivedConstructorDependenciesBean(TestBean spouse1, TestBean spouse2, IndexedTestBean other, int age, int otherAge) { + super(spouse1, spouse2, other); + } + + public DerivedConstructorDependenciesBean(TestBean spouse1, TestBean spouse2, IndexedTestBean other, int age, String name) { + super(spouse1, spouse2, other); + setAge(age); + setName(name); + } + + private void init() { + this.initialized = true; + } + + private void destroy() { + this.destroyed = true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBo.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBo.java new file mode 100644 index 00000000000..6bb51516e4d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBo.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +/** + * + * @author Rod Johnson + */ +public interface DummyBo { + + void something(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBoImpl.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBoImpl.java new file mode 100644 index 00000000000..a03cb3b9e6c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyBoImpl.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +/** + * + * @author Rod Johnson + */ +public class DummyBoImpl implements DummyBo { + + DummyDao dao; + + public DummyBoImpl(DummyDao dao) { + this.dao = dao; + } + + public void something() { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyDao.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyDao.java new file mode 100644 index 00000000000..d0b3176345f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyDao.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import javax.sql.DataSource; + +/** + * + * @author Rod Johnson + */ +public class DummyDao { + + DataSource ds; + + public DummyDao(DataSource ds) { + this.ds = ds; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java new file mode 100644 index 00000000000..94ff6de94ae --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.DummyFactory; + +/** + * @author Juergen Hoeller + * @since 21.07.2003 + */ +public class DummyReferencer { + + private TestBean testBean1; + + private TestBean testBean2; + + private DummyFactory dummyFactory; + + + public DummyReferencer() { + } + + public DummyReferencer(DummyFactory dummyFactory) { + this.dummyFactory = dummyFactory; + } + + public void setDummyFactory(DummyFactory dummyFactory) { + this.dummyFactory = dummyFactory; + } + + public DummyFactory getDummyFactory() { + return dummyFactory; + } + + public void setTestBean1(TestBean testBean1) { + this.testBean1 = testBean1; + } + + public TestBean getTestBean1() { + return testBean1; + } + + public void setTestBean2(TestBean testBean2) { + this.testBean2 = testBean2; + } + + public TestBean getTestBean2() { + return testBean2; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java new file mode 100644 index 00000000000..b2c34a77578 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.List; + +import junit.framework.TestCase; +import org.w3c.dom.Element; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.parsing.AliasDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CollectingReaderEventListener; +import org.springframework.beans.factory.parsing.ComponentDefinition; +import org.springframework.beans.factory.parsing.ImportDefinition; +import org.springframework.beans.factory.parsing.PassThroughSourceExtractor; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class EventPublicationTests extends TestCase { + + private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + + private final CollectingReaderEventListener eventListener = new CollectingReaderEventListener(); + + + protected void setUp() throws Exception { + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.setEventListener(this.eventListener); + reader.setSourceExtractor(new PassThroughSourceExtractor()); + reader.loadBeanDefinitions(new ClassPathResource("beanEvents.xml", getClass())); + } + + public void testDefaultsEventReceived() throws Exception { + List defaultsList = this.eventListener.getDefaults(); + assertTrue(!defaultsList.isEmpty()); + assertTrue(defaultsList.get(0) instanceof DocumentDefaultsDefinition); + DocumentDefaultsDefinition defaults = (DocumentDefaultsDefinition) defaultsList.get(0); + assertEquals("true", defaults.getLazyInit()); + assertEquals("constructor", defaults.getAutowire()); + assertEquals("objects", defaults.getDependencyCheck()); + assertEquals("myInit", defaults.getInitMethod()); + assertEquals("myDestroy", defaults.getDestroyMethod()); + assertEquals("true", defaults.getMerge()); + assertTrue(defaults.getSource() instanceof Element); + } + + public void testBeanEventReceived() throws Exception { + ComponentDefinition componentDefinition1 = this.eventListener.getComponentDefinition("testBean"); + assertTrue(componentDefinition1 instanceof BeanComponentDefinition); + assertEquals(1, componentDefinition1.getBeanDefinitions().length); + BeanDefinition beanDefinition1 = componentDefinition1.getBeanDefinitions()[0]; + assertEquals(new TypedStringValue("Rob Harrop"), + beanDefinition1.getConstructorArgumentValues().getGenericArgumentValue(String.class).getValue()); + assertEquals(1, componentDefinition1.getBeanReferences().length); + assertEquals("testBean2", componentDefinition1.getBeanReferences()[0].getBeanName()); + assertEquals(1, componentDefinition1.getInnerBeanDefinitions().length); + BeanDefinition innerBd1 = componentDefinition1.getInnerBeanDefinitions()[0]; + assertEquals(new TypedStringValue("ACME"), + innerBd1.getConstructorArgumentValues().getGenericArgumentValue(String.class).getValue()); + assertTrue(componentDefinition1.getSource() instanceof Element); + + ComponentDefinition componentDefinition2 = this.eventListener.getComponentDefinition("testBean2"); + assertTrue(componentDefinition2 instanceof BeanComponentDefinition); + assertEquals(1, componentDefinition1.getBeanDefinitions().length); + BeanDefinition beanDefinition2 = componentDefinition2.getBeanDefinitions()[0]; + assertEquals(new TypedStringValue("Juergen Hoeller"), + beanDefinition2.getPropertyValues().getPropertyValue("name").getValue()); + assertEquals(0, componentDefinition2.getBeanReferences().length); + assertEquals(1, componentDefinition2.getInnerBeanDefinitions().length); + BeanDefinition innerBd2 = componentDefinition2.getInnerBeanDefinitions()[0]; + assertEquals(new TypedStringValue("Eva Schallmeiner"), + innerBd2.getPropertyValues().getPropertyValue("name").getValue()); + assertTrue(componentDefinition2.getSource() instanceof Element); + } + + public void testAliasEventReceived() throws Exception { + List aliases = this.eventListener.getAliases("testBean"); + assertEquals(2, aliases.size()); + AliasDefinition aliasDefinition1 = (AliasDefinition) aliases.get(0); + assertEquals("testBeanAlias1", aliasDefinition1.getAlias()); + assertTrue(aliasDefinition1.getSource() instanceof Element); + AliasDefinition aliasDefinition2 = (AliasDefinition) aliases.get(1); + assertEquals("testBeanAlias2", aliasDefinition2.getAlias()); + assertTrue(aliasDefinition2.getSource() instanceof Element); + } + + public void testImportEventReceived() throws Exception { + List imports = this.eventListener.getImports(); + assertEquals(1, imports.size()); + ImportDefinition importDefinition = (ImportDefinition) imports.get(0); + assertEquals("beanEventsImported.xml", importDefinition.getImportedResource()); + assertTrue(importDefinition.getSource() instanceof Element); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java new file mode 100644 index 00000000000..b9715163f89 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java @@ -0,0 +1,325 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import javax.mail.Session; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + */ +public class FactoryMethodTests extends TestCase { + + public void testFactoryMethodsSingletonOnTargetClass() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + TestBean tb = (TestBean) xbf.getBean("defaultTestBean"); + assertEquals("defaultInstance", tb.getName()); + assertEquals(1, tb.getAge()); + + FactoryMethods fm = (FactoryMethods) xbf.getBean("default"); + assertEquals(0, fm.getNum()); + assertEquals("default", fm.getName()); + assertEquals("defaultInstance", fm.getTestBean().getName()); + assertEquals("setterString", fm.getStringValue()); + + fm = (FactoryMethods) xbf.getBean("testBeanOnly"); + assertEquals(0, fm.getNum()); + assertEquals("default", fm.getName()); + // This comes from the test bean + assertEquals("Juergen", fm.getTestBean().getName()); + + fm = (FactoryMethods) xbf.getBean("full"); + assertEquals(27, fm.getNum()); + assertEquals("gotcha", fm.getName()); + assertEquals("Juergen", fm.getTestBean().getName()); + + FactoryMethods fm2 = (FactoryMethods) xbf.getBean("full"); + assertSame(fm, fm2); + + xbf.destroySingletons(); + assertTrue(tb.wasDestroyed()); + } + + public void testFactoryMethodsWithNullInstance() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + FactoryMethods fm = (FactoryMethods) xbf.getBean("null"); + assertNull(fm); + + try { + xbf.getBean("nullWithProperty"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + } + } + + public void testFactoryMethodsWithNullValue() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + FactoryMethods fm = (FactoryMethods) xbf.getBean("fullWithNull"); + assertEquals(27, fm.getNum()); + assertEquals(null, fm.getName()); + assertEquals("Juergen", fm.getTestBean().getName()); + + fm = (FactoryMethods) xbf.getBean("fullWithGenericNull"); + assertEquals(27, fm.getNum()); + assertEquals(null, fm.getName()); + assertEquals("Juergen", fm.getTestBean().getName()); + } + + public void testFactoryMethodsWithAutowire() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + FactoryMethods fm = (FactoryMethods) xbf.getBean("fullWithAutowire"); + assertEquals(27, fm.getNum()); + assertEquals("gotchaAutowired", fm.getName()); + assertEquals("Juergen", fm.getTestBean().getName()); + } + + public void testProtectedFactoryMethod() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + TestBean tb = (TestBean) xbf.getBean("defaultTestBean.protected"); + assertEquals(1, tb.getAge()); + } + + public void testPrivateFactoryMethod() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + TestBean tb = (TestBean) xbf.getBean("defaultTestBean.private"); + assertEquals(1, tb.getAge()); + } + + public void testFactoryMethodsPrototypeOnTargetClass() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + FactoryMethods fm = (FactoryMethods) xbf.getBean("defaultPrototype"); + FactoryMethods fm2 = (FactoryMethods) xbf.getBean("defaultPrototype"); + assertEquals(0, fm.getNum()); + assertEquals("default", fm.getName()); + assertEquals("defaultInstance", fm.getTestBean().getName()); + assertEquals("setterString", fm.getStringValue()); + assertEquals(fm.getNum(), fm2.getNum()); + assertEquals(fm.getStringValue(), fm2.getStringValue()); + // The TestBean is created separately for each bean + assertNotSame(fm.getTestBean(), fm2.getTestBean()); + assertNotSame(fm, fm2); + + fm = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype"); + fm2 = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype"); + assertEquals(0, fm.getNum()); + assertEquals("default", fm.getName()); + // This comes from the test bean + assertEquals("Juergen", fm.getTestBean().getName()); + assertEquals(fm.getNum(), fm2.getNum()); + assertEquals(fm.getStringValue(), fm2.getStringValue()); + // The TestBean reference is resolved to a prototype in the factory + assertSame(fm.getTestBean(), fm2.getTestBean()); + assertNotSame(fm, fm2); + + fm = (FactoryMethods) xbf.getBean("fullPrototype"); + fm2 = (FactoryMethods) xbf.getBean("fullPrototype"); + assertEquals(27, fm.getNum()); + assertEquals("gotcha", fm.getName()); + assertEquals("Juergen", fm.getTestBean().getName()); + assertEquals(fm.getNum(), fm2.getNum()); + assertEquals(fm.getStringValue(), fm2.getStringValue()); + // The TestBean reference is resolved to a prototype in the factory + assertSame(fm.getTestBean(), fm2.getTestBean()); + assertNotSame(fm, fm2); + } + + /** + * Tests where the static factory method is on a different class. + */ + public void testFactoryMethodsOnExternalClass() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + assertEquals(TestBean.class, xbf.getType("externalFactoryMethodWithoutArgs")); + assertEquals(TestBean.class, xbf.getType("externalFactoryMethodWithArgs")); + String[] names = xbf.getBeanNamesForType(TestBean.class); + assertTrue(Arrays.asList(names).contains("externalFactoryMethodWithoutArgs")); + assertTrue(Arrays.asList(names).contains("externalFactoryMethodWithArgs")); + + TestBean tb = (TestBean) xbf.getBean("externalFactoryMethodWithoutArgs"); + assertEquals(2, tb.getAge()); + assertEquals("Tristan", tb.getName()); + tb = (TestBean) xbf.getBean("externalFactoryMethodWithArgs"); + assertEquals(33, tb.getAge()); + assertEquals("Rod", tb.getName()); + + assertEquals(TestBean.class, xbf.getType("externalFactoryMethodWithoutArgs")); + assertEquals(TestBean.class, xbf.getType("externalFactoryMethodWithArgs")); + names = xbf.getBeanNamesForType(TestBean.class); + assertTrue(Arrays.asList(names).contains("externalFactoryMethodWithoutArgs")); + assertTrue(Arrays.asList(names).contains("externalFactoryMethodWithArgs")); + } + + public void testInstanceFactoryMethodWithoutArgs() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + InstanceFactory.count = 0; + xbf.preInstantiateSingletons(); + assertEquals(1, InstanceFactory.count); + FactoryMethods fm = (FactoryMethods) xbf.getBean("instanceFactoryMethodWithoutArgs"); + assertEquals("instanceFactory", fm.getTestBean().getName()); + assertEquals(1, InstanceFactory.count); + FactoryMethods fm2 = (FactoryMethods) xbf.getBean("instanceFactoryMethodWithoutArgs"); + assertEquals("instanceFactory", fm2.getTestBean().getName()); + assertSame(fm2, fm); + assertEquals(1, InstanceFactory.count); + } + + public void testFactoryMethodNoMatchingStaticMethod() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + try { + xbf.getBean("noMatchPrototype"); + fail("No static method matched"); + } + catch (BeanCreationException ex) { + // Ok + } + } + + public void testCanSpecifyFactoryMethodArgumentsOnFactoryMethodPrototype() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + TestBean tbArg = new TestBean(); + tbArg.setName("arg1"); + TestBean tbArg2 = new TestBean(); + tbArg2.setName("arg2"); + + FactoryMethods fm1 = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype", new Object[] {tbArg}); + assertEquals(0, fm1.getNum()); + assertEquals("default", fm1.getName()); + // This comes from the test bean + assertEquals("arg1", fm1.getTestBean().getName()); + + FactoryMethods fm2 = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype", new Object[] {tbArg2}); + assertEquals("arg2", fm2.getTestBean().getName()); + assertEquals(fm1.getNum(), fm2.getNum()); + assertEquals(fm2.getStringValue(), "testBeanOnlyPrototypeDISetterString"); + assertEquals(fm2.getStringValue(), fm2.getStringValue()); + // The TestBean reference is resolved to a prototype in the factory + assertSame(fm2.getTestBean(), fm2.getTestBean()); + assertNotSame(fm1, fm2); + + FactoryMethods fm3 = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype", new Object[] {tbArg2, new Integer(1), "myName"}); + assertEquals(1, fm3.getNum()); + assertEquals("myName", fm3.getName()); + assertEquals("arg2", fm3.getTestBean().getName()); + + FactoryMethods fm4 = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype", new Object[] {tbArg}); + assertEquals(0, fm4.getNum()); + assertEquals("default", fm4.getName()); + assertEquals("arg1", fm4.getTestBean().getName()); + } + + public void testCannotSpecifyFactoryMethodArgumentsOnSingleton() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + try { + xbf.getBean("testBeanOnly", new Object[] {new TestBean()}); + fail("Shouldn't allow args to be passed to a singleton"); + } + catch (BeanDefinitionStoreException ex) { + // OK + } + } + + public void testCannotSpecifyFactoryMethodArgumentsOnSingletonAfterCreation() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + xbf.getBean("testBeanOnly"); + try { + xbf.getBean("testBeanOnly", new Object[] {new TestBean()}); + fail("Shouldn't allow args to be passed to a singleton"); + } + catch (BeanDefinitionStoreException ex) { + // OK + } + } + + public void testFactoryMethodWithDifferentReturnType() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + // Check that listInstance is not considered a bean of type FactoryMethods. + assertTrue(List.class.isAssignableFrom(xbf.getType("listInstance"))); + String[] names = xbf.getBeanNamesForType(FactoryMethods.class); + assertTrue(!Arrays.asList(names).contains("listInstance")); + names = xbf.getBeanNamesForType(List.class); + assertTrue(Arrays.asList(names).contains("listInstance")); + + xbf.preInstantiateSingletons(); + assertTrue(List.class.isAssignableFrom(xbf.getType("listInstance"))); + names = xbf.getBeanNamesForType(FactoryMethods.class); + assertTrue(!Arrays.asList(names).contains("listInstance")); + names = xbf.getBeanNamesForType(List.class); + assertTrue(Arrays.asList(names).contains("listInstance")); + List list = (List) xbf.getBean("listInstance"); + assertEquals(Collections.EMPTY_LIST, list); + } + + public void testFactoryMethodForJavaMailSession() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); + + Session session = (Session) xbf.getBean("javaMailSession"); + assertEquals("someuser", session.getProperty("mail.smtp.user")); + assertEquals("somepw", session.getProperty("mail.smtp.password")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethods.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethods.java new file mode 100644 index 00000000000..c164d8fae73 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FactoryMethods.java @@ -0,0 +1,120 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.TestBean; + +/** + * Test class for Spring's ability to create objects using static + * factory methods, rather than constructors. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class FactoryMethods { + + public static FactoryMethods nullInstance() { + return null; + } + + public static FactoryMethods defaultInstance() { + TestBean tb = new TestBean(); + tb.setName("defaultInstance"); + return new FactoryMethods(tb, "default", 0); + } + + /** + * Note that overloaded methods are supported. + */ + public static FactoryMethods newInstance(TestBean tb) { + return new FactoryMethods(tb, "default", 0); + } + + protected static FactoryMethods newInstance(TestBean tb, int num, String name) { + if (name == null) { + throw new IllegalStateException("Should never be called with null value"); + } + return new FactoryMethods(tb, name, num); + } + + static FactoryMethods newInstance(TestBean tb, int num, Integer something) { + if (something != null) { + throw new IllegalStateException("Should never be called with non-null value"); + } + return new FactoryMethods(tb, null, num); + } + + private static List listInstance() { + return Collections.EMPTY_LIST; + } + + + private int num = 0; + private String name = "default"; + private TestBean tb; + private String stringValue; + + + /** + * Constructor is private: not for use outside this class, + * even by IoC container. + */ + private FactoryMethods(TestBean tb, String name, int num) { + this.tb = tb; + this.name = name; + this.num = num; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + public String getStringValue() { + return this.stringValue; + } + + public TestBean getTestBean() { + return this.tb; + } + + protected TestBean protectedGetTestBean() { + return this.tb; + } + + private TestBean privateGetTestBean() { + return this.tb; + } + + public int getNum() { + return num; + } + + public String getName() { + return name; + } + + /** + * Set via Setter Injection once instance is created. + */ + public void setName(String name) { + this.name = name; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FixedMethodReplacer.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FixedMethodReplacer.java new file mode 100644 index 00000000000..2ac34def136 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/FixedMethodReplacer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.lang.reflect.Method; + +import org.springframework.beans.factory.support.MethodReplacer; + +/** + * Fixed method replacer for String return types + * @author Rod Johnson + */ +public class FixedMethodReplacer implements MethodReplacer { + + public static final String VALUE = "fixedMethodReplacer"; + + public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { + return VALUE; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/GeneratedNameBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/GeneratedNameBean.java new file mode 100644 index 00000000000..52eb2b2938c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/GeneratedNameBean.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.factory.BeanNameAware; + +/** + * @author Rob Harrop + */ +public class GeneratedNameBean implements BeanNameAware { + + private String beanName; + + private GeneratedNameBean child; + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public String getBeanName() { + return beanName; + } + + public void setChild(GeneratedNameBean child) { + this.child = child; + } + + public GeneratedNameBean getChild() { + return child; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java new file mode 100644 index 00000000000..8a43857fb76 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.TestBean; + +/** + * Test class for Spring's ability to create objects using + * static factory methods, rather than constructors. + * + * @author Rod Johnson + */ +public class InstanceFactory { + + protected static int count = 0; + + private String factoryBeanProperty; + + public InstanceFactory() { + count++; + } + + public void setFactoryBeanProperty(String s) { + this.factoryBeanProperty = s; + } + + public String getFactoryBeanProperty() { + return this.factoryBeanProperty; + } + + public FactoryMethods defaultInstance() { + TestBean tb = new TestBean(); + tb.setName(this.factoryBeanProperty); + return FactoryMethods.newInstance(tb); + } + + /** + * Note that overloaded methods are supported. + */ + public FactoryMethods newInstance(TestBean tb) { + return FactoryMethods.newInstance(tb); + } + + public FactoryMethods newInstance(TestBean tb, int num, String name) { + return FactoryMethods.newInstance(tb, num, name); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/LookupMethodWrappedByCglibProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/LookupMethodWrappedByCglibProxyTests.java new file mode 100644 index 00000000000..0a3c782d92e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/LookupMethodWrappedByCglibProxyTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; + +import org.springframework.aop.interceptor.DebugInterceptor; +import org.springframework.beans.ITestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Tests lookup methods wrapped by a CGLIB proxy (see SPR-391). + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class LookupMethodWrappedByCglibProxyTests extends TestCase { + + private ApplicationContext applicationContext; + + protected void setUp() { + this.applicationContext = new ClassPathXmlApplicationContext("overloadOverrides.xml", getClass()); + resetInterceptor(); + } + + public void testAutoProxiedLookup() { + OverloadLookup olup = (OverloadLookup) applicationContext.getBean("autoProxiedOverload"); + ITestBean jenny = olup.newTestBean(); + assertEquals("Jenny", jenny.getName()); + assertEquals("foo", olup.testMethod()); + assertInterceptorCount(2); + } + + public void testRegularlyProxiedLookup() { + OverloadLookup olup = (OverloadLookup) applicationContext.getBean("regularlyProxiedOverload"); + ITestBean jenny = olup.newTestBean(); + assertEquals("Jenny", jenny.getName()); + assertEquals("foo", olup.testMethod()); + assertInterceptorCount(2); + } + + private void assertInterceptorCount(int count) { + DebugInterceptor interceptor = getInterceptor(); + assertEquals("Interceptor count is incorrect", count, interceptor.getCount()); + } + + private void resetInterceptor() { + DebugInterceptor interceptor = getInterceptor(); + interceptor.resetCount(); + } + + private DebugInterceptor getInterceptor() { + return (DebugInterceptor) applicationContext.getBean("interceptor"); + } + + + public static abstract class OverloadLookup { + + public abstract ITestBean newTestBean(); + + public String testMethod() { + return "foo"; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MetadataAttachmentTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MetadataAttachmentTests.java new file mode 100644 index 00000000000..b943361f1a2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MetadataAttachmentTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; + +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + */ +public class MetadataAttachmentTests extends TestCase { + + private XmlBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new XmlBeanFactory(new ClassPathResource("withMeta.xml", getClass())); + } + + public void testMetadataAttachment() throws Exception { + BeanDefinition beanDefinition1 = this.beanFactory.getMergedBeanDefinition("testBean1"); + assertEquals("bar", beanDefinition1.getAttribute("foo")); + } + + public void testMetadataIsInherited() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("testBean2"); + assertEquals("Metadata not inherited", "bar", beanDefinition.getAttribute("foo")); + assertEquals("Child metdata not attached", "123", beanDefinition.getAttribute("abc")); + } + + public void testPropertyMetadata() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("testBean3"); + PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("name"); + assertEquals("Harrop", pv.getAttribute("surname")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MethodReplaceCandidate.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MethodReplaceCandidate.java new file mode 100644 index 00000000000..bf104819349 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MethodReplaceCandidate.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +/** + * + * @author Rod Johnson + */ +public class MethodReplaceCandidate { + + public String replaceMe(String echo) { + return echo; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MixedCollectionBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MixedCollectionBean.java new file mode 100644 index 00000000000..8ed5f2517ec --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/MixedCollectionBean.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.Collection; + +/** + * Bean that exposes a simple property that can be set + * to a mix of references and individual values. + * + * @author Rod Johnson + * @since 27.05.2003 + */ +public class MixedCollectionBean { + + private Collection jumble; + + + public void setJumble(Collection jumble) { + this.jumble = jumble; + } + + public Collection getJumble() { + return jumble; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideInterface.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideInterface.java new file mode 100644 index 00000000000..4ad5bedd82a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideInterface.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.TestBean; + +/** + * @author Juergen Hoeller + */ +public interface OverrideInterface { + + TestBean getPrototypeDependency(); + + TestBean getPrototypeDependency(Object someParam); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethod.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethod.java new file mode 100644 index 00000000000..6053f68e333 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethod.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.TestBean; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class OverrideOneMethod extends MethodReplaceCandidate implements OverrideInterface { + + protected abstract TestBean protectedOverrideSingleton(); + + public TestBean getPrototypeDependency(Object someParam) { + return new TestBean(); + } + + public TestBean invokesOverridenMethodOnSelf() { + return getPrototypeDependency(); + } + + public String echo(String echo) { + return echo; + } + + /** + * Overloaded form of replaceMe. + */ + public String replaceMe() { + return "replaceMe"; + } + + /** + * Another overloaded form of replaceMe, not getting replaced. + * Must not cause errors when the other replaceMe methods get replaced. + */ + public String replaceMe(int someParam) { + return "replaceMe:" + someParam; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethodSubclass.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethodSubclass.java new file mode 100644 index 00000000000..95da446ed48 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/OverrideOneMethodSubclass.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +/** + * Subclass of OverrideOneMethod, to check that overriding is + * supported for inherited methods. + * + * @author Rod Johnson + */ +public abstract class OverrideOneMethodSubclass extends OverrideOneMethod { + + protected void doSomething(String arg) { + // This implementation does nothing! + // It's not overloaded + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ProtectedLifecycleBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ProtectedLifecycleBean.java new file mode 100644 index 00000000000..7fef9c31533 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ProtectedLifecycleBean.java @@ -0,0 +1,162 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * Simple test of BeanFactory initialization and lifecycle callbacks. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +class ProtectedLifecycleBean implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean { + + protected boolean initMethodDeclared = false; + + protected String beanName; + + protected BeanFactory owningFactory; + + protected boolean postProcessedBeforeInit; + + protected boolean inited; + + protected boolean initedViaDeclaredInitMethod; + + protected boolean postProcessedAfterInit; + + protected boolean destroyed; + + + public void setInitMethodDeclared(boolean initMethodDeclared) { + this.initMethodDeclared = initMethodDeclared; + } + + public boolean isInitMethodDeclared() { + return initMethodDeclared; + } + + public void setBeanName(String name) { + this.beanName = name; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanFactory(BeanFactory beanFactory) { + this.owningFactory = beanFactory; + } + + public void postProcessBeforeInit() { + if (this.inited || this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory called postProcessBeforeInit after afterPropertiesSet"); + } + if (this.postProcessedBeforeInit) { + throw new RuntimeException("Factory called postProcessBeforeInit twice"); + } + this.postProcessedBeforeInit = true; + } + + public void afterPropertiesSet() { + if (this.owningFactory == null) { + throw new RuntimeException("Factory didn't call setBeanFactory before afterPropertiesSet on lifecycle bean"); + } + if (!this.postProcessedBeforeInit) { + throw new RuntimeException("Factory didn't call postProcessBeforeInit before afterPropertiesSet on lifecycle bean"); + } + if (this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory initialized via declared init method before initializing via afterPropertiesSet"); + } + if (this.inited) { + throw new RuntimeException("Factory called afterPropertiesSet twice"); + } + this.inited = true; + } + + public void declaredInitMethod() { + if (!this.inited) { + throw new RuntimeException("Factory didn't call afterPropertiesSet before declared init method"); + } + + if (this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory called declared init method twice"); + } + this.initedViaDeclaredInitMethod = true; + } + + public void postProcessAfterInit() { + if (!this.inited) { + throw new RuntimeException("Factory called postProcessAfterInit before afterPropertiesSet"); + } + if (this.initMethodDeclared && !this.initedViaDeclaredInitMethod) { + throw new RuntimeException("Factory called postProcessAfterInit before calling declared init method"); + } + if (this.postProcessedAfterInit) { + throw new RuntimeException("Factory called postProcessAfterInit twice"); + } + this.postProcessedAfterInit = true; + } + + /** + * Dummy business method that will fail unless the factory + * managed the bean's lifecycle correctly + */ + public void businessMethod() { + if (!this.inited || (this.initMethodDeclared && !this.initedViaDeclaredInitMethod) || + !this.postProcessedAfterInit) { + throw new RuntimeException("Factory didn't initialize lifecycle object correctly"); + } + } + + public void destroy() { + if (this.destroyed) { + throw new IllegalStateException("Already destroyed"); + } + this.destroyed = true; + } + + public boolean isDestroyed() { + return destroyed; + } + + + public static class PostProcessor implements BeanPostProcessor { + + public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException { + if (bean instanceof ProtectedLifecycleBean) { + ((ProtectedLifecycleBean) bean).postProcessBeforeInit(); + } + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String name) throws BeansException { + if (bean instanceof ProtectedLifecycleBean) { + ((ProtectedLifecycleBean) bean).postProcessAfterInit(); + } + return bean; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ReverseMethodReplacer.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ReverseMethodReplacer.java new file mode 100644 index 00000000000..73e364fa267 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ReverseMethodReplacer.java @@ -0,0 +1,23 @@ +/* + * The Spring Framework is published under the terms + * of the Apache Software License. + */ + +package org.springframework.beans.factory.xml; + +import java.io.Serializable; +import java.lang.reflect.Method; + +import org.springframework.beans.factory.support.MethodReplacer; + +/** + * @author Rod Johnson + */ +public class ReverseMethodReplacer implements MethodReplacer, Serializable { + + public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { + String s = (String) args[0]; + return new StringBuffer(s).reverse().toString(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java new file mode 100644 index 00000000000..3679c5a0e3e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; +import org.xml.sax.SAXParseException; + +import org.springframework.beans.BeansException; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + */ +public class SchemaValidationTests extends TestCase { + + public void testWithAutodetection() throws Exception { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + try { + reader.loadBeanDefinitions(new ClassPathResource("invalidPerSchema.xml", getClass())); + fail("Should not be able to parse a file with errors"); + } + catch (BeansException ex) { + assertTrue(ex.getCause() instanceof SAXParseException); + } + } + + public void testWithExplicitValidationMode() throws Exception { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD); + try { + reader.loadBeanDefinitions(new ClassPathResource("invalidPerSchema.xml", getClass())); + fail("Should not be able to parse a file with errors"); + } + catch (BeansException ex) { + assertTrue(ex.getCause() instanceof SAXParseException); + } + } + + public void testLoadDefinitions() throws Exception { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD); + reader.loadBeanDefinitions(new ClassPathResource("schemaValidated.xml", getClass())); + + TestBean foo = (TestBean) bf.getBean("fooBean"); + assertNotNull("Spouse is null", foo.getSpouse()); + assertEquals("Incorrect number of friends", 2, foo.getFriends().size()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SerializableMethodReplacerCandidate.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SerializableMethodReplacerCandidate.java new file mode 100644 index 00000000000..33150572012 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SerializableMethodReplacerCandidate.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.io.Serializable; + +/** + * @author Rod Johnson + */ +public abstract class SerializableMethodReplacerCandidate extends MethodReplaceCandidate implements Serializable { + + //public abstract Point getPoint(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ShortcutTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ShortcutTests.java new file mode 100644 index 00000000000..389e468b0ca --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ShortcutTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class ShortcutTests extends TestCase { + + public void testSimpleBeanConfigured() throws Exception { + XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("shortcutTests.xml", getClass())); + ITestBean rob = (TestBean) beanFactory.getBean("rob"); + ITestBean sally = (TestBean) beanFactory.getBean("sally"); + assertEquals("Rob Harrop", rob.getName()); + assertEquals(24, rob.getAge()); + assertEquals(rob.getSpouse(), sally); + } + + public void testInnerBeanConfigured() throws Exception { + XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("shortcutTests.xml", getClass())); + TestBean sally = (TestBean) beanFactory.getBean("sally2"); + ITestBean rob = (TestBean) sally.getSpouse(); + assertEquals("Rob Harrop", rob.getName()); + assertEquals(24, rob.getAge()); + assertEquals(rob.getSpouse(), sally); + } + + public void testWithPropertyDefinedTwice() throws Exception { + try { + new XmlBeanFactory(new ClassPathResource("shortcutTestsWithErrors.xml", getClass())); + fail("Should not be able to load a file with property specified twice."); + } + catch (BeanDefinitionStoreException e) { + // success + } + } + + public void testPropertyWithNameEndingInRef() throws Exception { + XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("shortcutTests.xml", getClass())); + ITestBean sally = (TestBean) beanFactory.getBean("derivedSally"); + assertEquals("r", sally.getSpouse().getName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SingleSimpleTypeConstructorBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SingleSimpleTypeConstructorBean.java new file mode 100644 index 00000000000..50ca3486480 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/SingleSimpleTypeConstructorBean.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +/** + * @author Juergen Hoeller + * @since 23.10.2004 + */ +public class SingleSimpleTypeConstructorBean { + + private boolean singleBoolean; + + private boolean secondBoolean; + + private String testString; + + public SingleSimpleTypeConstructorBean(boolean singleBoolean) { + this.singleBoolean = singleBoolean; + } + + public SingleSimpleTypeConstructorBean(String testString, boolean secondBoolean) { + this.testString = testString; + this.secondBoolean = secondBoolean; + } + + public boolean isSingleBoolean() { + return singleBoolean; + } + + public boolean isSecondBoolean() { + return secondBoolean; + } + + public String getTestString() { + return testString; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java new file mode 100644 index 00000000000..8658bc5a12a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import org.springframework.beans.TestBean; + +/** + * Test class for Spring's ability to create + * objects using static factory methods, rather + * than constructors. + * @author Rod Johnson + */ +public class TestBeanCreator { + + public static TestBean createTestBean(String name, int age) { + TestBean tb = new TestBean(); + tb.setName(name); + tb.setAge(age); + return tb; + } + + public static TestBean createTestBean() { + TestBean tb = new TestBean(); + tb.setName("Tristan"); + tb.setAge(2); + return tb; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java new file mode 100644 index 00000000000..31398eb9d96 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java @@ -0,0 +1,310 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.parsing.CollectingReaderEventListener; +import org.springframework.beans.factory.parsing.ComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.beans.factory.config.FieldRetrievingFactoryBean; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class UtilNamespaceHandlerTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + private CollectingReaderEventListener listener = new CollectingReaderEventListener(); + + public void setUp() { + this.beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.setEventListener(this.listener); + reader.loadBeanDefinitions(new ClassPathResource("testUtilNamespace.xml", getClass())); + } + + public void testConstant() throws Exception { + Integer min = (Integer) this.beanFactory.getBean("min"); + assertEquals(Integer.MIN_VALUE, min.intValue()); + } + + public void testConstantWithDefaultName() throws Exception { + Integer max = (Integer) this.beanFactory.getBean("java.lang.Integer.MAX_VALUE"); + assertEquals(Integer.MAX_VALUE, max.intValue()); + } + + public void testEvents() throws Exception { + ComponentDefinition propertiesComponent = this.listener.getComponentDefinition("myProperties"); + assertNotNull("Event for 'myProperties' not sent", propertiesComponent); + AbstractBeanDefinition propertiesBean = (AbstractBeanDefinition) propertiesComponent.getBeanDefinitions()[0]; + assertEquals("Incorrect BeanDefinition", PropertiesFactoryBean.class, propertiesBean.getBeanClass()); + + ComponentDefinition constantComponent = this.listener.getComponentDefinition("min"); + assertNotNull("Event for 'min' not sent", propertiesComponent); + AbstractBeanDefinition constantBean = (AbstractBeanDefinition) constantComponent.getBeanDefinitions()[0]; + assertEquals("Incorrect BeanDefinition", FieldRetrievingFactoryBean.class, constantBean.getBeanClass()); + } + + public void testNestedProperties() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); + Properties props = bean.getSomeProperties(); + assertEquals("Incorrect property value", "bar", props.get("foo")); + } + + public void testPropertyPath() throws Exception { + String name = (String) this.beanFactory.getBean("name"); + assertEquals("Rob Harrop", name); + } + + public void testNestedPropertyPath() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); + assertEquals("Rob Harrop", bean.getName()); + } + + public void testSimpleMap() throws Exception { + Map map = (Map) this.beanFactory.getBean("simpleMap"); + assertEquals("bar", map.get("foo")); + Map map2 = (Map) this.beanFactory.getBean("simpleMap"); + assertTrue(map == map2); + } + + public void testScopedMap() throws Exception { + Map map = (Map) this.beanFactory.getBean("scopedMap"); + assertEquals("bar", map.get("foo")); + Map map2 = (Map) this.beanFactory.getBean("scopedMap"); + assertEquals("bar", map2.get("foo")); + assertTrue(map != map2); + } + + public void testSimpleList() throws Exception { + List list = (List) this.beanFactory.getBean("simpleList"); + assertEquals("Rob Harrop", list.get(0)); + List list2 = (List) this.beanFactory.getBean("simpleList"); + assertTrue(list == list2); + } + + public void testScopedList() throws Exception { + List list = (List) this.beanFactory.getBean("scopedList"); + assertEquals("Rob Harrop", list.get(0)); + List list2 = (List) this.beanFactory.getBean("scopedList"); + assertEquals("Rob Harrop", list2.get(0)); + assertTrue(list != list2); + } + + public void testSimpleSet() throws Exception { + Set set = (Set) this.beanFactory.getBean("simpleSet"); + assertTrue(set.contains("Rob Harrop")); + Set set2 = (Set) this.beanFactory.getBean("simpleSet"); + assertTrue(set == set2); + } + + public void testScopedSet() throws Exception { + Set set = (Set) this.beanFactory.getBean("scopedSet"); + assertTrue(set.contains("Rob Harrop")); + Set set2 = (Set) this.beanFactory.getBean("scopedSet"); + assertTrue(set2.contains("Rob Harrop")); + assertTrue(set != set2); + } + + public void testMapWithRef() throws Exception { + Map map = (Map) this.beanFactory.getBean("mapWithRef"); + assertTrue(map instanceof TreeMap); + assertEquals(this.beanFactory.getBean("testBean"), map.get("bean")); + } + + public void testNestedCollections() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("nestedCollectionsBean"); + + List list = bean.getSomeList(); + assertEquals(1, list.size()); + assertEquals("foo", list.get(0)); + + Set set = bean.getSomeSet(); + assertEquals(1, set.size()); + assertTrue(set.contains("bar")); + + Map map = bean.getSomeMap(); + assertEquals(1, map.size()); + assertTrue(map.get("foo") instanceof Set); + Set innerSet = (Set) map.get("foo"); + assertEquals(1, innerSet.size()); + assertTrue(innerSet.contains("bar")); + } + + public void testNestedInCollections() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("nestedCustomTagBean"); + Integer min = new Integer(Integer.MIN_VALUE); + + List list = bean.getSomeList(); + assertEquals(1, list.size()); + assertEquals(min, list.get(0)); + + Set set = bean.getSomeSet(); + assertEquals(1, set.size()); + assertTrue(set.contains(min)); + + Map map = bean.getSomeMap(); + assertEquals(1, map.size()); + assertEquals(min, map.get("min")); + } + + public void testCircularCollections() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionsBean"); + + List list = bean.getSomeList(); + assertEquals(1, list.size()); + assertEquals(bean, list.get(0)); + + Set set = bean.getSomeSet(); + assertEquals(1, set.size()); + assertTrue(set.contains(bean)); + + Map map = bean.getSomeMap(); + assertEquals(1, map.size()); + assertEquals(bean, map.get("foo")); + } + + public void testCircularCollectionBeansStartingWithList() throws Exception { + this.beanFactory.getBean("circularList"); + TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean"); + + List list = bean.getSomeList(); + assertTrue(Proxy.isProxyClass(list.getClass())); + assertEquals(1, list.size()); + assertEquals(bean, list.get(0)); + + Set set = bean.getSomeSet(); + assertFalse(Proxy.isProxyClass(set.getClass())); + assertEquals(1, set.size()); + assertTrue(set.contains(bean)); + + Map map = bean.getSomeMap(); + assertFalse(Proxy.isProxyClass(map.getClass())); + assertEquals(1, map.size()); + assertEquals(bean, map.get("foo")); + } + + public void testCircularCollectionBeansStartingWithSet() throws Exception { + this.beanFactory.getBean("circularSet"); + TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean"); + + List list = bean.getSomeList(); + assertFalse(Proxy.isProxyClass(list.getClass())); + assertEquals(1, list.size()); + assertEquals(bean, list.get(0)); + + Set set = bean.getSomeSet(); + assertTrue(Proxy.isProxyClass(set.getClass())); + assertEquals(1, set.size()); + assertTrue(set.contains(bean)); + + Map map = bean.getSomeMap(); + assertFalse(Proxy.isProxyClass(map.getClass())); + assertEquals(1, map.size()); + assertEquals(bean, map.get("foo")); + } + + public void testCircularCollectionBeansStartingWithMap() throws Exception { + this.beanFactory.getBean("circularMap"); + TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean"); + + List list = bean.getSomeList(); + assertFalse(Proxy.isProxyClass(list.getClass())); + assertEquals(1, list.size()); + assertEquals(bean, list.get(0)); + + Set set = bean.getSomeSet(); + assertFalse(Proxy.isProxyClass(set.getClass())); + assertEquals(1, set.size()); + assertTrue(set.contains(bean)); + + Map map = bean.getSomeMap(); + assertTrue(Proxy.isProxyClass(map.getClass())); + assertEquals(1, map.size()); + assertEquals(bean, map.get("foo")); + } + + public void testNestedInConstructor() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("constructedTestBean"); + assertEquals("Rob Harrop", bean.getName()); + } + + public void testLoadProperties() throws Exception { + Properties props = (Properties) this.beanFactory.getBean("myProperties"); + assertEquals("Incorrect property value", "bar", props.get("foo")); + assertEquals("Incorrect property value", null, props.get("foo2")); + Properties props2 = (Properties) this.beanFactory.getBean("myProperties"); + assertTrue(props == props2); + } + + public void testScopedProperties() throws Exception { + Properties props = (Properties) this.beanFactory.getBean("myScopedProperties"); + assertEquals("Incorrect property value", "bar", props.get("foo")); + assertEquals("Incorrect property value", null, props.get("foo2")); + Properties props2 = (Properties) this.beanFactory.getBean("myScopedProperties"); + assertEquals("Incorrect property value", "bar", props.get("foo")); + assertEquals("Incorrect property value", null, props.get("foo2")); + assertTrue(props != props2); + } + + public void testLocalProperties() throws Exception { + Properties props = (Properties) this.beanFactory.getBean("myLocalProperties"); + assertEquals("Incorrect property value", null, props.get("foo")); + assertEquals("Incorrect property value", "bar2", props.get("foo2")); + } + + public void testMergedProperties() throws Exception { + Properties props = (Properties) this.beanFactory.getBean("myMergedProperties"); + assertEquals("Incorrect property value", "bar", props.get("foo")); + assertEquals("Incorrect property value", "bar2", props.get("foo2")); + } + + public void testLocalOverrideDefault() { + Properties props = (Properties) this.beanFactory.getBean("defaultLocalOverrideProperties"); + assertEquals("Incorrect property value", "bar", props.get("foo")); + assertEquals("Incorrect property value", "local2", props.get("foo2")); + } + + public void testLocalOverrideFalse() { + Properties props = (Properties) this.beanFactory.getBean("falseLocalOverrideProperties"); + assertEquals("Incorrect property value", "bar", props.get("foo")); + assertEquals("Incorrect property value", "local2", props.get("foo2")); + } + + public void testLocalOverrideTrue() { + Properties props = (Properties) this.beanFactory.getBean("trueLocalOverrideProperties"); + assertEquals("Incorrect property value", "local", props.get("foo")); + assertEquals("Incorrect property value", "local2", props.get("foo2")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java new file mode 100644 index 00000000000..358b07eb9e3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java @@ -0,0 +1,413 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import junit.framework.TestCase; +import org.hibernate.FlushMode; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.HasMap; +import org.springframework.beans.factory.config.ListFactoryBean; +import org.springframework.beans.factory.config.MapFactoryBean; +import org.springframework.beans.factory.config.SetFactoryBean; +import org.springframework.core.io.ClassPathResource; + +/** + * Tests for collections in XML bean definitions. + * + * @author Juergen Hoeller + * @since 19.12.2004 + */ +public class XmlBeanCollectionTests extends TestCase { + + public void testCollectionFactoryDefaults() throws Exception { + ListFactoryBean listFactory = new ListFactoryBean(); + listFactory.setSourceList(new LinkedList()); + listFactory.afterPropertiesSet(); + assertTrue(listFactory.getObject() instanceof ArrayList); + + SetFactoryBean setFactory = new SetFactoryBean(); + setFactory.setSourceSet(new TreeSet()); + setFactory.afterPropertiesSet(); + assertTrue(setFactory.getObject() instanceof LinkedHashSet); + + MapFactoryBean mapFactory = new MapFactoryBean(); + mapFactory.setSourceMap(new TreeMap()); + mapFactory.afterPropertiesSet(); + assertTrue(mapFactory.getObject() instanceof LinkedHashMap); + } + + public void testRefSubelement() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + //assertTrue("5 beans in reftypes, not " + xbf.getBeanDefinitionCount(), xbf.getBeanDefinitionCount() == 5); + TestBean jen = (TestBean) xbf.getBean("jenny"); + TestBean dave = (TestBean) xbf.getBean("david"); + assertTrue(jen.getSpouse() == dave); + } + + public void testPropertyWithLiteralValueSubelement() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + TestBean verbose = (TestBean) xbf.getBean("verbose"); + assertTrue(verbose.getName().equals("verbose")); + } + + public void testPropertyWithIdRefLocalAttrSubelement() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + TestBean verbose = (TestBean) xbf.getBean("verbose2"); + assertTrue(verbose.getName().equals("verbose")); + } + + public void testPropertyWithIdRefBeanAttrSubelement() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + TestBean verbose = (TestBean) xbf.getBean("verbose3"); + assertTrue(verbose.getName().equals("verbose")); + } + + public void testRefSubelementsBuildCollection() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + TestBean jen = (TestBean) xbf.getBean("jenny"); + TestBean dave = (TestBean) xbf.getBean("david"); + TestBean rod = (TestBean) xbf.getBean("rod"); + + // Must be a list to support ordering + // Our bean doesn't modify the collection: + // of course it could be a different copy in a real object. + Object[] friends = rod.getFriends().toArray(); + assertTrue(friends.length == 2); + + assertTrue("First friend must be jen, not " + friends[0], friends[0] == jen); + assertTrue(friends[1] == dave); + // Should be ordered + } + + public void testRefSubelementsBuildCollectionWithPrototypes() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + + TestBean jen = (TestBean) xbf.getBean("pJenny"); + TestBean dave = (TestBean) xbf.getBean("pDavid"); + TestBean rod = (TestBean) xbf.getBean("pRod"); + Object[] friends = rod.getFriends().toArray(); + assertTrue(friends.length == 2); + assertTrue("First friend must be jen, not " + friends[0], + friends[0].toString().equals(jen.toString())); + assertTrue("Jen not same instance", friends[0] != jen); + assertTrue(friends[1].toString().equals(dave.toString())); + assertTrue("Dave not same instance", friends[1] != dave); + + TestBean rod2 = (TestBean) xbf.getBean("pRod"); + Object[] friends2 = rod2.getFriends().toArray(); + assertTrue(friends2.length == 2); + assertTrue("First friend must be jen, not " + friends2[0], + friends2[0].toString().equals(jen.toString())); + assertTrue("Jen not same instance", friends2[0] != friends[0]); + assertTrue(friends2[1].toString().equals(dave.toString())); + assertTrue("Dave not same instance", friends2[1] != friends[1]); + } + + public void testRefSubelementsBuildCollectionFromSingleElement() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + TestBean loner = (TestBean) xbf.getBean("loner"); + TestBean dave = (TestBean) xbf.getBean("david"); + assertTrue(loner.getFriends().size() == 1); + assertTrue(loner.getFriends().contains(dave)); + } + + public void testBuildCollectionFromMixtureOfReferencesAndValues() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + MixedCollectionBean jumble = (MixedCollectionBean) xbf.getBean("jumble"); + assertTrue("Expected 4 elements, not " + jumble.getJumble().size(), + jumble.getJumble().size() == 4); + List l = (List) jumble.getJumble(); + assertTrue(l.get(0).equals(xbf.getBean("david"))); + assertTrue(l.get(1).equals("literal")); + assertTrue(l.get(2).equals(xbf.getBean("jenny"))); + assertTrue(l.get(3).equals("rod")); + } + + public void testInvalidBeanNameReference() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + try { + xbf.getBean("jumble2"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getCause() instanceof BeanDefinitionStoreException); + assertTrue(ex.getCause().getMessage().indexOf("rod2") != -1); + } + } + + public void testEmptyMap() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("emptyMap"); + assertTrue(hasMap.getMap().size() == 0); + } + + public void testMapWithLiteralsOnly() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("literalMap"); + assertTrue(hasMap.getMap().size() == 3); + assertTrue(hasMap.getMap().get("foo").equals("bar")); + assertTrue(hasMap.getMap().get("fi").equals("fum")); + assertTrue(hasMap.getMap().get("fa") == null); + } + + public void testMapWithLiteralsAndReferences() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("mixedMap"); + assertTrue(hasMap.getMap().size() == 3); + assertTrue(hasMap.getMap().get("foo").equals(new Integer(10))); + TestBean jenny = (TestBean) xbf.getBean("jenny"); + assertTrue(hasMap.getMap().get("jenny") == jenny); + assertTrue(hasMap.getMap().get(new Integer(5)).equals("david")); + } + + public void testMapWithLiteralsAndPrototypeReferences() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + + TestBean jenny = (TestBean) xbf.getBean("pJenny"); + HasMap hasMap = (HasMap) xbf.getBean("pMixedMap"); + assertTrue(hasMap.getMap().size() == 2); + assertTrue(hasMap.getMap().get("foo").equals("bar")); + assertTrue(hasMap.getMap().get("jenny").toString().equals(jenny.toString())); + assertTrue("Not same instance", hasMap.getMap().get("jenny") != jenny); + + HasMap hasMap2 = (HasMap) xbf.getBean("pMixedMap"); + assertTrue(hasMap2.getMap().size() == 2); + assertTrue(hasMap2.getMap().get("foo").equals("bar")); + assertTrue(hasMap2.getMap().get("jenny").toString().equals(jenny.toString())); + assertTrue("Not same instance", hasMap2.getMap().get("jenny") != hasMap.getMap().get("jenny")); + } + + public void testMapWithLiteralsReferencesAndList() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("mixedMapWithList"); + assertTrue(hasMap.getMap().size() == 4); + assertTrue(hasMap.getMap().get(null).equals("bar")); + TestBean jenny = (TestBean) xbf.getBean("jenny"); + assertTrue(hasMap.getMap().get("jenny").equals(jenny)); + + // Check list + List l = (List) hasMap.getMap().get("list"); + assertNotNull(l); + assertTrue(l.size() == 4); + assertTrue(l.get(0).equals("zero")); + assertTrue(l.get(3) == null); + + // Check nested map in list + Map m = (Map) l.get(1); + assertNotNull(m); + assertTrue(m.size() == 2); + assertTrue(m.get("fo").equals("bar")); + assertTrue("Map element 'jenny' should be equal to jenny bean, not " + m.get("jen"), + m.get("jen").equals(jenny)); + + // Check nested list in list + l = (List) l.get(2); + assertNotNull(l); + assertTrue(l.size() == 2); + assertTrue(l.get(0).equals(jenny)); + assertTrue(l.get(1).equals("ba")); + + // Check nested map + m = (Map) hasMap.getMap().get("map"); + assertNotNull(m); + assertTrue(m.size() == 2); + assertTrue(m.get("foo").equals("bar")); + assertTrue("Map element 'jenny' should be equal to jenny bean, not " + m.get("jenny"), + m.get("jenny").equals(jenny)); + } + + public void testEmptySet() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("emptySet"); + assertTrue(hasMap.getSet().size() == 0); + } + + public void testPopulatedSet() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("set"); + assertTrue(hasMap.getSet().size() == 3); + assertTrue(hasMap.getSet().contains("bar")); + TestBean jenny = (TestBean) xbf.getBean("jenny"); + assertTrue(hasMap.getSet().contains(jenny)); + assertTrue(hasMap.getSet().contains(null)); + Iterator it = hasMap.getSet().iterator(); + assertEquals("bar", it.next()); + assertEquals(jenny, it.next()); + assertEquals(null, it.next()); + } + + public void testEmptyProps() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("emptyProps"); + assertTrue(hasMap.getProps().size() == 0); + assertEquals(hasMap.getProps().getClass(), Properties.class); + } + + public void testPopulatedProps() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("props"); + assertTrue(hasMap.getProps().size() == 2); + assertTrue(hasMap.getProps().get("foo").equals("bar")); + assertTrue(hasMap.getProps().get("2").equals("TWO")); + } + + public void testObjectArray() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("objectArray"); + assertTrue(hasMap.getObjectArray().length == 2); + assertTrue(hasMap.getObjectArray()[0].equals("one")); + assertTrue(hasMap.getObjectArray()[1].equals(xbf.getBean("jenny"))); + } + + public void testClassArray() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("classArray"); + assertTrue(hasMap.getClassArray().length == 2); + assertTrue(hasMap.getClassArray()[0].equals(String.class)); + assertTrue(hasMap.getClassArray()[1].equals(Exception.class)); + } + + public void testIntegerArray() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + HasMap hasMap = (HasMap) xbf.getBean("integerArray"); + assertTrue(hasMap.getIntegerArray().length == 3); + assertTrue(hasMap.getIntegerArray()[0].intValue() == 0); + assertTrue(hasMap.getIntegerArray()[1].intValue() == 1); + assertTrue(hasMap.getIntegerArray()[2].intValue() == 2); + } + + public void testProps() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + + HasMap hasMap = (HasMap) xbf.getBean("props"); + assertEquals(2, hasMap.getProps().size()); + assertEquals("bar", hasMap.getProps().getProperty("foo")); + assertEquals("TWO", hasMap.getProps().getProperty("2")); + + HasMap hasMap2 = (HasMap) xbf.getBean("propsViaMap"); + assertEquals(2, hasMap2.getProps().size()); + assertEquals("bar", hasMap2.getProps().getProperty("foo")); + assertEquals("TWO", hasMap2.getProps().getProperty("2")); + } + + public void testListFactory() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + List list = (List) xbf.getBean("listFactory"); + assertTrue(list instanceof LinkedList); + assertTrue(list.size() == 2); + assertEquals("bar", list.get(0)); + assertEquals("jenny", list.get(1)); + } + + public void testPrototypeListFactory() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + List list = (List) xbf.getBean("pListFactory"); + assertTrue(list instanceof LinkedList); + assertTrue(list.size() == 2); + assertEquals("bar", list.get(0)); + assertEquals("jenny", list.get(1)); + } + + public void testSetFactory() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + Set set = (Set) xbf.getBean("setFactory"); + assertTrue(set instanceof TreeSet); + assertTrue(set.size() == 2); + assertTrue(set.contains("bar")); + assertTrue(set.contains("jenny")); + } + + public void testPrototypeSetFactory() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + Set set = (Set) xbf.getBean("pSetFactory"); + assertTrue(set instanceof TreeSet); + assertTrue(set.size() == 2); + assertTrue(set.contains("bar")); + assertTrue(set.contains("jenny")); + } + + public void testMapFactory() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + Map map = (Map) xbf.getBean("mapFactory"); + assertTrue(map instanceof TreeMap); + assertTrue(map.size() == 2); + assertEquals("bar", map.get("foo")); + assertEquals("jenny", map.get("jen")); + } + + public void testPrototypeMapFactory() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + Map map = (Map) xbf.getBean("pMapFactory"); + assertTrue(map instanceof TreeMap); + assertTrue(map.size() == 2); + assertEquals("bar", map.get("foo")); + assertEquals("jenny", map.get("jen")); + } + + public void testChoiceBetweenSetAndMap() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + MapAndSet sam = (MapAndSet) xbf.getBean("setAndMap"); + assertTrue("Didn't choose constructor with Map argument", sam.getObject() instanceof Map); + Map map = (Map) sam.getObject(); + assertEquals(3, map.size()); + assertEquals("val1", map.get("key1")); + assertEquals("val2", map.get("key2")); + assertEquals("val3", map.get("key3")); + } + + public void testEnumSetFactory() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("collections.xml", getClass())); + Set set = (Set) xbf.getBean("enumSetFactory"); + assertTrue(set.size() == 2); + assertTrue(set.contains(FlushMode.NEVER)); + assertTrue(set.contains(FlushMode.COMMIT)); + } + + + public static class MapAndSet { + + private Object obj; + + public MapAndSet(Map map) { + this.obj = map; + } + + public MapAndSet(Set set) { + this.obj = set; + } + + public Object getObject() { + return obj; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java new file mode 100644 index 00000000000..efeab901716 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java @@ -0,0 +1,142 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.Arrays; + +import junit.framework.TestCase; +import org.xml.sax.InputSource; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class XmlBeanDefinitionReaderTests extends TestCase { + + public void testSetParserClassSunnyDay() { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + new XmlBeanDefinitionReader(registry).setDocumentReaderClass(DefaultBeanDefinitionDocumentReader.class); + } + + public void testSetParserClassToNull() { + try { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + new XmlBeanDefinitionReader(registry).setDocumentReaderClass(null); + fail("Should have thrown IllegalArgumentException (null parserClass)"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testSetParserClassToUnsupportedParserType() throws Exception { + try { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + new XmlBeanDefinitionReader(registry).setDocumentReaderClass(String.class); + fail("Should have thrown IllegalArgumentException (unsupported parserClass)"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testWithOpenInputStream() { + try { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml")); + new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource); + fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)"); + } + catch (BeanDefinitionStoreException expected) { + } + } + + public void testWithOpenInputStreamAndExplicitValidationMode() { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml")); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD); + reader.loadBeanDefinitions(resource); + testBeanDefinitions(registry); + } + + public void testWithInputSource() { + try { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml")); + new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource); + fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)"); + } + catch (BeanDefinitionStoreException expected) { + } + } + + public void testWithInputSourceAndExplicitValidationMode() { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml")); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD); + reader.loadBeanDefinitions(resource); + testBeanDefinitions(registry); + } + + public void testWithFreshInputStream() { + SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();; + Resource resource = new ClassPathResource("test.xml", getClass()); + new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource); + testBeanDefinitions(registry); + } + + private void testBeanDefinitions(BeanDefinitionRegistry registry) { + assertEquals(24, registry.getBeanDefinitionCount()); + assertEquals(24, registry.getBeanDefinitionNames().length); + assertTrue(Arrays.asList(registry.getBeanDefinitionNames()).contains("rod")); + assertTrue(Arrays.asList(registry.getBeanDefinitionNames()).contains("aliased")); + assertTrue(registry.containsBeanDefinition("rod")); + assertTrue(registry.containsBeanDefinition("aliased")); + assertEquals(TestBean.class.getName(), registry.getBeanDefinition("rod").getBeanClassName()); + assertEquals(TestBean.class.getName(), registry.getBeanDefinition("aliased").getBeanClassName()); + assertTrue(registry.isAlias("youralias")); + assertEquals(2, registry.getAliases("aliased").length); + assertEquals("myalias", registry.getAliases("aliased")[0]); + assertEquals("youralias", registry.getAliases("aliased")[1]); + } + + public void testDtdValidationAutodetect() throws Exception { + doTestValidation("validateWithDtd.xml"); + } + + public void testXsdValidationAutodetect() throws Exception { + doTestValidation("validateWithXsd.xml"); + } + + private void doTestValidation(String resourceName) throws Exception { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory();; + Resource resource = new ClassPathResource(resourceName, getClass()); + new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource); + TestBean bean = (TestBean) factory.getBean("testBean"); + assertNotNull(bean); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java new file mode 100644 index 00000000000..359c8526cc3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java @@ -0,0 +1,1549 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.Map; + +import javax.servlet.ServletException; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.InputSource; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.ITestBean; +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.ResourceTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanCurrentlyInCreationException; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanIsAbstractException; +import org.springframework.beans.factory.CannotLoadBeanClassException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.DummyFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.MethodReplacer; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.SerializationTestUtils; +import org.springframework.util.StopWatch; + +/** + * Miscellaneous tests for XML bean definitions. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @author Rick Evans + */ +public class XmlBeanFactoryTests extends TestCase { + + /* + * http://opensource.atlassian.com/projects/spring/browse/SPR-2368 + */ + public void testCollectionsReferredToAsRefLocals() throws Exception { + XmlBeanFactory factory = new XmlBeanFactory( + new ClassPathResource("local-collections-using-XSD.xml", getClass())); + factory.preInstantiateSingletons(); + } + + public void testRefToSeparatePrototypeInstances() throws Exception { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + + TestBean emma = (TestBean) xbf.getBean("emma"); + TestBean georgia = (TestBean) xbf.getBean("georgia"); + ITestBean emmasJenks = emma.getSpouse(); + ITestBean georgiasJenks = georgia.getSpouse(); + assertTrue("Emma and georgia think they have a different boyfriend", emmasJenks != georgiasJenks); + assertTrue("Emmas jenks has right name", emmasJenks.getName().equals("Andrew")); + assertTrue("Emmas doesn't equal new ref", emmasJenks != xbf.getBean("jenks")); + assertTrue("Georgias jenks has right name", emmasJenks.getName().equals("Andrew")); + assertTrue("They are object equal", emmasJenks.equals(georgiasJenks)); + assertTrue("They object equal direct ref", emmasJenks.equals(xbf.getBean("jenks"))); + } + + public void testRefToSingleton() throws Exception { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + Resource resource = new ClassPathResource("reftypes.xml", getClass()); + reader.loadBeanDefinitions(new EncodedResource(resource, "ISO-8859-1")); + + TestBean jen = (TestBean) xbf.getBean("jenny"); + TestBean dave = (TestBean) xbf.getBean("david"); + TestBean jenks = (TestBean) xbf.getBean("jenks"); + ITestBean davesJen = dave.getSpouse(); + ITestBean jenksJen = jenks.getSpouse(); + assertTrue("1 jen instance", davesJen == jenksJen); + assertTrue("1 jen instance", davesJen == jen); + } + + public void testInnerBeans() throws IOException { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + InputStream inputStream = getClass().getResourceAsStream("reftypes.xml"); + try { + reader.loadBeanDefinitions(new InputSource(inputStream)); + } + finally { + inputStream.close(); + } + + // Let's create the outer bean named "innerBean", + // to check whether it doesn't create any conflicts + // with the actual inner beans named "innerBean". + xbf.getBean("innerBean"); + + TestBean hasInnerBeans = (TestBean) xbf.getBean("hasInnerBeans"); + assertEquals(5, hasInnerBeans.getAge()); + TestBean inner1 = (TestBean) hasInnerBeans.getSpouse(); + assertNotNull(inner1); + assertEquals("innerBean#1", inner1.getBeanName()); + assertEquals("inner1", inner1.getName()); + assertEquals(6, inner1.getAge()); + + assertNotNull(hasInnerBeans.getFriends()); + Object[] friends = hasInnerBeans.getFriends().toArray(); + assertEquals(3, friends.length); + DerivedTestBean inner2 = (DerivedTestBean) friends[0]; + assertEquals("inner2", inner2.getName()); + assertTrue(inner2.getBeanName().startsWith(DerivedTestBean.class.getName())); + assertFalse(xbf.containsBean("innerBean#1")); + assertNotNull(inner2); + assertEquals(7, inner2.getAge()); + TestBean innerFactory = (TestBean) friends[1]; + assertEquals(DummyFactory.SINGLETON_NAME, innerFactory.getName()); + TestBean inner5 = (TestBean) friends[2]; + assertEquals("innerBean#2", inner5.getBeanName()); + + assertNotNull(hasInnerBeans.getSomeMap()); + assertEquals(2, hasInnerBeans.getSomeMap().size()); + TestBean inner3 = (TestBean) hasInnerBeans.getSomeMap().get("someKey"); + assertEquals("Jenny", inner3.getName()); + assertEquals(30, inner3.getAge()); + TestBean inner4 = (TestBean) hasInnerBeans.getSomeMap().get("someOtherKey"); + assertEquals("inner4", inner4.getName()); + assertEquals(9, inner4.getAge()); + + TestBean hasInnerBeansForConstructor = (TestBean) xbf.getBean("hasInnerBeansForConstructor"); + TestBean innerForConstructor = (TestBean) hasInnerBeansForConstructor.getSpouse(); + assertNotNull(innerForConstructor); + assertEquals("innerBean#3", innerForConstructor.getBeanName()); + assertEquals("inner1", innerForConstructor.getName()); + assertEquals(6, innerForConstructor.getAge()); + + xbf.destroySingletons(); + assertTrue(inner1.wasDestroyed()); + assertTrue(inner2.wasDestroyed()); + assertTrue(innerFactory.getName() == null); + assertTrue(inner5.wasDestroyed()); + } + + public void testInnerBeansWithoutDestroy() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + + // Let's create the outer bean named "innerBean", + // to check whether it doesn't create any conflicts + // with the actual inner beans named "innerBean". + xbf.getBean("innerBean"); + + TestBean hasInnerBeans = (TestBean) xbf.getBean("hasInnerBeansWithoutDestroy"); + assertEquals(5, hasInnerBeans.getAge()); + TestBean inner1 = (TestBean) hasInnerBeans.getSpouse(); + assertNotNull(inner1); + assertEquals("innerBean", inner1.getBeanName()); + assertEquals("inner1", inner1.getName()); + assertEquals(6, inner1.getAge()); + + assertNotNull(hasInnerBeans.getFriends()); + Object[] friends = hasInnerBeans.getFriends().toArray(); + assertEquals(3, friends.length); + DerivedTestBean inner2 = (DerivedTestBean) friends[0]; + assertEquals("inner2", inner2.getName()); + assertTrue(inner2.getBeanName().startsWith(DerivedTestBean.class.getName())); + assertNotNull(inner2); + assertEquals(7, inner2.getAge()); + TestBean innerFactory = (TestBean) friends[1]; + assertEquals(DummyFactory.SINGLETON_NAME, innerFactory.getName()); + TestBean inner5 = (TestBean) friends[2]; + assertEquals("innerBean", inner5.getBeanName()); + } + + public void testFailsOnInnerBean() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + + try { + xbf.getBean("failsOnInnerBean"); + } + catch (BeanCreationException ex) { + // Check whether message contains outer bean name. + ex.printStackTrace(); + assertTrue(ex.getMessage().indexOf("failsOnInnerBean") != -1); + assertTrue(ex.getMessage().indexOf("someMap") != -1); + } + + try { + xbf.getBean("failsOnInnerBeanForConstructor"); + } + catch (BeanCreationException ex) { + // Check whether message contains outer bean name. + ex.printStackTrace(); + assertTrue(ex.getMessage().indexOf("failsOnInnerBeanForConstructor") != -1); + assertTrue(ex.getMessage().indexOf("constructor argument") != -1); + } + } + + public void testSingletonInheritanceFromParentFactorySingleton() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + assertEquals(TestBean.class, child.getType("inheritsFromParentFactory")); + TestBean inherits = (TestBean) child.getBean("inheritsFromParentFactory"); + // Name property value is overridden + assertTrue(inherits.getName().equals("override")); + // Age property is inherited from bean in parent factory + assertTrue(inherits.getAge() == 1); + TestBean inherits2 = (TestBean) child.getBean("inheritsFromParentFactory"); + assertTrue(inherits2 == inherits); + } + + public void testInheritanceWithDifferentClass() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + assertEquals(DerivedTestBean.class, child.getType("inheritsWithClass")); + DerivedTestBean inherits = (DerivedTestBean) child.getBean("inheritsWithDifferentClass"); + // Name property value is overridden + assertTrue(inherits.getName().equals("override")); + // Age property is inherited from bean in parent factory + assertTrue(inherits.getAge() == 1); + assertTrue(inherits.wasInitialized()); + } + + public void testInheritanceWithClass() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + assertEquals(DerivedTestBean.class, child.getType("inheritsWithClass")); + DerivedTestBean inherits = (DerivedTestBean) child.getBean("inheritsWithClass"); + // Name property value is overridden + assertTrue(inherits.getName().equals("override")); + // Age property is inherited from bean in parent factory + assertTrue(inherits.getAge() == 1); + assertTrue(inherits.wasInitialized()); + } + + public void testPrototypeInheritanceFromParentFactoryPrototype() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + assertEquals(TestBean.class, child.getType("prototypeInheritsFromParentFactoryPrototype")); + TestBean inherits = (TestBean) child.getBean("prototypeInheritsFromParentFactoryPrototype"); + // Name property value is overridden + assertTrue(inherits.getName().equals("prototype-override")); + // Age property is inherited from bean in parent factory + assertTrue(inherits.getAge() == 2); + TestBean inherits2 = (TestBean) child.getBean("prototypeInheritsFromParentFactoryPrototype"); + assertFalse(inherits2 == inherits); + inherits2.setAge(13); + assertTrue(inherits2.getAge() == 13); + // Shouldn't have changed first instance + assertTrue(inherits.getAge() == 2); + } + + public void testPrototypeInheritanceFromParentFactorySingleton() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + TestBean inherits = (TestBean) child.getBean("protoypeInheritsFromParentFactorySingleton"); + // Name property value is overridden + assertTrue(inherits.getName().equals("prototypeOverridesInheritedSingleton")); + // Age property is inherited from bean in parent factory + assertTrue(inherits.getAge() == 1); + TestBean inherits2 = (TestBean) child.getBean("protoypeInheritsFromParentFactorySingleton"); + assertFalse(inherits2 == inherits); + inherits2.setAge(13); + assertTrue(inherits2.getAge() == 13); + // Shouldn't have changed first instance + assertTrue(inherits.getAge() == 1); + } + + public void testAutowireModeNotInherited() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("overrides.xml", getClass())); + + TestBean david = (TestBean)xbf.getBean("magicDavid"); + // the parent bean is autowiring + assertNotNull(david.getSpouse()); + + TestBean derivedDavid = (TestBean)xbf.getBean("magicDavidDerived"); + // this fails while it inherits from the child bean + assertNull("autowiring not propagated along child relationships", derivedDavid.getSpouse()); + } + + public void testAbstractParentBeans() { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + parent.preInstantiateSingletons(); + assertTrue(parent.isSingleton("inheritedTestBeanWithoutClass")); + + // abstract beans should not match + Map tbs = parent.getBeansOfType(TestBean.class); + assertEquals(2, tbs.size()); + assertTrue(tbs.containsKey("inheritedTestBeanPrototype")); + assertTrue(tbs.containsKey("inheritedTestBeanSingleton")); + + // abstract bean should throw exception on creation attempt + try { + parent.getBean("inheritedTestBeanWithoutClass"); + fail("Should have thrown BeanIsAbstractException"); + } + catch (BeanIsAbstractException ex) { + // expected + } + + // non-abstract bean should work, even if it serves as parent + assertTrue(parent.getBean("inheritedTestBeanPrototype") instanceof TestBean); + } + + public void testDependenciesMaterializeThis() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("dependenciesMaterializeThis.xml", getClass())); + + assertEquals(2, xbf.getBeansOfType(DummyBo.class, true, false).size()); + assertEquals(3, xbf.getBeansOfType(DummyBo.class, true, true).size()); + assertEquals(3, xbf.getBeansOfType(DummyBo.class, true, false).size()); + assertEquals(3, xbf.getBeansOfType(DummyBo.class).size()); + assertEquals(2, xbf.getBeansOfType(DummyBoImpl.class, true, true).size()); + assertEquals(1, xbf.getBeansOfType(DummyBoImpl.class, false, true).size()); + assertEquals(2, xbf.getBeansOfType(DummyBoImpl.class).size()); + + DummyBoImpl bos = (DummyBoImpl) xbf.getBean("boSingleton"); + DummyBoImpl bop = (DummyBoImpl) xbf.getBean("boPrototype"); + assertNotSame(bos, bop); + assertTrue(bos.dao == bop.dao); + } + + public void testChildOverridesParentBean() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + TestBean inherits = (TestBean) child.getBean("inheritedTestBean"); + // Name property value is overridden + assertTrue(inherits.getName().equals("overrideParentBean")); + // Age property is inherited from bean in parent factory + assertTrue(inherits.getAge() == 1); + TestBean inherits2 = (TestBean) child.getBean("inheritedTestBean"); + assertTrue(inherits2 == inherits); + } + + /** + * Check that a prototype can't inherit from a bogus parent. + * If a singleton does this the factory will fail to load. + */ + public void testBogusParentageFromParentFactory() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + try { + child.getBean("bogusParent", TestBean.class); + fail(); + } + catch (BeanDefinitionStoreException ex) { + // check exception message contains the name + assertTrue(ex.getMessage().indexOf("bogusParent") != -1); + assertTrue(ex.getCause() instanceof NoSuchBeanDefinitionException); + } + } + + /** + * Note that prototype/singleton distinction is not inherited. + * It's possible for a subclass singleton not to return independent + * instances even if derived from a prototype + */ + public void testSingletonInheritsFromParentFactoryPrototype() throws Exception { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + TestBean inherits = (TestBean) child.getBean("singletonInheritsFromParentFactoryPrototype"); + // Name property value is overriden + assertTrue(inherits.getName().equals("prototype-override")); + // Age property is inherited from bean in parent factory + assertTrue(inherits.getAge() == 2); + TestBean inherits2 = (TestBean) child.getBean("singletonInheritsFromParentFactoryPrototype"); + assertTrue(inherits2 == inherits); + } + + public void testSingletonFromParent() { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + TestBean beanFromParent = (TestBean) parent.getBean("inheritedTestBeanSingleton"); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + TestBean beanFromChild = (TestBean) child.getBean("inheritedTestBeanSingleton"); + assertTrue("singleton from parent and child is the same", beanFromParent == beanFromChild); + } + + public void testNestedPropertyValue() { + XmlBeanFactory parent = new XmlBeanFactory(new ClassPathResource("parent.xml", getClass())); + XmlBeanFactory child = new XmlBeanFactory(new ClassPathResource("child.xml", getClass()), parent); + IndexedTestBean bean = (IndexedTestBean) child.getBean("indexedTestBean"); + assertEquals("name applied correctly", "myname", bean.getArray()[0].getName()); + } + + public void testCircularReferences() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + TestBean jenny = (TestBean) xbf.getBean("jenny"); + TestBean david = (TestBean) xbf.getBean("david"); + TestBean ego = (TestBean) xbf.getBean("ego"); + TestBean complexInnerEgo = (TestBean) xbf.getBean("complexInnerEgo"); + TestBean complexEgo = (TestBean) xbf.getBean("complexEgo"); + assertTrue("Correct circular reference", jenny.getSpouse() == david); + assertTrue("Correct circular reference", david.getSpouse() == jenny); + assertTrue("Correct circular reference", ego.getSpouse() == ego); + assertTrue("Correct circular reference", complexInnerEgo.getSpouse().getSpouse() == complexInnerEgo); + assertTrue("Correct circular reference", complexEgo.getSpouse().getSpouse() == complexEgo); + } + + public void testCircularReferenceWithFactoryBeanFirst() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + TestBean egoBridge = (TestBean) xbf.getBean("egoBridge"); + TestBean complexEgo = (TestBean) xbf.getBean("complexEgo"); + assertTrue("Correct circular reference", complexEgo.getSpouse().getSpouse() == complexEgo); + } + + public void testCircularReferenceWithTwoFactoryBeans() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + TestBean ego1 = (TestBean) xbf.getBean("ego1"); + assertTrue("Correct circular reference", ego1.getSpouse().getSpouse() == ego1); + TestBean ego3 = (TestBean) xbf.getBean("ego3"); + assertTrue("Correct circular reference", ego3.getSpouse().getSpouse() == ego3); + } + + public void testCircularReferencesWithNotAllowed() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + xbf.setAllowCircularReferences(false); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + try { + xbf.getBean("jenny"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.contains(BeanCurrentlyInCreationException.class)); + } + } + + public void testCircularReferencesWithWrapping() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + xbf.addBeanPostProcessor(new WrappingPostProcessor()); + try { + xbf.getBean("jenny"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.contains(BeanCurrentlyInCreationException.class)); + } + } + + public void testCircularReferencesWithWrappingAndRawInjectionAllowed() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + xbf.setAllowRawInjectionDespiteWrapping(true); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); + reader.loadBeanDefinitions(new ClassPathResource("reftypes.xml", getClass())); + xbf.addBeanPostProcessor(new WrappingPostProcessor()); + + ITestBean jenny = (ITestBean) xbf.getBean("jenny"); + ITestBean david = (ITestBean) xbf.getBean("david"); + assertTrue(AopUtils.isAopProxy(jenny)); + assertTrue(AopUtils.isAopProxy(david)); + assertSame(david, jenny.getSpouse()); + assertNotSame(jenny, david.getSpouse()); + assertEquals("Jenny", david.getSpouse().getName()); + assertSame(david, david.getSpouse().getSpouse()); + assertTrue(AopUtils.isAopProxy(jenny.getSpouse())); + assertTrue(!AopUtils.isAopProxy(david.getSpouse())); + } + + public void testFactoryReferenceCircle() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("factoryCircle.xml", getClass())); + TestBean tb = (TestBean) xbf.getBean("singletonFactory"); + DummyFactory db = (DummyFactory) xbf.getBean("&singletonFactory"); + assertTrue(tb == db.getOtherTestBean()); + } + + public void testFactoryReferenceWithDoublePrefix() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("factoryCircle.xml", getClass())); + DummyFactory db = (DummyFactory) xbf.getBean("&&singletonFactory"); + } + + public void testComplexFactoryReferenceCircle() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("complexFactoryCircle.xml", getClass())); + xbf.getBean("proxy1"); + // check that unused instances from autowiring got removed + assertEquals(5, xbf.getSingletonCount()); + // properly create the remaining two instances + xbf.getBean("proxy2"); + assertEquals(7, xbf.getSingletonCount()); + } + + public void testNoSuchFactoryBeanMethod() { + try { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("no-such-factory-method.xml", getClass())); + assertNotNull(xbf.getBean("defaultTestBean")); + fail("Should not get invalid bean"); + } + catch (BeanCreationException ex) { + // Ok + } + } + + public void testInitMethodIsInvoked() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("initializers.xml", getClass())); + DoubleInitializer in = (DoubleInitializer) xbf.getBean("init-method1"); + // Initializer should have doubled value + assertEquals(14, in.getNum()); + } + + /** + * Test that if a custom initializer throws an exception, it's handled correctly + */ + public void testInitMethodThrowsException() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("initializers.xml", getClass())); + try { + xbf.getBean("init-method2"); + fail(); + } + catch (BeanCreationException ex) { + assertTrue(ex.getResourceDescription().indexOf("initializers.xml") != -1); + assertEquals("init-method2", ex.getBeanName()); + assertTrue(ex.getCause() instanceof ServletException); + } + } + + public void testNoSuchInitMethod() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("initializers.xml", getClass())); + try { + xbf.getBean("init-method3"); + fail(); + } + catch (FatalBeanException ex) { + // check message is helpful + assertTrue(ex.getMessage().indexOf("initializers.xml") != -1); + assertTrue(ex.getMessage().indexOf("init-method3") != -1); + assertTrue(ex.getMessage().indexOf("init") != -1); + } + } + + /** + * Check that InitializingBean method is called first. + */ + public void testInitializingBeanAndInitMethod() throws Exception { + InitAndIB.constructed = false; + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("initializers.xml", getClass())); + assertFalse(InitAndIB.constructed); + xbf.preInstantiateSingletons(); + assertFalse(InitAndIB.constructed); + InitAndIB iib = (InitAndIB) xbf.getBean("init-and-ib"); + assertTrue(InitAndIB.constructed); + assertTrue(iib.afterPropertiesSetInvoked && iib.initMethodInvoked); + assertTrue(!iib.destroyed && !iib.customDestroyed); + xbf.destroySingletons(); + assertTrue(iib.destroyed && iib.customDestroyed); + xbf.destroySingletons(); + assertTrue(iib.destroyed && iib.customDestroyed); + } + + /** + * Check that InitializingBean method is not called twice. + */ + public void testInitializingBeanAndSameInitMethod() throws Exception { + InitAndIB.constructed = false; + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("initializers.xml", getClass())); + assertFalse(InitAndIB.constructed); + xbf.preInstantiateSingletons(); + assertFalse(InitAndIB.constructed); + InitAndIB iib = (InitAndIB) xbf.getBean("ib-same-init"); + assertTrue(InitAndIB.constructed); + assertTrue(iib.afterPropertiesSetInvoked && !iib.initMethodInvoked); + assertTrue(!iib.destroyed && !iib.customDestroyed); + xbf.destroySingletons(); + assertTrue(iib.destroyed && !iib.customDestroyed); + xbf.destroySingletons(); + assertTrue(iib.destroyed && !iib.customDestroyed); + } + + public void testDefaultLazyInit() throws Exception { + InitAndIB.constructed = false; + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("default-lazy-init.xml", getClass())); + assertFalse(InitAndIB.constructed); + xbf.preInstantiateSingletons(); + assertTrue(InitAndIB.constructed); + try { + xbf.getBean("lazy-and-bad"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getCause() instanceof ServletException); + } + } + + public void testNoSuchXmlFile() throws Exception { + try { + new XmlBeanFactory(new ClassPathResource("missing.xml", getClass())); + fail("Must not create factory from missing XML"); + } + catch (BeanDefinitionStoreException expected) { + } + } + + public void testInvalidXmlFile() throws Exception { + try { + new XmlBeanFactory(new ClassPathResource("invalid.xml", getClass())); + fail("Must not create factory from invalid XML"); + } + catch (BeanDefinitionStoreException expected) { + } + } + + public void testUnsatisfiedObjectDependencyCheck() throws Exception { + try { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("unsatisfiedObjectDependencyCheck.xml", getClass())); + xbf.getBean("a", DependenciesBean.class); + fail("Must have thrown an UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + } + } + + public void testUnsatisfiedSimpleDependencyCheck() throws Exception { + try { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("unsatisfiedSimpleDependencyCheck.xml", getClass())); + xbf.getBean("a", DependenciesBean.class); + fail("Must have thrown an UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testSatisfiedObjectDependencyCheck() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("satisfiedObjectDependencyCheck.xml", getClass())); + DependenciesBean a = (DependenciesBean) xbf.getBean("a"); + assertNotNull(a.getSpouse()); + assertEquals(xbf, a.getBeanFactory()); + } + + public void testSatisfiedSimpleDependencyCheck() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("satisfiedSimpleDependencyCheck.xml", getClass())); + DependenciesBean a = (DependenciesBean) xbf.getBean("a"); + assertEquals(a.getAge(), 33); + } + + public void testUnsatisfiedAllDependencyCheck() throws Exception { + try { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("unsatisfiedAllDependencyCheckMissingObjects.xml", getClass())); + xbf.getBean("a", DependenciesBean.class); + fail("Must have thrown an UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testSatisfiedAllDependencyCheck() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("satisfiedAllDependencyCheck.xml", getClass())); + DependenciesBean a = (DependenciesBean) xbf.getBean("a"); + assertEquals(a.getAge(), 33); + assertNotNull(a.getName()); + assertNotNull(a.getSpouse()); + } + + public void testAutowire() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("autowire.xml", getClass())); + TestBean spouse = new TestBean("kerry", 0); + xbf.registerSingleton("spouse", spouse); + doTestAutowire(xbf); + } + + public void testAutowireWithParent() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("autowire.xml", getClass())); + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "kerry"); + lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class, pvs)); + xbf.setParentBeanFactory(lbf); + doTestAutowire(xbf); + } + + private void doTestAutowire(XmlBeanFactory xbf) throws Exception { + DependenciesBean rod1 = (DependenciesBean) xbf.getBean("rod1"); + TestBean kerry = (TestBean) xbf.getBean("spouse"); + // should have been autowired + assertEquals(kerry, rod1.getSpouse()); + + DependenciesBean rod1a = (DependenciesBean) xbf.getBean("rod1a"); + // should have been autowired + assertEquals(kerry, rod1a.getSpouse()); + + DependenciesBean rod2 = (DependenciesBean) xbf.getBean("rod2"); + // should have been autowired + assertEquals(kerry, rod2.getSpouse()); + + DependenciesBean rod2a = (DependenciesBean) xbf.getBean("rod2a"); + // should have been set explicitly + assertEquals(kerry, rod2a.getSpouse()); + + ConstructorDependenciesBean rod3 = (ConstructorDependenciesBean) xbf.getBean("rod3"); + IndexedTestBean other = (IndexedTestBean) xbf.getBean("other"); + // should have been autowired + assertEquals(kerry, rod3.getSpouse1()); + assertEquals(kerry, rod3.getSpouse2()); + assertEquals(other, rod3.getOther()); + + ConstructorDependenciesBean rod3a = (ConstructorDependenciesBean) xbf.getBean("rod3a"); + // should have been autowired + assertEquals(kerry, rod3a.getSpouse1()); + assertEquals(kerry, rod3a.getSpouse2()); + assertEquals(other, rod3a.getOther()); + + try { + xbf.getBean("rod4", ConstructorDependenciesBean.class); + fail("Must have thrown a FatalBeanException"); + } + catch (FatalBeanException expected) { + } + + DependenciesBean rod5 = (DependenciesBean) xbf.getBean("rod5"); + // Should not have been autowired + assertNull(rod5.getSpouse()); + + BeanFactory appCtx = (BeanFactory) xbf.getBean("childAppCtx"); + assertTrue(appCtx.containsBean("rod1")); + assertTrue(appCtx.containsBean("jenny")); + } + + public void testAutowireWithDefault() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("default-autowire.xml", getClass())); + + DependenciesBean rod1 = (DependenciesBean) xbf.getBean("rod1"); + // should have been autowired + assertNotNull(rod1.getSpouse()); + assertTrue(rod1.getSpouse().getName().equals("Kerry")); + + DependenciesBean rod2 = (DependenciesBean) xbf.getBean("rod2"); + // should have been autowired + assertNotNull(rod2.getSpouse()); + assertTrue(rod2.getSpouse().getName().equals("Kerry")); + + try { + xbf.getBean("rod3", DependenciesBean.class); + fail("Must have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testAutowireByConstructor() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + ConstructorDependenciesBean rod1 = (ConstructorDependenciesBean) xbf.getBean("rod1"); + TestBean kerry = (TestBean) xbf.getBean("kerry2"); + // should have been autowired + assertEquals(kerry, rod1.getSpouse1()); + assertEquals(0, rod1.getAge()); + assertEquals(null, rod1.getName()); + + ConstructorDependenciesBean rod2 = (ConstructorDependenciesBean) xbf.getBean("rod2"); + TestBean kerry1 = (TestBean) xbf.getBean("kerry1"); + TestBean kerry2 = (TestBean) xbf.getBean("kerry2"); + // should have been autowired + assertEquals(kerry2, rod2.getSpouse1()); + assertEquals(kerry1, rod2.getSpouse2()); + assertEquals(0, rod2.getAge()); + assertEquals(null, rod2.getName()); + + ConstructorDependenciesBean rod = (ConstructorDependenciesBean) xbf.getBean("rod3"); + IndexedTestBean other = (IndexedTestBean) xbf.getBean("other"); + // should have been autowired + assertEquals(kerry, rod.getSpouse1()); + assertEquals(kerry, rod.getSpouse2()); + assertEquals(other, rod.getOther()); + assertEquals(0, rod.getAge()); + assertEquals(null, rod.getName()); + + xbf.getBean("rod4", ConstructorDependenciesBean.class); + // should have been autowired + assertEquals(kerry, rod.getSpouse1()); + assertEquals(kerry, rod.getSpouse2()); + assertEquals(other, rod.getOther()); + assertEquals(0, rod.getAge()); + assertEquals(null, rod.getName()); + } + + public void testAutowireByConstructorWithSimpleValues() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + + ConstructorDependenciesBean rod5 = (ConstructorDependenciesBean) xbf.getBean("rod5"); + TestBean kerry1 = (TestBean) xbf.getBean("kerry1"); + TestBean kerry2 = (TestBean) xbf.getBean("kerry2"); + IndexedTestBean other = (IndexedTestBean) xbf.getBean("other"); + // should have been autowired + assertEquals(kerry2, rod5.getSpouse1()); + assertEquals(kerry1, rod5.getSpouse2()); + assertEquals(other, rod5.getOther()); + assertEquals(99, rod5.getAge()); + assertEquals("myname", rod5.getName()); + + DerivedConstructorDependenciesBean rod6 = (DerivedConstructorDependenciesBean) xbf.getBean("rod6"); + // should have been autowired + assertTrue(rod6.initialized); + assertTrue(!rod6.destroyed); + assertEquals(kerry2, rod6.getSpouse1()); + assertEquals(kerry1, rod6.getSpouse2()); + assertEquals(other, rod6.getOther()); + assertEquals(0, rod6.getAge()); + assertEquals(null, rod6.getName()); + + xbf.destroySingletons(); + assertTrue(rod6.destroyed); + } + + public void testRelatedCausesFromConstructorResolution() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + + try { + xbf.getBean("rod2Accessor"); + } + catch (BeanCreationException ex) { + assertTrue(ex.toString().indexOf("touchy") != -1); + ex.printStackTrace(); + assertNull(ex.getRelatedCauses()); + } + } + + public void testConstructorArgResolution() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + TestBean kerry1 = (TestBean) xbf.getBean("kerry1"); + TestBean kerry2 = (TestBean) xbf.getBean("kerry2"); + + ConstructorDependenciesBean rod9 = (ConstructorDependenciesBean) xbf.getBean("rod9"); + assertEquals(99, rod9.getAge()); + ConstructorDependenciesBean rod9a = (ConstructorDependenciesBean) xbf.getBean("rod9", new Object[] {new Integer(98)}); + assertEquals(98, rod9a.getAge()); + ConstructorDependenciesBean rod9b = (ConstructorDependenciesBean) xbf.getBean("rod9", new Object[] {"myName"}); + assertEquals("myName", rod9b.getName()); + ConstructorDependenciesBean rod9c = (ConstructorDependenciesBean) xbf.getBean("rod9", new Object[] {new Integer(97)}); + assertEquals(97, rod9c.getAge()); + + ConstructorDependenciesBean rod10 = (ConstructorDependenciesBean) xbf.getBean("rod10"); + assertEquals(null, rod10.getName()); + + ConstructorDependenciesBean rod11 = (ConstructorDependenciesBean) xbf.getBean("rod11"); + assertEquals(kerry2, rod11.getSpouse1()); + + ConstructorDependenciesBean rod12 = (ConstructorDependenciesBean) xbf.getBean("rod12"); + assertEquals(kerry1, rod12.getSpouse1()); + assertNull(rod12.getSpouse2()); + + ConstructorDependenciesBean rod13 = (ConstructorDependenciesBean) xbf.getBean("rod13"); + assertEquals(kerry1, rod13.getSpouse1()); + assertEquals(kerry2, rod13.getSpouse2()); + + ConstructorDependenciesBean rod14 = (ConstructorDependenciesBean) xbf.getBean("rod14"); + assertEquals(kerry1, rod14.getSpouse1()); + assertEquals(kerry2, rod14.getSpouse2()); + + ConstructorDependenciesBean rod15 = (ConstructorDependenciesBean) xbf.getBean("rod15"); + assertEquals(kerry2, rod15.getSpouse1()); + assertEquals(kerry1, rod15.getSpouse2()); + + ConstructorDependenciesBean rod16 = (ConstructorDependenciesBean) xbf.getBean("rod16"); + assertEquals(kerry2, rod16.getSpouse1()); + assertEquals(kerry1, rod16.getSpouse2()); + assertEquals(29, rod16.getAge()); + } + + public void testConstructorArgWithSingleMatch() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + File file = (File) xbf.getBean("file"); + assertEquals(File.separator + "test", file.getPath()); + } + + public void testThrowsExceptionOnTooManyArguments() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + try { + xbf.getBean("rod7", ConstructorDependenciesBean.class); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException expected) { + } + } + + public void testThrowsExceptionOnAmbiguousResolution() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + try { + xbf.getBean("rod8", ConstructorDependenciesBean.class); + fail("Must have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException expected) { + } + } + + public void testDependsOn() { + doTestDependencies("dependencies-dependsOn.xml", 1); + } + + public void testDependsOnInInnerBean() { + doTestDependencies("dependencies-dependsOn-inner.xml", 4); + } + + public void testDependenciesThroughConstructorArguments() { + doTestDependencies("dependencies-carg.xml", 1); + } + + public void testDependenciesThroughConstructorArgumentAutowiring() { + doTestDependencies("dependencies-carg-autowire.xml", 1); + } + + public void testDependenciesThroughConstructorArgumentsInInnerBean() { + doTestDependencies("dependencies-carg-inner.xml", 1); + } + + public void testDependenciesThroughProperties() { + doTestDependencies("dependencies-prop.xml", 1); + } + + public void testDependenciesThroughPropertiesWithInTheMiddle() { + doTestDependencies("dependencies-prop-inTheMiddle.xml", 1); + } + + public void testDependenciesThroughPropertyAutowiringByName() { + doTestDependencies("dependencies-prop-autowireByName.xml", 1); + } + + public void testDependenciesThroughPropertyAutowiringByType() { + doTestDependencies("dependencies-prop-autowireByType.xml", 1); + } + + public void testDependenciesThroughPropertiesInInnerBean() { + doTestDependencies("dependencies-prop-inner.xml", 1); + } + + private void doTestDependencies(String filename, int nrOfHoldingBeans) { + PreparingBean1.prepared = false; + PreparingBean1.destroyed = false; + PreparingBean2.prepared = false; + PreparingBean2.destroyed = false; + DependingBean.destroyCount = 0; + HoldingBean.destroyCount = 0; + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource(filename, getClass())); + xbf.preInstantiateSingletons(); + xbf.destroySingletons(); + assertTrue(PreparingBean1.prepared); + assertTrue(PreparingBean1.destroyed); + assertTrue(PreparingBean2.prepared); + assertTrue(PreparingBean2.destroyed); + assertEquals(nrOfHoldingBeans, DependingBean.destroyCount); + if (!xbf.getBeansOfType(HoldingBean.class, false, false).isEmpty()) { + assertEquals(nrOfHoldingBeans, HoldingBean.destroyCount); + } + } + + /** + * When using a BeanFactory. singletons are of course not pre-instantiated. + * So rubbish class names in bean defs must now not be 'resolved' when the + * bean def is being parsed, 'cos everything on a bean def is now lazy, but + * must rather only be picked up when the bean is instantiated. + */ + public void testClassNotFoundWithDefaultBeanClassLoader() { + BeanFactory factory = new XmlBeanFactory(new ClassPathResource("classNotFound.xml", getClass())); + // cool, no errors, so the rubbish class name in the bean def was not resolved + try { + // let's resolve the bean definition; must blow up + factory.getBean("classNotFound"); + fail("Must have thrown a CannotLoadBeanClassException"); + } + catch (CannotLoadBeanClassException ex) { + assertTrue(ex.getResourceDescription().indexOf("classNotFound.xml") != -1); + assertTrue(ex.getCause() instanceof ClassNotFoundException); + } + } + + public void testClassNotFoundWithNoBeanClassLoader() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + reader.setBeanClassLoader(null); + reader.loadBeanDefinitions(new ClassPathResource("classNotFound.xml", getClass())); + assertEquals("WhatALotOfRubbish", bf.getBeanDefinition("classNotFound").getBeanClassName()); + } + + public void testResourceAndInputStream() throws IOException { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("resource.xml", getClass())); + // comes from "resourceImport.xml" + ResourceTestBean resource1 = (ResourceTestBean) xbf.getBean("resource1"); + // comes from "resource.xml" + ResourceTestBean resource2 = (ResourceTestBean) xbf.getBean("resource2"); + + assertTrue(resource1.getResource() instanceof ClassPathResource); + StringWriter writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource1.getResource().getInputStream()), writer); + assertEquals("test", writer.toString()); + writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource1.getInputStream()), writer); + assertEquals("test", writer.toString()); + writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource2.getResource().getInputStream()), writer); + assertEquals("test", writer.toString()); + writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource2.getInputStream()), writer); + assertEquals("test", writer.toString()); + } + + public void testClassPathResourceWithImport() { + XmlBeanFactory xbf = new XmlBeanFactory( + new ClassPathResource("org/springframework/beans/factory/xml/resource.xml")); + // comes from "resourceImport.xml" + xbf.getBean("resource1", ResourceTestBean.class); + // comes from "resource.xml" + xbf.getBean("resource2", ResourceTestBean.class); + } + + public void testUrlResourceWithImport() { + URL url = getClass().getResource("resource.xml"); + XmlBeanFactory xbf = new XmlBeanFactory(new UrlResource(url)); + // comes from "resourceImport.xml" + xbf.getBean("resource1", ResourceTestBean.class); + // comes from "resource.xml" + xbf.getBean("resource2", ResourceTestBean.class); + } + + public void testFileSystemResourceWithImport() { + String file = getClass().getResource("resource.xml").getFile(); + XmlBeanFactory xbf = new XmlBeanFactory(new FileSystemResource(file)); + // comes from "resourceImport.xml" + xbf.getBean("resource1", ResourceTestBean.class); + // comes from "resource.xml" + xbf.getBean("resource2", ResourceTestBean.class); + } + + public void testRecursiveImport() { + try { + XmlBeanFactory xbf = new XmlBeanFactory( + new ClassPathResource("org/springframework/beans/factory/xml/recursiveImport.xml")); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + ex.printStackTrace(); + } + } + + + public void testLookupOverrideMethodsWithSetterInjection() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("overrides.xml", getClass())); + + testLookupOverrideMethodsWithSetterInjection(xbf, "overrideOneMethod", true); + // Should work identically on subclass definition, in which lookup + // methods are inherited + testLookupOverrideMethodsWithSetterInjection(xbf, "overrideInheritedMethod", true); + + // Check cost of repeated construction of beans with method overrides + // Will pick up misuse of CGLIB + int howMany = 100; + StopWatch sw = new StopWatch(); + sw.start("Look up " + howMany + " prototype bean instances with method overrides"); + for (int i = 0; i < howMany; i++) { + testLookupOverrideMethodsWithSetterInjection(xbf, "overrideOnPrototype", false); + } + sw.stop(); + System.out.println(sw); + if (!LogFactory.getLog(DefaultListableBeanFactory.class).isDebugEnabled()) { + assertTrue(sw.getTotalTimeMillis() < 2000); + } + + // Now test distinct bean with swapped value in factory, to ensure the two are independent + OverrideOneMethod swappedOom = (OverrideOneMethod) xbf.getBean("overrideOneMethodSwappedReturnValues"); + + TestBean tb = swappedOom.getPrototypeDependency(); + assertEquals("David", tb.getName()); + tb = swappedOom.protectedOverrideSingleton(); + assertEquals("Jenny", tb.getName()); + } + + private void testLookupOverrideMethodsWithSetterInjection(BeanFactory xbf, String beanName, boolean singleton) { + OverrideOneMethod oom = (OverrideOneMethod) xbf.getBean(beanName); + + if (singleton) { + assertSame(oom, xbf.getBean(beanName)); + } + else { + assertNotSame(oom, xbf.getBean(beanName)); + } + + TestBean jenny1 = oom.getPrototypeDependency(); + assertEquals("Jenny", jenny1.getName()); + TestBean jenny2 = oom.getPrototypeDependency(); + assertEquals("Jenny", jenny2.getName()); + assertNotSame(jenny1, jenny2); + + // Check that the bean can invoke the overridden method on itself + // This differs from Spring's AOP support, which has a distinct notion + // of a "target" object, meaning that the target needs explicit knowledge + // of AOP proxying to invoke an advised method on itself. + TestBean jenny3 = oom.invokesOverridenMethodOnSelf(); + assertEquals("Jenny", jenny3.getName()); + assertNotSame(jenny1, jenny3); + + // Now try protected method, and singleton + TestBean dave1 = oom.protectedOverrideSingleton(); + assertEquals("David", dave1.getName()); + TestBean dave2 = oom.protectedOverrideSingleton(); + assertEquals("David", dave2.getName()); + assertSame(dave1, dave2); + } + + public void testReplaceMethodOverrideWithSetterInjection() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("delegationOverrides.xml", getClass())); + + OverrideOneMethod oom = (OverrideOneMethod) xbf.getBean("overrideOneMethod"); + + // Same contract as for overrides.xml + TestBean jenny1 = oom.getPrototypeDependency(); + assertEquals("Jenny", jenny1.getName()); + TestBean jenny2 = oom.getPrototypeDependency(); + assertEquals("Jenny", jenny2.getName()); + assertNotSame(jenny1, jenny2); + + TestBean notJenny = oom.getPrototypeDependency("someParam"); + assertTrue(!"Jenny".equals(notJenny.getName())); + + // Now try protected method, and singleton + TestBean dave1 = oom.protectedOverrideSingleton(); + assertEquals("David", dave1.getName()); + TestBean dave2 = oom.protectedOverrideSingleton(); + assertEquals("David", dave2.getName()); + assertSame(dave1, dave2); + + // Check unadvised behaviour + String str = "woierowijeiowiej"; + assertEquals(str, oom.echo(str)); + + // Now test replace + String s = "this is not a palindrome"; + String reverse = new StringBuffer(s).reverse().toString(); + assertEquals("Should have overridden to reverse, not echo", reverse, oom.replaceMe(s)); + + assertEquals("Should have overridden no-arg overloaded replaceMe method to return fixed value", + FixedMethodReplacer.VALUE, oom.replaceMe()); + + OverrideOneMethodSubclass ooms = (OverrideOneMethodSubclass) xbf.getBean("replaceVoidMethod"); + DoSomethingReplacer dos = (DoSomethingReplacer) xbf.getBean("doSomethingReplacer"); + assertEquals(null, dos.lastArg); + String s1 = ""; + String s2 = "foo bar black sheep"; + ooms.doSomething(s1); + assertEquals(s1, dos.lastArg); + ooms.doSomething(s2); + assertEquals(s2, dos.lastArg); + } + + public void testLookupOverrideOneMethodWithConstructorInjection() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("constructorOverrides.xml", getClass())); + + ConstructorInjectedOverrides cio = (ConstructorInjectedOverrides) xbf.getBean("constructorOverrides"); + + // Check that the setter was invoked... + // We should be able to combine Constructor and + // Setter Injection + assertEquals("Setter string was set", "from property element", cio.getSetterString()); + + // Jenny is a singleton + TestBean jenny = (TestBean) xbf.getBean("jenny"); + assertSame(jenny, cio.getTestBean()); + assertSame(jenny, cio.getTestBean()); + FactoryMethods fm1 = cio.createFactoryMethods(); + FactoryMethods fm2 = cio.createFactoryMethods(); + assertNotSame("FactoryMethods reference is to a prototype", fm1, fm2); + assertSame("The two prototypes hold the same singleton reference", + fm1.getTestBean(), fm2.getTestBean()); + } + + public void testRejectsOverrideOfBogusMethodName() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + try { + reader.loadBeanDefinitions(new ClassPathResource("invalidOverridesNoSuchMethod.xml", getClass())); + xbf.getBean("constructorOverrides"); + fail("Shouldn't allow override of bogus method"); + } + catch (BeanDefinitionStoreException ex) { + // Check that the bogus method name was included in the error message + assertTrue("Bogus method name correctly reported", ex.getMessage().indexOf("bogusMethod") != -1); + } + } + + /** + * Assert the presence of this bug until we resolve it. + */ + public void testSerializabilityOfMethodReplacer() throws Exception { + try { + BUGtestSerializableMethodReplacerAndSuperclass(); + fail(); + } + catch (AssertionFailedError ex) { + System.err.println("****** SPR-356: Objects with MethodReplace overrides are not serializable"); + } + } + + public void BUGtestSerializableMethodReplacerAndSuperclass() throws IOException, ClassNotFoundException { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("delegationOverrides.xml", getClass())); + SerializableMethodReplacerCandidate s = (SerializableMethodReplacerCandidate) xbf.getBean("serializableReplacer"); + String forwards = "this is forwards"; + String backwards = new StringBuffer(forwards).reverse().toString(); + assertEquals(backwards, s.replaceMe(forwards)); + assertTrue(SerializationTestUtils.isSerializable(s)); + s = (SerializableMethodReplacerCandidate) SerializationTestUtils.serializeAndDeserialize(s); + assertEquals("Method replace still works after serialization and deserialization", backwards, s.replaceMe(forwards)); + } + + public void testInnerBeanInheritsScopeFromConcreteChildDefinition() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); + reader.loadBeanDefinitions(new ClassPathResource("overrides.xml", getClass())); + TestBean jenny = (TestBean) xbf.getBean("jennyChild"); + assertEquals(1, jenny.getFriends().size()); + assertTrue(jenny.getFriends().iterator().next() instanceof TestBean); + } + + public void testConstructorArgWithSingleSimpleTypeMatch() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + + SingleSimpleTypeConstructorBean bean = (SingleSimpleTypeConstructorBean) xbf.getBean("beanWithBoolean"); + assertTrue(bean.isSingleBoolean()); + + SingleSimpleTypeConstructorBean bean2 = (SingleSimpleTypeConstructorBean) xbf.getBean("beanWithBoolean2"); + assertTrue(bean2.isSingleBoolean()); + } + + public void testConstructorArgWithDoubleSimpleTypeMatch() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + + SingleSimpleTypeConstructorBean bean = (SingleSimpleTypeConstructorBean) xbf.getBean("beanWithBooleanAndString"); + assertTrue(bean.isSecondBoolean()); + assertEquals("A String", bean.getTestString()); + + SingleSimpleTypeConstructorBean bean2 = (SingleSimpleTypeConstructorBean) xbf.getBean("beanWithBooleanAndString2"); + assertTrue(bean2.isSecondBoolean()); + assertEquals("A String", bean2.getTestString()); + } + + public void testDoubleBooleanAutowire() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + DoubleBooleanConstructorBean bean = (DoubleBooleanConstructorBean) xbf.getBean("beanWithDoubleBoolean"); + assertEquals(Boolean.TRUE, bean.boolean1); + assertEquals(Boolean.FALSE, bean.boolean2); + } + + public void testDoubleBooleanAutowireWithIndex() { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("constructor-arg.xml", getClass())); + DoubleBooleanConstructorBean bean = (DoubleBooleanConstructorBean) xbf.getBean("beanWithDoubleBooleanAndIndex"); + assertEquals(Boolean.FALSE, bean.boolean1); + assertEquals(Boolean.TRUE, bean.boolean2); + } + + public void testWithDuplicateName() throws Exception { + try { + new XmlBeanFactory(new ClassPathResource("testWithDuplicateNames.xml", getClass())); + fail("Duplicate name not detected"); + } + catch (BeansException ex) { + assertTrue(ex.getMessage().indexOf("Bean name 'foo'") > -1); + } + } + + public void testWithDuplicateNameInAlias() throws Exception { + try { + new XmlBeanFactory(new ClassPathResource("testWithDuplicateNameInAlias.xml", getClass())); + fail("Duplicate name not detected"); + } + catch (BeansException e) { + assertTrue(e.getMessage().indexOf("Bean name 'foo'") > -1); + } + } + + public static class DoSomethingReplacer implements MethodReplacer { + + public Object lastArg; + + public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { + assertEquals(1, args.length); + assertEquals("doSomething", method.getName()); + lastArg = args[0]; + return null; + } + } + + + public static class BadInitializer { + + /** Init method */ + public void init2() throws ServletException { + throw new ServletException(); + } + } + + + public static class DoubleInitializer { + + private int num; + + public int getNum() { + return num; + } + + public void setNum(int i) { + num = i; + } + + /** Init method */ + public void init() { + this.num *= 2; + } + } + + + public static class InitAndIB implements InitializingBean, DisposableBean { + + public static boolean constructed; + + public boolean afterPropertiesSetInvoked, initMethodInvoked, destroyed, customDestroyed; + + public InitAndIB() { + constructed = true; + } + + public void afterPropertiesSet() { + if (this.initMethodInvoked) { + fail(); + } + if (this.afterPropertiesSetInvoked) { + throw new IllegalStateException("Already initialized"); + } + this.afterPropertiesSetInvoked = true; + } + + /** Init method */ + public void customInit() throws ServletException { + if (!this.afterPropertiesSetInvoked) { + fail(); + } + if (this.initMethodInvoked) { + throw new IllegalStateException("Already customInitialized"); + } + this.initMethodInvoked = true; + } + + public void destroy() { + if (this.customDestroyed) { + fail(); + } + if (this.destroyed) { + throw new IllegalStateException("Already destroyed"); + } + this.destroyed = true; + } + + public void customDestroy() { + if (!this.destroyed) { + fail(); + } + if (this.customDestroyed) { + throw new IllegalStateException("Already customDestroyed"); + } + this.customDestroyed = true; + } + } + + + public static class PreparingBean1 implements DisposableBean { + + public static boolean prepared = false; + + public static boolean destroyed = false; + + public PreparingBean1() { + prepared = true; + } + + public void destroy() { + destroyed = true; + } + } + + + public static class PreparingBean2 implements DisposableBean { + + public static boolean prepared = false; + + public static boolean destroyed = false; + + public PreparingBean2() { + prepared = true; + } + + public void destroy() { + destroyed = true; + } + } + + + public static class DependingBean implements InitializingBean, DisposableBean { + + public static int destroyCount = 0; + + public boolean destroyed = false; + + public DependingBean() { + } + + public DependingBean(PreparingBean1 bean1, PreparingBean2 bean2) { + } + + public void setBean1(PreparingBean1 bean1) { + } + + public void setBean2(PreparingBean2 bean2) { + } + + public void setInTheMiddleBean(InTheMiddleBean bean) { + } + + public void afterPropertiesSet() { + if (!(PreparingBean1.prepared && PreparingBean2.prepared)) { + throw new IllegalStateException("Need prepared PreparingBeans!"); + } + } + + public void destroy() { + if (PreparingBean1.destroyed || PreparingBean2.destroyed) { + throw new IllegalStateException("Should not be destroyed after PreparingBeans"); + } + destroyed = true; + destroyCount++; + } + } + + + public static class InTheMiddleBean { + + public void setBean1(PreparingBean1 bean1) { + } + + public void setBean2(PreparingBean2 bean2) { + } + } + + + public static class HoldingBean implements DisposableBean { + + public static int destroyCount = 0; + + private DependingBean dependingBean; + + public boolean destroyed = false; + + public void setDependingBean(DependingBean dependingBean) { + this.dependingBean = dependingBean; + } + + public void destroy() { + if (this.dependingBean.destroyed) { + throw new IllegalStateException("Should not be destroyed after DependingBean"); + } + this.destroyed = true; + destroyCount++; + } + } + + + public static class DoubleBooleanConstructorBean { + + private Boolean boolean1; + private Boolean boolean2; + + public DoubleBooleanConstructorBean(Boolean b1, Boolean b2) { + this.boolean1 = b1; + this.boolean2 = b2; + } + } + + + public static class WrappingPostProcessor implements BeanPostProcessor { + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + ProxyFactory pf = new ProxyFactory(bean); + return pf.getProxy(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java new file mode 100644 index 00000000000..321a8f2e6e1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java @@ -0,0 +1,226 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.BeansException; +import org.springframework.beans.ITestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.AbstractListableBeanFactoryTests; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.DummyFactory; +import org.springframework.beans.factory.LifecycleBean; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + * @since 09.11.2003 + */ +public class XmlListableBeanFactoryTests extends AbstractListableBeanFactoryTests { + + private DefaultListableBeanFactory parent; + + private XmlBeanFactory factory; + + protected void setUp() { + parent = new DefaultListableBeanFactory(); + Map m = new HashMap(); + m.put("name", "Albert"); + parent.registerBeanDefinition("father", + new RootBeanDefinition(TestBean.class, new MutablePropertyValues(m))); + m = new HashMap(); + m.put("name", "Roderick"); + parent.registerBeanDefinition("rod", + new RootBeanDefinition(TestBean.class, new MutablePropertyValues(m))); + + this.factory = new XmlBeanFactory(new ClassPathResource("test.xml", getClass()), parent); + this.factory.addBeanPostProcessor(new BeanPostProcessor() { + public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException { + if (bean instanceof TestBean) { + ((TestBean) bean).setPostProcessed(true); + } + if (bean instanceof DummyFactory) { + ((DummyFactory) bean).setPostProcessed(true); + } + return bean; + } + public Object postProcessAfterInitialization(Object bean, String name) throws BeansException { + return bean; + } + }); + this.factory.addBeanPostProcessor(new LifecycleBean.PostProcessor()); + this.factory.addBeanPostProcessor(new ProtectedLifecycleBean.PostProcessor()); + //this.factory.preInstantiateSingletons(); + } + + protected BeanFactory getBeanFactory() { + return factory; + } + + public void testCount() { + assertCount(24); + } + + public void testTestBeanCount() { + assertTestBeanCount(13); + } + + public void testLifecycleMethods() throws Exception { + LifecycleBean bean = (LifecycleBean) getBeanFactory().getBean("lifecycle"); + bean.businessMethod(); + } + + public void testProtectedLifecycleMethods() throws Exception { + ProtectedLifecycleBean bean = (ProtectedLifecycleBean) getBeanFactory().getBean("protectedLifecycle"); + bean.businessMethod(); + } + + public void testDescriptionButNoProperties() throws Exception { + TestBean validEmpty = (TestBean) getBeanFactory().getBean("validEmptyWithDescription"); + assertEquals(0, validEmpty.getAge()); + } + + /** + * Test that properties with name as well as id creating an alias up front. + */ + public void testAutoAliasing() throws Exception { + List beanNames = Arrays.asList(getListableBeanFactory().getBeanDefinitionNames()); + + TestBean tb1 = (TestBean) getBeanFactory().getBean("aliased"); + TestBean alias1 = (TestBean) getBeanFactory().getBean("myalias"); + assertTrue(tb1 == alias1); + List tb1Aliases = Arrays.asList(getBeanFactory().getAliases("aliased")); + assertEquals(2, tb1Aliases.size()); + assertTrue(tb1Aliases.contains("myalias")); + assertTrue(tb1Aliases.contains("youralias")); + assertTrue(beanNames.contains("aliased")); + assertFalse(beanNames.contains("myalias")); + assertFalse(beanNames.contains("youralias")); + + TestBean tb2 = (TestBean) getBeanFactory().getBean("multiAliased"); + TestBean alias2 = (TestBean) getBeanFactory().getBean("alias1"); + TestBean alias3 = (TestBean) getBeanFactory().getBean("alias2"); + TestBean alias3a = (TestBean) getBeanFactory().getBean("alias3"); + TestBean alias3b = (TestBean) getBeanFactory().getBean("alias4"); + assertTrue(tb2 == alias2); + assertTrue(tb2 == alias3); + assertTrue(tb2 == alias3a); + assertTrue(tb2 == alias3b); + + List tb2Aliases = Arrays.asList(getBeanFactory().getAliases("multiAliased")); + assertEquals(4, tb2Aliases.size()); + assertTrue(tb2Aliases.contains("alias1")); + assertTrue(tb2Aliases.contains("alias2")); + assertTrue(tb2Aliases.contains("alias3")); + assertTrue(tb2Aliases.contains("alias4")); + assertTrue(beanNames.contains("multiAliased")); + assertFalse(beanNames.contains("alias1")); + assertFalse(beanNames.contains("alias2")); + assertFalse(beanNames.contains("alias3")); + assertFalse(beanNames.contains("alias4")); + + TestBean tb3 = (TestBean) getBeanFactory().getBean("aliasWithoutId1"); + TestBean alias4 = (TestBean) getBeanFactory().getBean("aliasWithoutId2"); + TestBean alias5 = (TestBean) getBeanFactory().getBean("aliasWithoutId3"); + assertTrue(tb3 == alias4); + assertTrue(tb3 == alias5); + List tb3Aliases = Arrays.asList(getBeanFactory().getAliases("aliasWithoutId1")); + assertEquals(2, tb3Aliases.size()); + assertTrue(tb3Aliases.contains("aliasWithoutId2")); + assertTrue(tb3Aliases.contains("aliasWithoutId3")); + assertTrue(beanNames.contains("aliasWithoutId1")); + assertFalse(beanNames.contains("aliasWithoutId2")); + assertFalse(beanNames.contains("aliasWithoutId3")); + + TestBean tb4 = (TestBean) getBeanFactory().getBean(TestBean.class.getName() + "#0"); + assertEquals(null, tb4.getName()); + + Map drs = getListableBeanFactory().getBeansOfType(DummyReferencer.class, false, false); + assertEquals(5, drs.size()); + assertTrue(drs.containsKey(DummyReferencer.class.getName() + "#0")); + assertTrue(drs.containsKey(DummyReferencer.class.getName() + "#1")); + assertTrue(drs.containsKey(DummyReferencer.class.getName() + "#2")); + } + + public void testFactoryNesting() { + ITestBean father = (ITestBean) getBeanFactory().getBean("father"); + assertTrue("Bean from root context", father != null); + + TestBean rod = (TestBean) getBeanFactory().getBean("rod"); + assertTrue("Bean from child context", "Rod".equals(rod.getName())); + assertTrue("Bean has external reference", rod.getSpouse() == father); + + rod = (TestBean) parent.getBean("rod"); + assertTrue("Bean from root context", "Roderick".equals(rod.getName())); + } + + public void testFactoryReferences() { + DummyFactory factory = (DummyFactory) getBeanFactory().getBean("&singletonFactory"); + + DummyReferencer ref = (DummyReferencer) getBeanFactory().getBean("factoryReferencer"); + assertTrue(ref.getTestBean1() == ref.getTestBean2()); + assertTrue(ref.getDummyFactory() == factory); + + DummyReferencer ref2 = (DummyReferencer) getBeanFactory().getBean("factoryReferencerWithConstructor"); + assertTrue(ref2.getTestBean1() == ref2.getTestBean2()); + assertTrue(ref2.getDummyFactory() == factory); + } + + public void testPrototypeReferences() { + // check that not broken by circular reference resolution mechanism + DummyReferencer ref1 = (DummyReferencer) getBeanFactory().getBean("prototypeReferencer"); + assertTrue("Not referencing same bean twice", ref1.getTestBean1() != ref1.getTestBean2()); + DummyReferencer ref2 = (DummyReferencer) getBeanFactory().getBean("prototypeReferencer"); + assertTrue("Not the same referencer", ref1 != ref2); + assertTrue("Not referencing same bean twice", ref2.getTestBean1() != ref2.getTestBean2()); + assertTrue("Not referencing same bean twice", ref1.getTestBean1() != ref2.getTestBean1()); + assertTrue("Not referencing same bean twice", ref1.getTestBean2() != ref2.getTestBean2()); + assertTrue("Not referencing same bean twice", ref1.getTestBean1() != ref2.getTestBean2()); + } + + public void testBeanPostProcessor() throws Exception { + TestBean kerry = (TestBean) getBeanFactory().getBean("kerry"); + TestBean kathy = (TestBean) getBeanFactory().getBean("kathy"); + DummyFactory factory = (DummyFactory) getBeanFactory().getBean("&singletonFactory"); + TestBean factoryCreated = (TestBean) getBeanFactory().getBean("singletonFactory"); + assertTrue(kerry.isPostProcessed()); + assertTrue(kathy.isPostProcessed()); + assertTrue(factory.isPostProcessed()); + assertTrue(factoryCreated.isPostProcessed()); + } + + public void testEmptyValues() { + TestBean rod = (TestBean) getBeanFactory().getBean("rod"); + TestBean kerry = (TestBean) getBeanFactory().getBean("kerry"); + assertTrue("Touchy is empty", "".equals(rod.getTouchy())); + assertTrue("Touchy is empty", "".equals(kerry.getTouchy())); + } + + public void testCommentsAndCdataInValue() { + TestBean bean = (TestBean) getBeanFactory().getBean("commentsInValue"); + assertEquals("Failed to handle comments and CDATA properly", "this is a ", bean.getName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml new file mode 100644 index 00000000000..5952fa0c540 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + name=props1 + + + + + + name=props2 + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-exclusion.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-exclusion.xml new file mode 100644 index 00000000000..041092cdd92 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-exclusion.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + name=props1 + + + + + + name=props2 + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-inclusion.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-inclusion.xml new file mode 100644 index 00000000000..271e66f5703 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-inclusion.xml @@ -0,0 +1,27 @@ + + + + + + + + + + name=props1 + + + + + + name=props2 + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml new file mode 100644 index 00000000000..c49f3680e8c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml @@ -0,0 +1,33 @@ + + + + + + + + + + name=props1 + + + + + + name=props2 + + + + + + name=someProps + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire.xml new file mode 100644 index 00000000000..0518c7c8c0e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/autowire.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /org/springframework/beans/factory/xml/collections.xml + + + + + + + /org/springframework/beans/factory/xml/constructor-arg.xml + /org/springframework/beans/factory/xml/initializers.xml + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEvents.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEvents.xml new file mode 100644 index 00000000000..110eb1ebaff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEvents.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEventsImported.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEventsImported.xml new file mode 100644 index 00000000000..bdfc3c4c31e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanEventsImported.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanNameGeneration.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanNameGeneration.xml new file mode 100644 index 00000000000..813049d1a59 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/beanNameGeneration.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/child.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/child.xml new file mode 100644 index 00000000000..654e76e7fb5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/child.xml @@ -0,0 +1,51 @@ + + + + + + + override + + + + + override + + + + + override + + + + + prototypeOverridesInheritedSingleton + + + + + prototype-override + + + + + prototype-override + + + + + overrideParentBean + + + + + + + myname + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/classNotFound.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/classNotFound.xml new file mode 100644 index 00000000000..58738edd74f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/classNotFound.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionMerging.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionMerging.xml new file mode 100644 index 00000000000..0bd9225e535 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionMerging.xml @@ -0,0 +1,205 @@ + + + + + + + + + Rob Harrop + Rod Johnson + + + + + + + + Juergen Hoeller + + + + + + + + + + + + + + + + Rob Harrop + + + + + + + + Sally Greenwood + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sall + Kerry + + + + + + + + Eva + Sally + + + + + + + + + Rob Harrop + Rod Johnson + + + + + + + + Juergen Hoeller + + + + + + + + + + + + + + + + Rob Harrop + + + + + + + + Sally Greenwood + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sall + Kerry + + + + + + + + Eva + Sally + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collections.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collections.xml new file mode 100644 index 00000000000..c0dc059c7b7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collections.xml @@ -0,0 +1,376 @@ + + + + + Jenny + 30 + + + + + + + + + Simple bean, without any collections. + + + The name of the user + David + + 27 + + + + Rod + 32 + + List of Rod's friends + + + + + + + + + Jenny + 30 + + + + + + + + David + 27 + + + + Rod + 32 + + + + + + + + + + + loner + 26 + + + My List + + + + + + + + + + literal + + + + + + + + + + + literal + + + + + + + + + verbose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bar + + + + + zero + + bar + + + + + ba + + + + + + + bar + + + + + + + + + + + + + + + + + + + bar + + + + + + + + + + + + + + + + + + bar + TWO + + + + + + + + + + + + + + + + + one + + + + + + + + + java.lang.String + java.lang.Exception + + + + + + + + 0 + 1 + 2 + + + + + + + + bar + jenny + + + + java.util.LinkedList + + + + + + + bar + jenny + + + + java.util.LinkedList + + + true + + + + + + + bar + jenny + + + + java.util.TreeSet + + + + + + + bar + jenny + + + + java.util.TreeSet + + + true + + + + + + + bar + jenny + + + + java.util.TreeMap + + + + + + + bar + jenny + + + + java.util.TreeMap + + + true + + + + + + + My Map + + + + + + + + + + + My Set + NEVER + COMMIT + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml new file mode 100644 index 00000000000..584063fde10 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml @@ -0,0 +1,61 @@ + + + + + + + + 1 + 2 + 3 + + + + + 1 + 2 + 3 + + + + + + + + + + + + + + + + + + 1 + + true + + + + 2 + + false + + + + 3 + + false + + + + 4 + + true + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/complexFactoryCircle.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/complexFactoryCircle.xml new file mode 100644 index 00000000000..c99a803abd8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/complexFactoryCircle.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + PROPAGATION_REQUIRED + + + + + + + + + + + + + + PROPAGATION_REQUIRED + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructor-arg.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructor-arg.xml new file mode 100644 index 00000000000..2221bdbfca9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructor-arg.xml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wife + + + + + + + + wife + + + + + magic int value: 99 is the number of aliens who can dance on the tip of pin + + 99 + + + myname + + + + + + + + + + + + + + + + + + + + + + + 99 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 29 + + + + + Kerry1 + + + 33 + + + + + + Kerry2 + + + 32 + + + + + + + /test + + + + + + + + + + + + true + A String + + + + + + + + + + + + + true + + + + true + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructorOverrides.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructorOverrides.xml new file mode 100644 index 00000000000..ea061046ce3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/constructorOverrides.xml @@ -0,0 +1,34 @@ + + + + + + + + + from property element + + + + + + + + Jenny + 30 + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-autowire.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-autowire.xml new file mode 100644 index 00000000000..0094234b090 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-autowire.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + Kerry + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-lazy-init.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-lazy-init.xml new file mode 100644 index 00000000000..5021766b1c0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/default-lazy-init.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/defaultLifecycleMethods.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/defaultLifecycleMethods.xml new file mode 100644 index 00000000000..635df1adc85 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/defaultLifecycleMethods.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/delegationOverrides.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/delegationOverrides.xml new file mode 100644 index 00000000000..6c85f27bb73 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/delegationOverrides.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + String + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + String + + + + + + Jenny + 30 + + + + + + + + + Simple bean, without any collections. + + + The name of the user + David + + 27 + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-autowire.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-autowire.xml new file mode 100644 index 00000000000..b05465fec7d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-autowire.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-inner.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-inner.xml new file mode 100644 index 00000000000..e8754f4c878 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg-inner.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg.xml new file mode 100644 index 00000000000..89b6f142db5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-carg.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn-inner.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn-inner.xml new file mode 100644 index 00000000000..cffa6d766d1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn-inner.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn.xml new file mode 100644 index 00000000000..dd06299f4c3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-dependsOn.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByName.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByName.xml new file mode 100644 index 00000000000..a51b221ec53 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByName.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByType.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByType.xml new file mode 100644 index 00000000000..cfc11301c77 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-autowireByType.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inTheMiddle.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inTheMiddle.xml new file mode 100644 index 00000000000..92968cf72b4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inTheMiddle.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inner.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inner.xml new file mode 100644 index 00000000000..d4100fbd1e7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop-inner.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop.xml new file mode 100644 index 00000000000..67f73e29441 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependencies-prop.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependenciesMaterializeThis.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependenciesMaterializeThis.xml new file mode 100644 index 00000000000..ac060a882b2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/dependenciesMaterializeThis.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + boPrototype + + + + + + org.springframework.beans.factory.xml.DummyBo + + + PROPAGATION_REQUIRED + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factory-methods.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factory-methods.xml new file mode 100644 index 00000000000..41cdfe5e360 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factory-methods.xml @@ -0,0 +1,145 @@ + + + + + + + + setterString + + + + + + + + + + + + + + + + setterString + + + + + 27 + gotcha + + + + + 27 + + + + + + 27 + + + + + + + + + + + + + + + setterString + + + + + testBeanOnlyPrototypeDISetterString + + + + 27 + gotcha + + + + + + 27 + gotcha + bogus + + + + + + Juergen + + + + + + + + Rod + 33 + + + + + + + + + + + + + + + + + + instanceFactory + + + + + + true + + + someuser + somepw + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factoryCircle.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factoryCircle.xml new file mode 100644 index 00000000000..f94371ee0c7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/factoryCircle.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ignoreDefaultLifecycleMethods.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ignoreDefaultLifecycleMethods.xml new file mode 100644 index 00000000000..a10029da323 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/ignoreDefaultLifecycleMethods.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/initializers.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/initializers.xml new file mode 100644 index 00000000000..1a6eb553328 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/initializers.xml @@ -0,0 +1,23 @@ + + + + + + + 7 + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid-factory.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid-factory.xml new file mode 100644 index 00000000000..4822140c206 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid-factory.xml @@ -0,0 +1,10 @@ + + + + + + + false + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid.xml new file mode 100644 index 00000000000..57151714d49 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalid.xml @@ -0,0 +1,20 @@ + + + + + + + + Jenny + 30 + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidOverridesNoSuchMethod.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidOverridesNoSuchMethod.xml new file mode 100644 index 00000000000..e8b85a509af --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidOverridesNoSuchMethod.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + Jenny + 30 + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidPerSchema.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidPerSchema.xml new file mode 100644 index 00000000000..430c8adc7e4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/invalidPerSchema.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/local-collections-using-XSD.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/local-collections-using-XSD.xml new file mode 100644 index 00000000000..da6d7405eb3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/local-collections-using-XSD.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/no-such-factory-method.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/no-such-factory-method.xml new file mode 100644 index 00000000000..251459cf61a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/no-such-factory-method.xml @@ -0,0 +1,17 @@ + + + + + + + + + setterString + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overloadOverrides.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overloadOverrides.xml new file mode 100644 index 00000000000..4f2212256cf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overloadOverrides.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + true + interceptor + + + + Jenny + 30 + + + + + autoProxiedOverload + true + interceptor + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overrides.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overrides.xml new file mode 100644 index 00000000000..bf0849bc98c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/overrides.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jenny + 30 + + + + + + + + + + Jenny + 30 + + + + + + + + + + + + + + Simple bean, without any collections. + + + The name of the user + David + + 27 + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/parent.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/parent.xml new file mode 100644 index 00000000000..6f5675fffd6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/parent.xml @@ -0,0 +1,23 @@ + + + + + + + parent + 1 + + + + parent + 1 + + + + parent + 2 + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/recursiveImport.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/recursiveImport.xml new file mode 100644 index 00000000000..07088881edf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/recursiveImport.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/reftypes.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/reftypes.xml new file mode 100644 index 00000000000..c8adc19bb3d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/reftypes.xml @@ -0,0 +1,186 @@ + + + + + + Jenny + 30 + + + + + + + + + + + Andrew + 36 + + + + + + + + + + + Georgia + 33 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + outer + 0 + + + + hasInner + 5 + + + inner1 + 6 + + + + + + inner2 + 7 + + + + inner5 + 6 + + + + + + + + inner3 + 8 + + + + + inner4 + 9 + + + + + + + + + + inner1 + 6 + + + + + + hasInner + 5 + + + inner1 + 6 + + + + + + inner2 + 7 + + + + inner5 + 6 + + + + + + + + + + + inner3 + 8 + + + + + + inner4 + 9 + + + + + + + + + + inner1 + 6 + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resource.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resource.xml new file mode 100644 index 00000000000..0bf9399d30f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resource.xml @@ -0,0 +1,17 @@ + + + + + + + + + + classpath:org/springframework/beans/factory/xml/test.properties + + + classpath:org/springframework/beans/factory/xml/test.properties + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resourceImport.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resourceImport.xml new file mode 100644 index 00000000000..e5515885eff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/resourceImport.xml @@ -0,0 +1,15 @@ + + + + + + + + classpath:org/springframework/beans/factory/xml/test.properties + + + classpath:org/springframework/beans/factory/xml/test.properties + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedAllDependencyCheck.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedAllDependencyCheck.xml new file mode 100644 index 00000000000..4b315b7582d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedAllDependencyCheck.xml @@ -0,0 +1,17 @@ + + + + + + + + 33 + Rod + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedObjectDependencyCheck.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedObjectDependencyCheck.xml new file mode 100644 index 00000000000..8c1d0d3f37c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedObjectDependencyCheck.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedSimpleDependencyCheck.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedSimpleDependencyCheck.xml new file mode 100644 index 00000000000..92981195029 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/satisfiedSimpleDependencyCheck.xml @@ -0,0 +1,13 @@ + + + + + + + 33 + Rod + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/schemaValidated.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/schemaValidated.xml new file mode 100644 index 00000000000..3a45ffec354 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/schemaValidated.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutTests.xml new file mode 100644 index 00000000000..2d5762942ff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutTests.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutWithErrorsTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutWithErrorsTests.xml new file mode 100644 index 00000000000..d82595bac7a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/shortcutWithErrorsTests.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java new file mode 100644 index 00000000000..0a9552c9a66 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java @@ -0,0 +1,155 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml.support; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; +import org.xml.sax.InputSource; + +import org.springframework.aop.Advisor; +import org.springframework.aop.framework.Advised; +import org.springframework.aop.interceptor.DebugInterceptor; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver; +import org.springframework.beans.factory.xml.NamespaceHandlerResolver; +import org.springframework.beans.factory.xml.PluggableSchemaResolver; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * @author Rob Harrop + * @author Rick Evans + */ +public final class CustomNamespaceHandlerTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + + protected void setUp() throws Exception { + String location = "org/springframework/beans/factory/xml/support/customNamespace.properties"; + NamespaceHandlerResolver resolver = new DefaultNamespaceHandlerResolver(getClass().getClassLoader(), location); + this.beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.setNamespaceHandlerResolver(resolver); + reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD); + reader.setEntityResolver(new DummySchemaResolver()); + reader.loadBeanDefinitions(getResource()); + } + + + public void testSimpleParser() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); + assetTestBean(bean); + } + + public void testSimpleDecorator() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("customisedTestBean"); + assetTestBean(bean); + } + + public void testProxyingDecorator() throws Exception { + ITestBean bean = (ITestBean) this.beanFactory.getBean("debuggingTestBean"); + assetTestBean(bean); + assertTrue(AopUtils.isAopProxy(bean)); + Advisor[] advisors = ((Advised) bean).getAdvisors(); + assertEquals("Incorrect number of advisors", 1, advisors.length); + assertEquals("Incorrect advice class.", DebugInterceptor.class, advisors[0].getAdvice().getClass()); + } + + public void testChainedDecorators() throws Exception { + ITestBean bean = (ITestBean) this.beanFactory.getBean("chainedTestBean"); + assetTestBean(bean); + assertTrue(AopUtils.isAopProxy(bean)); + Advisor[] advisors = ((Advised) bean).getAdvisors(); + assertEquals("Incorrect number of advisors", 2, advisors.length); + assertEquals("Incorrect advice class.", DebugInterceptor.class, advisors[0].getAdvice().getClass()); + assertEquals("Incorrect advice class.", NopInterceptor.class, advisors[1].getAdvice().getClass()); + } + + public void testDecorationViaAttribute() throws Exception { + BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("decorateWithAttribute"); + assertEquals("foo", beanDefinition.getAttribute("objectName")); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2728 + */ + public void testCustomElementNestedWithinUtilList() throws Exception { + List things = (List) this.beanFactory.getBean("list.of.things"); + assertNotNull(things); + assertEquals(2, things.size()); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2728 + */ + public void testCustomElementNestedWithinUtilSet() throws Exception { + Set things = (Set) this.beanFactory.getBean("set.of.things"); + assertNotNull(things); + assertEquals(2, things.size()); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2728 + */ + public void testCustomElementNestedWithinUtilMap() throws Exception { + Map things = (Map) this.beanFactory.getBean("map.of.things"); + assertNotNull(things); + assertEquals(2, things.size()); + } + + + private void assetTestBean(ITestBean bean) { + assertEquals("Invalid name", "Rob Harrop", bean.getName()); + assertEquals("Invalid age", 23, bean.getAge()); + } + + private Resource getResource() { + return new ClassPathResource("customNamespace.xml", getClass()); + } + + + private final class DummySchemaResolver extends PluggableSchemaResolver { + + public DummySchemaResolver() { + super(CustomNamespaceHandlerTests.this.getClass().getClassLoader()); + } + + + public InputSource resolveEntity(String publicId, String systemId) throws IOException { + InputSource source = super.resolveEntity(publicId, systemId); + if (source == null) { + Resource resource = new ClassPathResource("org/springframework/beans/factory/xml/support/spring-test.xsd"); + source = new InputSource(resource.getInputStream()); + source.setPublicId(publicId); + source.setSystemId(systemId); + } + return source; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/DefaultNamespaceHandlerResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/DefaultNamespaceHandlerResolverTests.java new file mode 100644 index 00000000000..a3826d38574 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/DefaultNamespaceHandlerResolverTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml.support; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver; +import org.springframework.beans.factory.xml.NamespaceHandler; +import org.springframework.beans.factory.xml.UtilNamespaceHandler; +import org.springframework.test.AssertThrows; + +/** + * Unit and integration tests for the {@link DefaultNamespaceHandlerResolver} class. + * + * @author Rob Harrop + * @author Rick Evans + */ +public class DefaultNamespaceHandlerResolverTests extends TestCase { + + public void testResolvedMappedHandler() { + DefaultNamespaceHandlerResolver resolver = new DefaultNamespaceHandlerResolver(getClass().getClassLoader()); + NamespaceHandler handler = resolver.resolve("http://www.springframework.org/schema/util"); + assertNotNull("Handler should not be null.", handler); + assertEquals("Incorrect handler loaded", UtilNamespaceHandler.class, handler.getClass()); + } + + public void testResolvedMappedHandlerWithNoArgCtor() { + DefaultNamespaceHandlerResolver resolver = new DefaultNamespaceHandlerResolver(); + NamespaceHandler handler = resolver.resolve("http://www.springframework.org/schema/util"); + assertNotNull("Handler should not be null.", handler); + assertEquals("Incorrect handler loaded", UtilNamespaceHandler.class, handler.getClass()); + } + + public void testNonExistentHandlerClass() throws Exception { + String mappingPath = "org/springframework/beans/factory/xml/support/nonExistent.properties"; + try { + new DefaultNamespaceHandlerResolver(getClass().getClassLoader(), mappingPath); + // pass + } + catch (Throwable ex) { + fail("Non-existent handler classes must be ignored: " + ex); + } + } + + public void testResolveInvalidHandler() throws Exception { + String mappingPath = "org/springframework/beans/factory/xml/support/invalid.properties"; + try { + new DefaultNamespaceHandlerResolver(getClass().getClassLoader(), mappingPath); + fail("Should not be able to map a class that doesn't implement NamespaceHandler"); + } + catch (Throwable expected) { + } + } + + public void testCtorWithNullClassLoaderArgument() throws Exception { + // simply must not bail... + new DefaultNamespaceHandlerResolver(null); + } + + public void testCtorWithNullClassLoaderArgumentAndNullMappingLocationArgument() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new DefaultNamespaceHandlerResolver(null, null); + } + }.runTest(); + } + + public void testCtorWithNonExistentMappingLocationArgument() throws Exception { + // simply must not bail; we don't want non-existent resources to result in an Exception + new DefaultNamespaceHandlerResolver(null, "738trbc bobabloobop871"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/TestNamespaceHandler.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/TestNamespaceHandler.java new file mode 100644 index 00000000000..997e21db8d6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/TestNamespaceHandler.java @@ -0,0 +1,119 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml.support; + +import org.springframework.aop.config.AbstractInterceptorDrivenBeanDefinitionDecorator; +import org.springframework.aop.interceptor.DebugInterceptor; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.BeanDefinitionDecorator; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * @author Rob Harrop + */ +public class TestNamespaceHandler extends NamespaceHandlerSupport { + + public void init() { + registerBeanDefinitionParser("testBean", new TestBeanDefinitionParser()); + registerBeanDefinitionParser("person", new PersonDefinitionParser()); + + registerBeanDefinitionDecorator("set", new PropertyModifyingBeanDefinitionDecorator()); + registerBeanDefinitionDecorator("debug", new DebugBeanDefinitionDecorator()); + registerBeanDefinitionDecorator("nop", new NopInterceptorBeanDefinitionDecorator()); + registerBeanDefinitionDecoratorForAttribute("object-name", new ObjectNameBeanDefinitionDecorator()); + } + + private static class TestBeanDefinitionParser implements BeanDefinitionParser { + + public BeanDefinition parse(Element element, ParserContext parserContext) { + RootBeanDefinition definition = new RootBeanDefinition(); + definition.setBeanClass(TestBean.class); + + MutablePropertyValues mpvs = new MutablePropertyValues(); + mpvs.addPropertyValue("name", element.getAttribute("name")); + mpvs.addPropertyValue("age", element.getAttribute("age")); + definition.setPropertyValues(mpvs); + + parserContext.getRegistry().registerBeanDefinition(element.getAttribute("id"), definition); + + return null; + } + } + + private static final class PersonDefinitionParser extends AbstractSingleBeanDefinitionParser { + + protected Class getBeanClass(Element element) { + return TestBean.class; + } + + protected void doParse(Element element, BeanDefinitionBuilder builder) { + builder.addPropertyValue("name", element.getAttribute("name")); + builder.addPropertyValue("age", element.getAttribute("age")); + } + } + + private static class PropertyModifyingBeanDefinitionDecorator implements BeanDefinitionDecorator { + + public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { + Element element = (Element) node; + BeanDefinition def = definition.getBeanDefinition(); + + MutablePropertyValues mpvs = (def.getPropertyValues() == null) ? new MutablePropertyValues() : def.getPropertyValues(); + mpvs.addPropertyValue("name", element.getAttribute("name")); + mpvs.addPropertyValue("age", element.getAttribute("age")); + + ((AbstractBeanDefinition) def).setPropertyValues(mpvs); + return definition; + } + } + + private static class DebugBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator { + + protected BeanDefinition createInterceptorDefinition(Node node) { + return new RootBeanDefinition(DebugInterceptor.class); + } + } + + private static class NopInterceptorBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator { + + protected BeanDefinition createInterceptorDefinition(Node node) { + return new RootBeanDefinition(NopInterceptor.class); + } + } + + private static class ObjectNameBeanDefinitionDecorator implements BeanDefinitionDecorator { + + public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { + Attr objectNameAttribute = (Attr) node; + definition.getBeanDefinition().setAttribute("objectName", objectNameAttribute.getValue()); + return definition; + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.properties new file mode 100644 index 00000000000..fe0eca6f07c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.properties @@ -0,0 +1,2 @@ +http\://www.springframework.org/schema/beans/test=org.springframework.beans.factory.xml.support.TestNamespaceHandler +http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.xml new file mode 100644 index 00000000000..fdd268c8cdc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/customNamespace.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/invalid.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/invalid.properties new file mode 100644 index 00000000000..f0c6c392ba4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/invalid.properties @@ -0,0 +1 @@ +http\://www.springframework.org/schema/test=java.lang.String \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/nonExistent.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/nonExistent.properties new file mode 100644 index 00000000000..0944d907a31 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/nonExistent.properties @@ -0,0 +1 @@ +http\://www.springframework.org/schema/test=com.myapp.Foo \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/spring-test.xsd b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/spring-test.xsd new file mode 100644 index 00000000000..ccf71f6c8e6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/support/spring-test.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.properties new file mode 100644 index 00000000000..30d74d25844 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.properties @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.xml new file mode 100644 index 00000000000..e67e3101362 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/test.xml @@ -0,0 +1,127 @@ + + + + + + + + I have no properties and I'm happy without them. + + + + + + aliased + + + + + + + + aliased + + + + + + aliased + + + + + + + + + + + + + + Rod + 31 + + + + + + Roderick + + + + + Kerry + 34 + + + + + + Kathy + 28 + + + + + typeMismatch + 34x + + + + + + + + true + + + + true + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + listenerVeto + 66 + + + + + + this is a ]]> + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testUtilNamespace.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testUtilNamespace.xml new file mode 100644 index 00000000000..052e27965e7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testUtilNamespace.xml @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + My scoped Map + + + + + + + + + Rob Harrop + + + + My scoped List + Rob Harrop + + + + Rob Harrop + + + + My scoped Set + Rob Harrop + + + + + + foo + + + + + bar + + + + + + + bar + + + + + + + + + + + + + + + + + + + + + min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bar2 + + + + bar2 + + + + local + local2 + + + + local + local2 + + + + local + local2 + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNameInAlias.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNameInAlias.xml new file mode 100644 index 00000000000..cc049ed23cd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNameInAlias.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNames.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNames.xml new file mode 100644 index 00000000000..e991af7167a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/testWithDuplicateNames.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingObjects.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingObjects.xml new file mode 100644 index 00000000000..19faed79258 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingObjects.xml @@ -0,0 +1,14 @@ + + + + + + + 33 + Rod + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingSimple.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingSimple.xml new file mode 100644 index 00000000000..df21ad72626 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedAllDependencyCheckMissingSimple.xml @@ -0,0 +1,16 @@ + + + + + + + tony + --> + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedObjectDependencyCheck.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedObjectDependencyCheck.xml new file mode 100644 index 00000000000..f18e9e77c29 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedObjectDependencyCheck.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedSimpleDependencyCheck.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedSimpleDependencyCheck.xml new file mode 100644 index 00000000000..8463f132a12 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/unsatisfiedSimpleDependencyCheck.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithDtd.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithDtd.xml new file mode 100644 index 00000000000..91fdcd879f2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithDtd.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithXsd.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithXsd.xml new file mode 100644 index 00000000000..cb08194ade8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/validateWithXsd.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/withMeta.xml b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/withMeta.xml new file mode 100644 index 00000000000..3b8d004cd5f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/factory/xml/withMeta.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java new file mode 100644 index 00000000000..9be6a107f39 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +import junit.framework.TestCase; + +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.FatalBeanException; +import org.springframework.core.JdkVersion; +import org.springframework.util.Assert; + +/** + * @author Juergen Hoeller + * @since 06.03.2006 + */ +public class BeanInfoTests extends TestCase { + + public void testComplexObject() { + ValueBean bean = new ValueBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + Integer value = new Integer(1); + + bw.setPropertyValue("value", value); + assertEquals("value not set correctly", bean.getValue(), value); + + value = new Integer(2); + bw.setPropertyValue("value", value.toString()); + assertEquals("value not converted", bean.getValue(), value); + + bw.setPropertyValue("value", null); + assertNull("value not null", bean.getValue()); + + bw.setPropertyValue("value", ""); + assertNull("value not converted to null", bean.getValue()); + } + + + public static class ValueBean { + + private Integer value; + + public Integer getValue() { + return value; + } + + public void setValue(Integer value) { + this.value = value; + } + } + + + public static class ValueBeanBeanInfo extends SimpleBeanInfo { + + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor pd = new PropertyDescriptor("value", ValueBean.class); + pd.setPropertyEditorClass(MyNumberEditor.class); + return new PropertyDescriptor[] {pd}; + } + catch (IntrospectionException ex) { + throw new FatalBeanException("Couldn't create PropertyDescriptor", ex); + } + } + } + + + public static class MyNumberEditor extends CustomNumberEditor { + + private Object target; + + public MyNumberEditor() throws IllegalArgumentException { + super(Integer.class, true); + } + + public MyNumberEditor(Object target) throws IllegalArgumentException { + super(Integer.class, true); + this.target = target; + } + + public void setAsText(String text) throws IllegalArgumentException { + if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) { + Assert.isTrue(this.target instanceof ValueBean, "Target must be available on JDK 1.5+"); + } + super.setAsText(text); + } + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ByteArrayPropertyEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ByteArrayPropertyEditorTests.java new file mode 100644 index 00000000000..7c8ab4a56fe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ByteArrayPropertyEditorTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import junit.framework.TestCase; + +import java.beans.PropertyEditor; + +/** + * Unit tests for the {@link ByteArrayPropertyEditor} class. + * + * @author Rick Evans + */ +public final class ByteArrayPropertyEditorTests extends TestCase { + + public void testSunnyDaySetAsText() throws Exception { + final String text = "Hideous towns make me throw... up"; + + PropertyEditor byteEditor = new ByteArrayPropertyEditor(); + byteEditor.setAsText(text); + + Object value = byteEditor.getValue(); + assertNotNull(value); + assertTrue(value instanceof byte[]); + byte[] bytes = (byte[]) value; + for (int i = 0; i < text.length(); ++i) { + assertEquals("cyte[] differs at index '" + i + "'", text.charAt(i), bytes[i]); + } + assertEquals(text, byteEditor.getAsText()); + } + + public void testGetAsTextReturnsEmptyStringIfValueIsNull() throws Exception { + PropertyEditor byteEditor = new ByteArrayPropertyEditor(); + assertEquals("", byteEditor.getAsText()); + + byteEditor.setAsText(null); + assertEquals("", byteEditor.getAsText()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CharArrayPropertyEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CharArrayPropertyEditorTests.java new file mode 100644 index 00000000000..3f28d1c2512 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CharArrayPropertyEditorTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import junit.framework.TestCase; + +import java.beans.PropertyEditor; + +/** + * Unit tests for the {@link CharArrayPropertyEditor} class. + * + * @author Rick Evans + */ +public final class CharArrayPropertyEditorTests extends TestCase { + + public void testSunnyDaySetAsText() throws Exception { + final String text = "Hideous towns make me throw... up"; + + PropertyEditor charEditor = new CharArrayPropertyEditor(); + charEditor.setAsText(text); + + Object value = charEditor.getValue(); + assertNotNull(value); + assertTrue(value instanceof char[]); + char[] chars = (char[]) value; + for (int i = 0; i < text.length(); ++i) { + assertEquals("char[] differs at index '" + i + "'", text.charAt(i), chars[i]); + } + assertEquals(text, charEditor.getAsText()); + } + + public void testGetAsTextReturnsEmptyStringIfValueIsNull() throws Exception { + PropertyEditor charEditor = new CharArrayPropertyEditor(); + assertEquals("", charEditor.getAsText()); + + charEditor.setAsText(null); + assertEquals("", charEditor.getAsText()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java new file mode 100644 index 00000000000..87ace2d0787 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java @@ -0,0 +1,98 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collection; + +/** + * Unit tests for the {@link CustomCollectionEditor} class. + * + * @author Rick Evans + */ +public final class CustomCollectionEditorTests extends TestCase { + + public void testCtorWithNullCollectionType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new CustomCollectionEditor(null); + } + }.runTest(); + } + + public void testCtorWithNonCollectionType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new CustomCollectionEditor(String.class); + } + }.runTest(); + } + + public void testWithCollectionTypeThatDoesNotExposeAPublicNoArgCtor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + CustomCollectionEditor editor = new CustomCollectionEditor(CollectionTypeWithNoNoArgCtor.class); + editor.setValue("1"); + } + }.runTest(); + } + + public void testSunnyDaySetValue() throws Exception { + CustomCollectionEditor editor = new CustomCollectionEditor(ArrayList.class); + editor.setValue(new int[] {0, 1, 2}); + Object value = editor.getValue(); + assertNotNull(value); + assertTrue(value instanceof ArrayList); + List list = (List) value; + assertEquals("There must be 3 elements in the converted collection", 3, list.size()); + assertEquals(new Integer(0), list.get(0)); + assertEquals(new Integer(1), list.get(1)); + assertEquals(new Integer(2), list.get(2)); + } + + public void testWhenTargetTypeIsExactlyTheCollectionInterfaceUsesFallbackCollectionType() throws Exception { + CustomCollectionEditor editor = new CustomCollectionEditor(Collection.class); + editor.setValue("0, 1, 2"); + Collection value = (Collection) editor.getValue(); + assertNotNull(value); + assertEquals("There must be 1 element in the converted collection", 1, value.size()); + assertEquals("0, 1, 2", value.iterator().next()); + } + + public void testSunnyDaySetAsTextYieldsSingleValue() throws Exception { + CustomCollectionEditor editor = new CustomCollectionEditor(ArrayList.class); + editor.setValue("0, 1, 2"); + Object value = editor.getValue(); + assertNotNull(value); + assertTrue(value instanceof ArrayList); + List list = (List) value; + assertEquals("There must be 1 element in the converted collection", 1, list.size()); + assertEquals("0, 1, 2", list.get(0)); + } + + + private static final class CollectionTypeWithNoNoArgCtor extends ArrayList { + + public CollectionTypeWithNoNoArgCtor(String anArg) { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java new file mode 100644 index 00000000000..cf2e3922175 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java @@ -0,0 +1,1492 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import java.beans.PropertyEditor; +import java.beans.PropertyEditorSupport; +import java.beans.PropertyVetoException; +import java.io.File; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.regex.Pattern; + +import junit.framework.TestCase; + +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.BeansException; +import org.springframework.beans.BooleanTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.NumberTestBean; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.TestBean; +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the various PropertyEditors in Spring. + * + * @author Juergen Hoeller + * @author Rick Evans + * @author Rob Harrop + * @author Arjen Poutsma + * + * @since 10.06.2003 + */ +public class CustomEditorTests extends TestCase { + + public void testComplexObject() { + TestBean tb = new TestBean(); + String newName = "Rod"; + String tbString = "Kerry_34"; + + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(ITestBean.class, new TestBeanEditor()); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("age", new Integer(55))); + pvs.addPropertyValue(new PropertyValue("name", newName)); + pvs.addPropertyValue(new PropertyValue("touchy", "valid")); + pvs.addPropertyValue(new PropertyValue("spouse", tbString)); + bw.setPropertyValues(pvs); + assertTrue("spouse is non-null", tb.getSpouse() != null); + assertTrue("spouse name is Kerry and age is 34", + tb.getSpouse().getName().equals("Kerry") && tb.getSpouse().getAge() == 34); + } + + public void testComplexObjectWithOldValueAccess() { + TestBean tb = new TestBean(); + String newName = "Rod"; + String tbString = "Kerry_34"; + + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.setExtractOldValueForEditor(true); + bw.registerCustomEditor(ITestBean.class, new OldValueAccessingTestBeanEditor()); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("age", new Integer(55))); + pvs.addPropertyValue(new PropertyValue("name", newName)); + pvs.addPropertyValue(new PropertyValue("touchy", "valid")); + pvs.addPropertyValue(new PropertyValue("spouse", tbString)); + + bw.setPropertyValues(pvs); + assertTrue("spouse is non-null", tb.getSpouse() != null); + assertTrue("spouse name is Kerry and age is 34", + tb.getSpouse().getName().equals("Kerry") && tb.getSpouse().getAge() == 34); + ITestBean spouse = tb.getSpouse(); + + bw.setPropertyValues(pvs); + assertSame("Should have remained same object", spouse, tb.getSpouse()); + } + + public void testCustomEditorForSingleProperty() { + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, "name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix" + text); + } + }); + bw.setPropertyValue("name", "value"); + bw.setPropertyValue("touchy", "value"); + assertEquals("prefixvalue", bw.getPropertyValue("name")); + assertEquals("prefixvalue", tb.getName()); + assertEquals("value", bw.getPropertyValue("touchy")); + assertEquals("value", tb.getTouchy()); + } + + public void testCustomEditorForAllStringProperties() { + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix" + text); + } + }); + bw.setPropertyValue("name", "value"); + bw.setPropertyValue("touchy", "value"); + assertEquals("prefixvalue", bw.getPropertyValue("name")); + assertEquals("prefixvalue", tb.getName()); + assertEquals("prefixvalue", bw.getPropertyValue("touchy")); + assertEquals("prefixvalue", tb.getTouchy()); + } + + public void testCustomEditorForSingleNestedProperty() { + TestBean tb = new TestBean(); + tb.setSpouse(new TestBean()); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, "spouse.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix" + text); + } + }); + bw.setPropertyValue("spouse.name", "value"); + bw.setPropertyValue("touchy", "value"); + assertEquals("prefixvalue", bw.getPropertyValue("spouse.name")); + assertEquals("prefixvalue", tb.getSpouse().getName()); + assertEquals("value", bw.getPropertyValue("touchy")); + assertEquals("value", tb.getTouchy()); + } + + public void testCustomEditorForAllNestedStringProperties() { + TestBean tb = new TestBean(); + tb.setSpouse(new TestBean()); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix" + text); + } + }); + bw.setPropertyValue("spouse.name", "value"); + bw.setPropertyValue("touchy", "value"); + assertEquals("prefixvalue", bw.getPropertyValue("spouse.name")); + assertEquals("prefixvalue", tb.getSpouse().getName()); + assertEquals("prefixvalue", bw.getPropertyValue("touchy")); + assertEquals("prefixvalue", tb.getTouchy()); + } + + public void testDefaultBooleanEditorForPrimitiveType() { + BooleanTestBean tb = new BooleanTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + + bw.setPropertyValue("bool1", "true"); + assertTrue("Correct bool1 value", Boolean.TRUE.equals(bw.getPropertyValue("bool1"))); + assertTrue("Correct bool1 value", tb.isBool1()); + + bw.setPropertyValue("bool1", "false"); + assertTrue("Correct bool1 value", Boolean.FALSE.equals(bw.getPropertyValue("bool1"))); + assertTrue("Correct bool1 value", !tb.isBool1()); + + bw.setPropertyValue("bool1", " true "); + assertTrue("Correct bool1 value", tb.isBool1()); + + bw.setPropertyValue("bool1", " false "); + assertTrue("Correct bool1 value", !tb.isBool1()); + + bw.setPropertyValue("bool1", "on"); + assertTrue("Correct bool1 value", tb.isBool1()); + + bw.setPropertyValue("bool1", "off"); + assertTrue("Correct bool1 value", !tb.isBool1()); + + bw.setPropertyValue("bool1", "yes"); + assertTrue("Correct bool1 value", tb.isBool1()); + + bw.setPropertyValue("bool1", "no"); + assertTrue("Correct bool1 value", !tb.isBool1()); + + bw.setPropertyValue("bool1", "1"); + assertTrue("Correct bool1 value", tb.isBool1()); + + bw.setPropertyValue("bool1", "0"); + assertTrue("Correct bool1 value", !tb.isBool1()); + + try { + bw.setPropertyValue("bool1", "argh"); + fail("Should have thrown BeansException"); + } + catch (BeansException ex) { + // expected + } + } + + public void testDefaultBooleanEditorForWrapperType() { + BooleanTestBean tb = new BooleanTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + + bw.setPropertyValue("bool2", "true"); + assertTrue("Correct bool2 value", Boolean.TRUE.equals(bw.getPropertyValue("bool2"))); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "false"); + assertTrue("Correct bool2 value", Boolean.FALSE.equals(bw.getPropertyValue("bool2"))); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "on"); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "off"); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "yes"); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "no"); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "1"); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "0"); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", ""); + assertNull("Correct bool2 value", tb.getBool2()); + } + + public void testCustomBooleanEditorWithAllowEmpty() { + BooleanTestBean tb = new BooleanTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(Boolean.class, new CustomBooleanEditor(true)); + + bw.setPropertyValue("bool2", "true"); + assertTrue("Correct bool2 value", Boolean.TRUE.equals(bw.getPropertyValue("bool2"))); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "false"); + assertTrue("Correct bool2 value", Boolean.FALSE.equals(bw.getPropertyValue("bool2"))); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "on"); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "off"); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "yes"); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "no"); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "1"); + assertTrue("Correct bool2 value", tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", "0"); + assertTrue("Correct bool2 value", !tb.getBool2().booleanValue()); + + bw.setPropertyValue("bool2", ""); + assertTrue("Correct bool2 value", bw.getPropertyValue("bool2") == null); + assertTrue("Correct bool2 value", tb.getBool2() == null); + } + + public void testCustomBooleanEditorWithSpecialTrueAndFalseStrings() throws Exception { + final String trueString = "pechorin"; + final String falseString = "nash"; + + CustomBooleanEditor editor = new CustomBooleanEditor(trueString, falseString, false); + + editor.setAsText(trueString); + assertTrue(((Boolean) editor.getValue()).booleanValue()); + assertEquals(trueString, editor.getAsText()); + editor.setAsText(falseString); + assertFalse(((Boolean) editor.getValue()).booleanValue()); + assertEquals(falseString, editor.getAsText()); + + editor.setAsText(trueString.toUpperCase()); + assertTrue(((Boolean) editor.getValue()).booleanValue()); + assertEquals(trueString, editor.getAsText()); + editor.setAsText(falseString.toUpperCase()); + assertFalse(((Boolean) editor.getValue()).booleanValue()); + assertEquals(falseString, editor.getAsText()); + } + + public void testDefaultNumberEditor() { + NumberTestBean tb = new NumberTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + + bw.setPropertyValue("short1", "1"); + bw.setPropertyValue("short2", "2"); + bw.setPropertyValue("int1", "7"); + bw.setPropertyValue("int2", "8"); + bw.setPropertyValue("long1", "5"); + bw.setPropertyValue("long2", "6"); + bw.setPropertyValue("bigInteger", "3"); + bw.setPropertyValue("float1", "7.1"); + bw.setPropertyValue("float2", "8.1"); + bw.setPropertyValue("double1", "5.1"); + bw.setPropertyValue("double2", "6.1"); + bw.setPropertyValue("bigDecimal", "4.5"); + + assertTrue("Correct short1 value", new Short("1").equals(bw.getPropertyValue("short1"))); + assertTrue("Correct short1 value", tb.getShort1() == 1); + assertTrue("Correct short2 value", new Short("2").equals(bw.getPropertyValue("short2"))); + assertTrue("Correct short2 value", new Short("2").equals(tb.getShort2())); + assertTrue("Correct int1 value", new Integer("7").equals(bw.getPropertyValue("int1"))); + assertTrue("Correct int1 value", tb.getInt1() == 7); + assertTrue("Correct int2 value", new Integer("8").equals(bw.getPropertyValue("int2"))); + assertTrue("Correct int2 value", new Integer("8").equals(tb.getInt2())); + assertTrue("Correct long1 value", new Long("5").equals(bw.getPropertyValue("long1"))); + assertTrue("Correct long1 value", tb.getLong1() == 5); + assertTrue("Correct long2 value", new Long("6").equals(bw.getPropertyValue("long2"))); + assertTrue("Correct long2 value", new Long("6").equals(tb.getLong2())); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(bw.getPropertyValue("bigInteger"))); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(tb.getBigInteger())); + assertTrue("Correct float1 value", new Float("7.1").equals(bw.getPropertyValue("float1"))); + assertTrue("Correct float1 value", new Float("7.1").equals(new Float(tb.getFloat1()))); + assertTrue("Correct float2 value", new Float("8.1").equals(bw.getPropertyValue("float2"))); + assertTrue("Correct float2 value", new Float("8.1").equals(tb.getFloat2())); + assertTrue("Correct double1 value", new Double("5.1").equals(bw.getPropertyValue("double1"))); + assertTrue("Correct double1 value", tb.getDouble1() == 5.1); + assertTrue("Correct double2 value", new Double("6.1").equals(bw.getPropertyValue("double2"))); + assertTrue("Correct double2 value", new Double("6.1").equals(tb.getDouble2())); + assertTrue("Correct bigDecimal value", new BigDecimal("4.5").equals(bw.getPropertyValue("bigDecimal"))); + assertTrue("Correct bigDecimal value", new BigDecimal("4.5").equals(tb.getBigDecimal())); + } + + public void testCustomNumberEditorWithoutAllowEmpty() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN); + NumberTestBean tb = new NumberTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(short.class, new CustomNumberEditor(Short.class, nf, false)); + bw.registerCustomEditor(Short.class, new CustomNumberEditor(Short.class, nf, false)); + bw.registerCustomEditor(int.class, new CustomNumberEditor(Integer.class, nf, false)); + bw.registerCustomEditor(Integer.class, new CustomNumberEditor(Integer.class, nf, false)); + bw.registerCustomEditor(long.class, new CustomNumberEditor(Long.class, nf, false)); + bw.registerCustomEditor(Long.class, new CustomNumberEditor(Long.class, nf, false)); + bw.registerCustomEditor(BigInteger.class, new CustomNumberEditor(BigInteger.class, nf, false)); + bw.registerCustomEditor(float.class, new CustomNumberEditor(Float.class, nf, false)); + bw.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, nf, false)); + bw.registerCustomEditor(double.class, new CustomNumberEditor(Double.class, nf, false)); + bw.registerCustomEditor(Double.class, new CustomNumberEditor(Double.class, nf, false)); + bw.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, nf, false)); + + bw.setPropertyValue("short1", "1"); + bw.setPropertyValue("short2", "2"); + bw.setPropertyValue("int1", "7"); + bw.setPropertyValue("int2", "8"); + bw.setPropertyValue("long1", "5"); + bw.setPropertyValue("long2", "6"); + bw.setPropertyValue("bigInteger", "3"); + bw.setPropertyValue("float1", "7,1"); + bw.setPropertyValue("float2", "8,1"); + bw.setPropertyValue("double1", "5,1"); + bw.setPropertyValue("double2", "6,1"); + bw.setPropertyValue("bigDecimal", "4,5"); + + assertTrue("Correct short1 value", new Short("1").equals(bw.getPropertyValue("short1"))); + assertTrue("Correct short1 value", tb.getShort1() == 1); + assertTrue("Correct short2 value", new Short("2").equals(bw.getPropertyValue("short2"))); + assertTrue("Correct short2 value", new Short("2").equals(tb.getShort2())); + assertTrue("Correct int1 value", new Integer("7").equals(bw.getPropertyValue("int1"))); + assertTrue("Correct int1 value", tb.getInt1() == 7); + assertTrue("Correct int2 value", new Integer("8").equals(bw.getPropertyValue("int2"))); + assertTrue("Correct int2 value", new Integer("8").equals(tb.getInt2())); + assertTrue("Correct long1 value", new Long("5").equals(bw.getPropertyValue("long1"))); + assertTrue("Correct long1 value", tb.getLong1() == 5); + assertTrue("Correct long2 value", new Long("6").equals(bw.getPropertyValue("long2"))); + assertTrue("Correct long2 value", new Long("6").equals(tb.getLong2())); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(bw.getPropertyValue("bigInteger"))); + assertTrue("Correct bigInteger value", new BigInteger("3").equals(tb.getBigInteger())); + assertTrue("Correct float1 value", new Float("7.1").equals(bw.getPropertyValue("float1"))); + assertTrue("Correct float1 value", new Float("7.1").equals(new Float(tb.getFloat1()))); + assertTrue("Correct float2 value", new Float("8.1").equals(bw.getPropertyValue("float2"))); + assertTrue("Correct float2 value", new Float("8.1").equals(tb.getFloat2())); + assertTrue("Correct double1 value", new Double("5.1").equals(bw.getPropertyValue("double1"))); + assertTrue("Correct double1 value", tb.getDouble1() == 5.1); + assertTrue("Correct double2 value", new Double("6.1").equals(bw.getPropertyValue("double2"))); + assertTrue("Correct double2 value", new Double("6.1").equals(tb.getDouble2())); + assertTrue("Correct bigDecimal value", new BigDecimal("4.5").equals(bw.getPropertyValue("bigDecimal"))); + assertTrue("Correct bigDecimal value", new BigDecimal("4.5").equals(tb.getBigDecimal())); + } + + public void testCustomNumberEditorCtorWithNullNumberType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new CustomNumberEditor(null, true); + } + }.runTest(); + } + + public void testCustomNumberEditorCtorWithNonNumberType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new CustomNumberEditor(String.class, true); + } + }.runTest(); + } + + public void testCustomNumberEditorWithAllowEmpty() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN); + NumberTestBean tb = new NumberTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(long.class, new CustomNumberEditor(Long.class, nf, true)); + bw.registerCustomEditor(Long.class, new CustomNumberEditor(Long.class, nf, true)); + + bw.setPropertyValue("long1", "5"); + bw.setPropertyValue("long2", "6"); + assertTrue("Correct long1 value", new Long("5").equals(bw.getPropertyValue("long1"))); + assertTrue("Correct long1 value", tb.getLong1() == 5); + assertTrue("Correct long2 value", new Long("6").equals(bw.getPropertyValue("long2"))); + assertTrue("Correct long2 value", new Long("6").equals(tb.getLong2())); + + bw.setPropertyValue("long2", ""); + assertTrue("Correct long2 value", bw.getPropertyValue("long2") == null); + assertTrue("Correct long2 value", tb.getLong2() == null); + + try { + bw.setPropertyValue("long1", ""); + fail("Should have thrown BeansException"); + } + catch (BeansException ex) { + // expected + assertTrue("Correct long1 value", new Long("5").equals(bw.getPropertyValue("long1"))); + assertTrue("Correct long1 value", tb.getLong1() == 5); + } + } + + public void testCustomNumberEditorWithFrenchBigDecimal() throws Exception { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.FRENCH); + NumberTestBean tb = new NumberTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, nf, true)); + bw.setPropertyValue("bigDecimal", "1000"); + assertEquals(1000.0f, tb.getBigDecimal().floatValue(), 0f); + bw.setPropertyValue("bigDecimal", "1000,5"); + assertEquals(1000.5f, tb.getBigDecimal().floatValue(), 0f); + bw.setPropertyValue("bigDecimal", "1 000,5"); + assertEquals(1000.5f, tb.getBigDecimal().floatValue(), 0f); + } + + public void testParseShortGreaterThanMaxValueWithoutNumberFormat() { + new AssertThrows(NumberFormatException.class, Short.MAX_VALUE + 1 + " is greater than max value") { + public void test() throws Exception { + CustomNumberEditor editor = new CustomNumberEditor(Short.class, true); + editor.setAsText(String.valueOf(Short.MAX_VALUE + 1)); + } + }.runTest(); + } + + public void testByteArrayPropertyEditor() { + PrimitiveArrayBean bean = new PrimitiveArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.setPropertyValue("byteArray", "myvalue"); + assertEquals("myvalue", new String(bean.getByteArray())); + } + + public void testCharArrayPropertyEditor() { + PrimitiveArrayBean bean = new PrimitiveArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.setPropertyValue("charArray", "myvalue"); + assertEquals("myvalue", new String(bean.getCharArray())); + } + + public void testCharacterEditor() { + CharBean cb = new CharBean(); + BeanWrapper bw = new BeanWrapperImpl(cb); + + bw.setPropertyValue("myChar", new Character('c')); + assertEquals('c', cb.getMyChar()); + + bw.setPropertyValue("myChar", "c"); + assertEquals('c', cb.getMyChar()); + + bw.setPropertyValue("myChar", "\u0041"); + assertEquals('A', cb.getMyChar()); + + bw.setPropertyValue("myChar", "\\u0022"); + assertEquals('"', cb.getMyChar()); + + CharacterEditor editor = new CharacterEditor(false); + editor.setAsText("M"); + assertEquals("M", editor.getAsText()); + } + + public void testCharacterEditorWithAllowEmpty() { + CharBean cb = new CharBean(); + BeanWrapper bw = new BeanWrapperImpl(cb); + bw.registerCustomEditor(Character.class, new CharacterEditor(true)); + + bw.setPropertyValue("myCharacter", new Character('c')); + assertEquals(new Character('c'), cb.getMyCharacter()); + + bw.setPropertyValue("myCharacter", "c"); + assertEquals(new Character('c'), cb.getMyCharacter()); + + bw.setPropertyValue("myCharacter", "\u0041"); + assertEquals(new Character('A'), cb.getMyCharacter()); + + bw.setPropertyValue("myCharacter", " "); + assertEquals(new Character(' '), cb.getMyCharacter()); + + bw.setPropertyValue("myCharacter", ""); + assertNull(cb.getMyCharacter()); + } + + public void testCharacterEditorSetAsTextWithStringLongerThanOneCharacter() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PropertyEditor charEditor = new CharacterEditor(false); + charEditor.setAsText("ColdWaterCanyon"); + } + }.runTest(); + } + + public void testCharacterEditorGetAsTextReturnsEmptyStringIfValueIsNull() throws Exception { + PropertyEditor charEditor = new CharacterEditor(false); + assertEquals("", charEditor.getAsText()); + charEditor = new CharacterEditor(true); + charEditor.setAsText(null); + assertEquals("", charEditor.getAsText()); + charEditor.setAsText(""); + assertEquals("", charEditor.getAsText()); + charEditor.setAsText(" "); + assertEquals(" ", charEditor.getAsText()); + } + + public void testCharacterEditorSetAsTextWithNullNotAllowingEmptyAsNull() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PropertyEditor charEditor = new CharacterEditor(false); + charEditor.setAsText(null); + } + }.runTest(); + } + + public void testClassEditor() { + PropertyEditor classEditor = new ClassEditor(); + classEditor.setAsText("org.springframework.beans.TestBean"); + assertEquals(TestBean.class, classEditor.getValue()); + assertEquals("org.springframework.beans.TestBean", classEditor.getAsText()); + + classEditor.setAsText(null); + assertEquals("", classEditor.getAsText()); + classEditor.setAsText(""); + assertEquals("", classEditor.getAsText()); + classEditor.setAsText("\t "); + assertEquals("", classEditor.getAsText()); + } + + public void testClassEditorWithNonExistentClass() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PropertyEditor classEditor = new ClassEditor(); + classEditor.setAsText("hairdresser.on.Fire"); + } + }.runTest(); + } + + public void testClassEditorWithArray() { + PropertyEditor classEditor = new ClassEditor(); + classEditor.setAsText("org.springframework.beans.TestBean[]"); + assertEquals(TestBean[].class, classEditor.getValue()); + assertEquals("org.springframework.beans.TestBean[]", classEditor.getAsText()); + } + + /* + * SPR_2165 - ClassEditor is inconsistent with multidimensional arrays + */ + public void testGetAsTextWithTwoDimensionalArray() throws Exception { + String[][] chessboard = new String[8][8]; + ClassEditor editor = new ClassEditor(); + editor.setValue(chessboard.getClass()); + assertEquals("java.lang.String[][]", editor.getAsText()); + } + + /* + * SPR_2165 - ClassEditor is inconsistent with multidimensional arrays + */ + public void testGetAsTextWithRidiculousMultiDimensionalArray() throws Exception { + String[][][][][] ridiculousChessboard = new String[8][4][0][1][3]; + ClassEditor editor = new ClassEditor(); + editor.setValue(ridiculousChessboard.getClass()); + assertEquals("java.lang.String[][][][][]", editor.getAsText()); + } + + public void testFileEditor() { + PropertyEditor fileEditor = new FileEditor(); + fileEditor.setAsText("file:myfile.txt"); + assertEquals(new File("myfile.txt"), fileEditor.getValue()); + assertEquals((new File("myfile.txt")).getPath(), fileEditor.getAsText()); + } + + public void testFileEditorWithRelativePath() { + PropertyEditor fileEditor = new FileEditor(); + try { + fileEditor.setAsText("myfile.txt"); + } + catch (IllegalArgumentException ex) { + // expected: should get resolved as class path resource, + // and there is no such resource in the class path... + } + } + + public void testFileEditorWithAbsolutePath() { + PropertyEditor fileEditor = new FileEditor(); + // testing on Windows + if (new File("C:/myfile.txt").isAbsolute()) { + fileEditor.setAsText("C:/myfile.txt"); + assertEquals(new File("C:/myfile.txt"), fileEditor.getValue()); + } + // testing on Unix + if (new File("/myfile.txt").isAbsolute()) { + fileEditor.setAsText("/myfile.txt"); + assertEquals(new File("/myfile.txt"), fileEditor.getValue()); + } + } + + public void testLocaleEditor() { + PropertyEditor localeEditor = new LocaleEditor(); + localeEditor.setAsText("en_CA"); + assertEquals(Locale.CANADA, localeEditor.getValue()); + assertEquals("en_CA", localeEditor.getAsText()); + + localeEditor = new LocaleEditor(); + assertEquals("", localeEditor.getAsText()); + } + + public void testPatternEditor() { + final String REGEX = "a.*"; + + PropertyEditor patternEditor = new PatternEditor(); + patternEditor.setAsText(REGEX); + assertEquals(Pattern.compile(REGEX).pattern(), ((Pattern) patternEditor.getValue()).pattern()); + assertEquals(REGEX, patternEditor.getAsText()); + + patternEditor = new PatternEditor(); + assertEquals("", patternEditor.getAsText()); + + patternEditor = new PatternEditor(); + patternEditor.setAsText(null); + assertEquals("", patternEditor.getAsText()); + } + + public void testCustomBooleanEditor() { + CustomBooleanEditor editor = new CustomBooleanEditor(false); + editor.setAsText("true"); + assertEquals(Boolean.TRUE, editor.getValue()); + assertEquals("true", editor.getAsText()); + editor.setAsText("false"); + assertEquals(Boolean.FALSE, editor.getValue()); + assertEquals("false", editor.getAsText()); + editor.setValue(null); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testCustomBooleanEditorWithEmptyAsNull() { + CustomBooleanEditor editor = new CustomBooleanEditor(true); + editor.setAsText("true"); + assertEquals(Boolean.TRUE, editor.getValue()); + assertEquals("true", editor.getAsText()); + editor.setAsText("false"); + assertEquals(Boolean.FALSE, editor.getValue()); + assertEquals("false", editor.getAsText()); + editor.setValue(null); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testCustomDateEditor() { + CustomDateEditor editor = new CustomDateEditor(null, false); + editor.setValue(null); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testCustomDateEditorWithEmptyAsNull() { + CustomDateEditor editor = new CustomDateEditor(null, true); + editor.setValue(null); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testCustomDateEditorWithExactDateLength() { + int maxLength = 10; + String validDate = "01/01/2005"; + String invalidDate = "01/01/05"; + + assertTrue(validDate.length() == maxLength); + assertFalse(invalidDate.length() == maxLength); + + CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("MM/dd/yyyy"), true, maxLength); + + try { + editor.setAsText(validDate); + } + catch (IllegalArgumentException ex) { + fail("Exception shouldn't be thrown because this is a valid date"); + } + + try { + editor.setAsText(invalidDate); + fail("Exception should be thrown because this is an invalid date"); + } + catch (IllegalArgumentException ex) { + // expected + assertTrue(ex.getMessage().indexOf("10") != -1); + } + } + + public void testCustomNumberEditor() { + CustomNumberEditor editor = new CustomNumberEditor(Integer.class, false); + editor.setAsText("5"); + assertEquals(new Integer(5), editor.getValue()); + assertEquals("5", editor.getAsText()); + editor.setValue(null); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testCustomNumberEditorWithHex() { + CustomNumberEditor editor = new CustomNumberEditor(Integer.class, false); + editor.setAsText("0x" + Integer.toHexString(64)); + assertEquals(new Integer(64), editor.getValue()); + } + + public void testCustomNumberEditorWithEmptyAsNull() { + CustomNumberEditor editor = new CustomNumberEditor(Integer.class, true); + editor.setAsText("5"); + assertEquals(new Integer(5), editor.getValue()); + assertEquals("5", editor.getAsText()); + editor.setAsText(""); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + editor.setValue(null); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testStringTrimmerEditor() { + StringTrimmerEditor editor = new StringTrimmerEditor(false); + editor.setAsText("test"); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(" test "); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(""); + assertEquals("", editor.getValue()); + assertEquals("", editor.getAsText()); + editor.setValue(null); + assertEquals("", editor.getAsText()); + editor.setAsText(null); + assertEquals("", editor.getAsText()); + } + + public void testStringTrimmerEditorWithEmptyAsNull() { + StringTrimmerEditor editor = new StringTrimmerEditor(true); + editor.setAsText("test"); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(" test "); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(" "); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + editor.setValue(null); + assertEquals("", editor.getAsText()); + } + + public void testStringTrimmerEditorWithCharsToDelete() { + StringTrimmerEditor editor = new StringTrimmerEditor("\r\n\f", false); + editor.setAsText("te\ns\ft"); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(" test "); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(""); + assertEquals("", editor.getValue()); + assertEquals("", editor.getAsText()); + editor.setValue(null); + assertEquals("", editor.getAsText()); + } + + public void testStringTrimmerEditorWithCharsToDeleteAndEmptyAsNull() { + StringTrimmerEditor editor = new StringTrimmerEditor("\r\n\f", true); + editor.setAsText("te\ns\ft"); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(" test "); + assertEquals("test", editor.getValue()); + assertEquals("test", editor.getAsText()); + editor.setAsText(" \n\f "); + assertEquals(null, editor.getValue()); + assertEquals("", editor.getAsText()); + editor.setValue(null); + assertEquals("", editor.getAsText()); + } + + public void testIndexedPropertiesWithCustomEditorForType() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(String.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix" + text); + } + }); + TestBean tb0 = bean.getArray()[0]; + TestBean tb1 = bean.getArray()[1]; + TestBean tb2 = ((TestBean) bean.getList().get(0)); + TestBean tb3 = ((TestBean) bean.getList().get(1)); + TestBean tb4 = ((TestBean) bean.getMap().get("key1")); + TestBean tb5 = ((TestBean) bean.getMap().get("key2")); + assertEquals("name0", tb0.getName()); + assertEquals("name1", tb1.getName()); + assertEquals("name2", tb2.getName()); + assertEquals("name3", tb3.getName()); + assertEquals("name4", tb4.getName()); + assertEquals("name5", tb5.getName()); + assertEquals("name0", bw.getPropertyValue("array[0].name")); + assertEquals("name1", bw.getPropertyValue("array[1].name")); + assertEquals("name2", bw.getPropertyValue("list[0].name")); + assertEquals("name3", bw.getPropertyValue("list[1].name")); + assertEquals("name4", bw.getPropertyValue("map[key1].name")); + assertEquals("name5", bw.getPropertyValue("map[key2].name")); + assertEquals("name4", bw.getPropertyValue("map['key1'].name")); + assertEquals("name5", bw.getPropertyValue("map[\"key2\"].name")); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].name", "name5"); + pvs.addPropertyValue("array[1].name", "name4"); + pvs.addPropertyValue("list[0].name", "name3"); + pvs.addPropertyValue("list[1].name", "name2"); + pvs.addPropertyValue("map[key1].name", "name1"); + pvs.addPropertyValue("map['key2'].name", "name0"); + bw.setPropertyValues(pvs); + assertEquals("prefixname5", tb0.getName()); + assertEquals("prefixname4", tb1.getName()); + assertEquals("prefixname3", tb2.getName()); + assertEquals("prefixname2", tb3.getName()); + assertEquals("prefixname1", tb4.getName()); + assertEquals("prefixname0", tb5.getName()); + assertEquals("prefixname5", bw.getPropertyValue("array[0].name")); + assertEquals("prefixname4", bw.getPropertyValue("array[1].name")); + assertEquals("prefixname3", bw.getPropertyValue("list[0].name")); + assertEquals("prefixname2", bw.getPropertyValue("list[1].name")); + assertEquals("prefixname1", bw.getPropertyValue("map[\"key1\"].name")); + assertEquals("prefixname0", bw.getPropertyValue("map['key2'].name")); + } + + public void testIndexedPropertiesWithCustomEditorForProperty() { + IndexedTestBean bean = new IndexedTestBean(false); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(String.class, "array.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("array" + text); + } + }); + bw.registerCustomEditor(String.class, "list.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list" + text); + } + }); + bw.registerCustomEditor(String.class, "map.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("map" + text); + } + }); + bean.populate(); + + TestBean tb0 = bean.getArray()[0]; + TestBean tb1 = bean.getArray()[1]; + TestBean tb2 = ((TestBean) bean.getList().get(0)); + TestBean tb3 = ((TestBean) bean.getList().get(1)); + TestBean tb4 = ((TestBean) bean.getMap().get("key1")); + TestBean tb5 = ((TestBean) bean.getMap().get("key2")); + assertEquals("name0", tb0.getName()); + assertEquals("name1", tb1.getName()); + assertEquals("name2", tb2.getName()); + assertEquals("name3", tb3.getName()); + assertEquals("name4", tb4.getName()); + assertEquals("name5", tb5.getName()); + assertEquals("name0", bw.getPropertyValue("array[0].name")); + assertEquals("name1", bw.getPropertyValue("array[1].name")); + assertEquals("name2", bw.getPropertyValue("list[0].name")); + assertEquals("name3", bw.getPropertyValue("list[1].name")); + assertEquals("name4", bw.getPropertyValue("map[key1].name")); + assertEquals("name5", bw.getPropertyValue("map[key2].name")); + assertEquals("name4", bw.getPropertyValue("map['key1'].name")); + assertEquals("name5", bw.getPropertyValue("map[\"key2\"].name")); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].name", "name5"); + pvs.addPropertyValue("array[1].name", "name4"); + pvs.addPropertyValue("list[0].name", "name3"); + pvs.addPropertyValue("list[1].name", "name2"); + pvs.addPropertyValue("map[key1].name", "name1"); + pvs.addPropertyValue("map['key2'].name", "name0"); + bw.setPropertyValues(pvs); + assertEquals("arrayname5", tb0.getName()); + assertEquals("arrayname4", tb1.getName()); + assertEquals("listname3", tb2.getName()); + assertEquals("listname2", tb3.getName()); + assertEquals("mapname1", tb4.getName()); + assertEquals("mapname0", tb5.getName()); + assertEquals("arrayname5", bw.getPropertyValue("array[0].name")); + assertEquals("arrayname4", bw.getPropertyValue("array[1].name")); + assertEquals("listname3", bw.getPropertyValue("list[0].name")); + assertEquals("listname2", bw.getPropertyValue("list[1].name")); + assertEquals("mapname1", bw.getPropertyValue("map[\"key1\"].name")); + assertEquals("mapname0", bw.getPropertyValue("map['key2'].name")); + } + + public void testIndexedPropertiesWithIndividualCustomEditorForProperty() { + IndexedTestBean bean = new IndexedTestBean(false); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(String.class, "array[0].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("array0" + text); + } + }); + bw.registerCustomEditor(String.class, "array[1].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("array1" + text); + } + }); + bw.registerCustomEditor(String.class, "list[0].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list0" + text); + } + }); + bw.registerCustomEditor(String.class, "list[1].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list1" + text); + } + }); + bw.registerCustomEditor(String.class, "map[key1].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("mapkey1" + text); + } + }); + bw.registerCustomEditor(String.class, "map[key2].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("mapkey2" + text); + } + }); + bean.populate(); + + TestBean tb0 = bean.getArray()[0]; + TestBean tb1 = bean.getArray()[1]; + TestBean tb2 = ((TestBean) bean.getList().get(0)); + TestBean tb3 = ((TestBean) bean.getList().get(1)); + TestBean tb4 = ((TestBean) bean.getMap().get("key1")); + TestBean tb5 = ((TestBean) bean.getMap().get("key2")); + assertEquals("name0", tb0.getName()); + assertEquals("name1", tb1.getName()); + assertEquals("name2", tb2.getName()); + assertEquals("name3", tb3.getName()); + assertEquals("name4", tb4.getName()); + assertEquals("name5", tb5.getName()); + assertEquals("name0", bw.getPropertyValue("array[0].name")); + assertEquals("name1", bw.getPropertyValue("array[1].name")); + assertEquals("name2", bw.getPropertyValue("list[0].name")); + assertEquals("name3", bw.getPropertyValue("list[1].name")); + assertEquals("name4", bw.getPropertyValue("map[key1].name")); + assertEquals("name5", bw.getPropertyValue("map[key2].name")); + assertEquals("name4", bw.getPropertyValue("map['key1'].name")); + assertEquals("name5", bw.getPropertyValue("map[\"key2\"].name")); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].name", "name5"); + pvs.addPropertyValue("array[1].name", "name4"); + pvs.addPropertyValue("list[0].name", "name3"); + pvs.addPropertyValue("list[1].name", "name2"); + pvs.addPropertyValue("map[key1].name", "name1"); + pvs.addPropertyValue("map['key2'].name", "name0"); + bw.setPropertyValues(pvs); + assertEquals("array0name5", tb0.getName()); + assertEquals("array1name4", tb1.getName()); + assertEquals("list0name3", tb2.getName()); + assertEquals("list1name2", tb3.getName()); + assertEquals("mapkey1name1", tb4.getName()); + assertEquals("mapkey2name0", tb5.getName()); + assertEquals("array0name5", bw.getPropertyValue("array[0].name")); + assertEquals("array1name4", bw.getPropertyValue("array[1].name")); + assertEquals("list0name3", bw.getPropertyValue("list[0].name")); + assertEquals("list1name2", bw.getPropertyValue("list[1].name")); + assertEquals("mapkey1name1", bw.getPropertyValue("map[\"key1\"].name")); + assertEquals("mapkey2name0", bw.getPropertyValue("map['key2'].name")); + } + + public void testNestedIndexedPropertiesWithCustomEditorForProperty() { + IndexedTestBean bean = new IndexedTestBean(); + TestBean tb0 = bean.getArray()[0]; + TestBean tb1 = bean.getArray()[1]; + TestBean tb2 = ((TestBean) bean.getList().get(0)); + TestBean tb3 = ((TestBean) bean.getList().get(1)); + TestBean tb4 = ((TestBean) bean.getMap().get("key1")); + TestBean tb5 = ((TestBean) bean.getMap().get("key2")); + tb0.setNestedIndexedBean(new IndexedTestBean()); + tb1.setNestedIndexedBean(new IndexedTestBean()); + tb2.setNestedIndexedBean(new IndexedTestBean()); + tb3.setNestedIndexedBean(new IndexedTestBean()); + tb4.setNestedIndexedBean(new IndexedTestBean()); + tb5.setNestedIndexedBean(new IndexedTestBean()); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(String.class, "array.nestedIndexedBean.array.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("array" + text); + } + + public String getAsText() { + return ((String) getValue()).substring(5); + } + }); + bw.registerCustomEditor(String.class, "list.nestedIndexedBean.list.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list" + text); + } + + public String getAsText() { + return ((String) getValue()).substring(4); + } + }); + bw.registerCustomEditor(String.class, "map.nestedIndexedBean.map.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("map" + text); + } + + public String getAsText() { + return ((String) getValue()).substring(4); + } + }); + assertEquals("name0", tb0.getName()); + assertEquals("name1", tb1.getName()); + assertEquals("name2", tb2.getName()); + assertEquals("name3", tb3.getName()); + assertEquals("name4", tb4.getName()); + assertEquals("name5", tb5.getName()); + assertEquals("name0", bw.getPropertyValue("array[0].nestedIndexedBean.array[0].name")); + assertEquals("name1", bw.getPropertyValue("array[1].nestedIndexedBean.array[1].name")); + assertEquals("name2", bw.getPropertyValue("list[0].nestedIndexedBean.list[0].name")); + assertEquals("name3", bw.getPropertyValue("list[1].nestedIndexedBean.list[1].name")); + assertEquals("name4", bw.getPropertyValue("map[key1].nestedIndexedBean.map[key1].name")); + assertEquals("name5", bw.getPropertyValue("map['key2'].nestedIndexedBean.map[\"key2\"].name")); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].nestedIndexedBean.array[0].name", "name5"); + pvs.addPropertyValue("array[1].nestedIndexedBean.array[1].name", "name4"); + pvs.addPropertyValue("list[0].nestedIndexedBean.list[0].name", "name3"); + pvs.addPropertyValue("list[1].nestedIndexedBean.list[1].name", "name2"); + pvs.addPropertyValue("map[key1].nestedIndexedBean.map[\"key1\"].name", "name1"); + pvs.addPropertyValue("map['key2'].nestedIndexedBean.map[key2].name", "name0"); + bw.setPropertyValues(pvs); + assertEquals("arrayname5", tb0.getNestedIndexedBean().getArray()[0].getName()); + assertEquals("arrayname4", tb1.getNestedIndexedBean().getArray()[1].getName()); + assertEquals("listname3", ((TestBean) tb2.getNestedIndexedBean().getList().get(0)).getName()); + assertEquals("listname2", ((TestBean) tb3.getNestedIndexedBean().getList().get(1)).getName()); + assertEquals("mapname1", ((TestBean) tb4.getNestedIndexedBean().getMap().get("key1")).getName()); + assertEquals("mapname0", ((TestBean) tb5.getNestedIndexedBean().getMap().get("key2")).getName()); + assertEquals("arrayname5", bw.getPropertyValue("array[0].nestedIndexedBean.array[0].name")); + assertEquals("arrayname4", bw.getPropertyValue("array[1].nestedIndexedBean.array[1].name")); + assertEquals("listname3", bw.getPropertyValue("list[0].nestedIndexedBean.list[0].name")); + assertEquals("listname2", bw.getPropertyValue("list[1].nestedIndexedBean.list[1].name")); + assertEquals("mapname1", bw.getPropertyValue("map['key1'].nestedIndexedBean.map[key1].name")); + assertEquals("mapname0", bw.getPropertyValue("map[key2].nestedIndexedBean.map[\"key2\"].name")); + } + + public void testNestedIndexedPropertiesWithIndexedCustomEditorForProperty() { + IndexedTestBean bean = new IndexedTestBean(); + TestBean tb0 = bean.getArray()[0]; + TestBean tb1 = bean.getArray()[1]; + TestBean tb2 = ((TestBean) bean.getList().get(0)); + TestBean tb3 = ((TestBean) bean.getList().get(1)); + TestBean tb4 = ((TestBean) bean.getMap().get("key1")); + TestBean tb5 = ((TestBean) bean.getMap().get("key2")); + tb0.setNestedIndexedBean(new IndexedTestBean()); + tb1.setNestedIndexedBean(new IndexedTestBean()); + tb2.setNestedIndexedBean(new IndexedTestBean()); + tb3.setNestedIndexedBean(new IndexedTestBean()); + tb4.setNestedIndexedBean(new IndexedTestBean()); + tb5.setNestedIndexedBean(new IndexedTestBean()); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(String.class, "array[0].nestedIndexedBean.array[0].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("array" + text); + } + }); + bw.registerCustomEditor(String.class, "list.nestedIndexedBean.list[1].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list" + text); + } + }); + bw.registerCustomEditor(String.class, "map[key1].nestedIndexedBean.map.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("map" + text); + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].nestedIndexedBean.array[0].name", "name5"); + pvs.addPropertyValue("array[1].nestedIndexedBean.array[1].name", "name4"); + pvs.addPropertyValue("list[0].nestedIndexedBean.list[0].name", "name3"); + pvs.addPropertyValue("list[1].nestedIndexedBean.list[1].name", "name2"); + pvs.addPropertyValue("map[key1].nestedIndexedBean.map[\"key1\"].name", "name1"); + pvs.addPropertyValue("map['key2'].nestedIndexedBean.map[key2].name", "name0"); + bw.setPropertyValues(pvs); + assertEquals("arrayname5", tb0.getNestedIndexedBean().getArray()[0].getName()); + assertEquals("name4", tb1.getNestedIndexedBean().getArray()[1].getName()); + assertEquals("name3", ((TestBean) tb2.getNestedIndexedBean().getList().get(0)).getName()); + assertEquals("listname2", ((TestBean) tb3.getNestedIndexedBean().getList().get(1)).getName()); + assertEquals("mapname1", ((TestBean) tb4.getNestedIndexedBean().getMap().get("key1")).getName()); + assertEquals("name0", ((TestBean) tb5.getNestedIndexedBean().getMap().get("key2")).getName()); + } + + public void testIndexedPropertiesWithDirectAccessAndPropertyEditors() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(TestBean.class, "array", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("array" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + bw.registerCustomEditor(TestBean.class, "list", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("list" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + bw.registerCustomEditor(TestBean.class, "map", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("map" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0]", "a"); + pvs.addPropertyValue("array[1]", "b"); + pvs.addPropertyValue("list[0]", "c"); + pvs.addPropertyValue("list[1]", "d"); + pvs.addPropertyValue("map[key1]", "e"); + pvs.addPropertyValue("map['key2']", "f"); + bw.setPropertyValues(pvs); + assertEquals("arraya", bean.getArray()[0].getName()); + assertEquals("arrayb", bean.getArray()[1].getName()); + assertEquals("listc", ((TestBean) bean.getList().get(0)).getName()); + assertEquals("listd", ((TestBean) bean.getList().get(1)).getName()); + assertEquals("mape", ((TestBean) bean.getMap().get("key1")).getName()); + assertEquals("mapf", ((TestBean) bean.getMap().get("key2")).getName()); + } + + public void testIndexedPropertiesWithDirectAccessAndSpecificPropertyEditors() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(TestBean.class, "array[0]", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("array0" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + bw.registerCustomEditor(TestBean.class, "array[1]", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("array1" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + bw.registerCustomEditor(TestBean.class, "list[0]", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("list0" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + bw.registerCustomEditor(TestBean.class, "list[1]", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("list1" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + bw.registerCustomEditor(TestBean.class, "map[key1]", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("mapkey1" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + bw.registerCustomEditor(TestBean.class, "map[key2]", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean("mapkey2" + text, 99)); + } + + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0]", "a"); + pvs.addPropertyValue("array[1]", "b"); + pvs.addPropertyValue("list[0]", "c"); + pvs.addPropertyValue("list[1]", "d"); + pvs.addPropertyValue("map[key1]", "e"); + pvs.addPropertyValue("map['key2']", "f"); + bw.setPropertyValues(pvs); + assertEquals("array0a", bean.getArray()[0].getName()); + assertEquals("array1b", bean.getArray()[1].getName()); + assertEquals("list0c", ((TestBean) bean.getList().get(0)).getName()); + assertEquals("list1d", ((TestBean) bean.getList().get(1)).getName()); + assertEquals("mapkey1e", ((TestBean) bean.getMap().get("key1")).getName()); + assertEquals("mapkey2f", ((TestBean) bean.getMap().get("key2")).getName()); + } + + public void testIndexedPropertiesWithListPropertyEditor() { + IndexedTestBean bean = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(bean); + bw.registerCustomEditor(List.class, "list", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + List result = new ArrayList(); + result.add(new TestBean("list" + text, 99)); + setValue(result); + } + }); + bw.setPropertyValue("list", "1"); + assertEquals("list1", ((TestBean) bean.getList().get(0)).getName()); + bw.setPropertyValue("list[0]", "test"); + assertEquals("test", bean.getList().get(0)); + } + + public void testConversionToOldCollections() throws PropertyVetoException { + OldCollectionsBean tb = new OldCollectionsBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(Vector.class, new CustomCollectionEditor(Vector.class)); + bw.registerCustomEditor(Hashtable.class, new CustomMapEditor(Hashtable.class)); + + bw.setPropertyValue("vector", new String[] {"a", "b"}); + assertEquals(2, tb.getVector().size()); + assertEquals("a", tb.getVector().get(0)); + assertEquals("b", tb.getVector().get(1)); + + bw.setPropertyValue("hashtable", Collections.singletonMap("foo", "bar")); + assertEquals(1, tb.getHashtable().size()); + assertEquals("bar", tb.getHashtable().get("foo")); + } + + public void testUninitializedArrayPropertyWithCustomEditor() { + IndexedTestBean bean = new IndexedTestBean(false); + BeanWrapper bw = new BeanWrapperImpl(bean); + PropertyEditor pe = new CustomNumberEditor(Integer.class, true); + bw.registerCustomEditor(null, "list.age", pe); + TestBean tb = new TestBean(); + bw.setPropertyValue("list", new ArrayList()); + bw.setPropertyValue("list[0]", tb); + assertEquals(tb, bean.getList().get(0)); + assertEquals(pe, bw.findCustomEditor(int.class, "list.age")); + assertEquals(pe, bw.findCustomEditor(null, "list.age")); + assertEquals(pe, bw.findCustomEditor(int.class, "list[0].age")); + assertEquals(pe, bw.findCustomEditor(null, "list[0].age")); + } + + public void testArrayToArrayConversion() throws PropertyVetoException { + IndexedTestBean tb = new IndexedTestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(TestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean(text, 99)); + } + }); + bw.setPropertyValue("array", new String[] {"a", "b"}); + assertEquals(2, tb.getArray().length); + assertEquals("a", tb.getArray()[0].getName()); + assertEquals("b", tb.getArray()[1].getName()); + } + + public void testArrayToStringConversion() throws PropertyVetoException { + TestBean tb = new TestBean(); + BeanWrapper bw = new BeanWrapperImpl(tb); + bw.registerCustomEditor(String.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("-" + text + "-"); + } + }); + bw.setPropertyValue("name", new String[] {"a", "b"}); + assertEquals("-a,b-", tb.getName()); + } + + public void testClassArrayEditorSunnyDay() throws Exception { + ClassArrayEditor classArrayEditor = new ClassArrayEditor(); + classArrayEditor.setAsText("java.lang.String,java.util.HashMap"); + Class[] classes = (Class[]) classArrayEditor.getValue(); + assertEquals(2, classes.length); + assertEquals(String.class, classes[0]); + assertEquals(HashMap.class, classes[1]); + assertEquals("java.lang.String,java.util.HashMap", classArrayEditor.getAsText()); + // ensure setAsText can consume the return value of getAsText + classArrayEditor.setAsText(classArrayEditor.getAsText()); + } + + public void testClassArrayEditorSunnyDayWithArrayTypes() throws Exception { + ClassArrayEditor classArrayEditor = new ClassArrayEditor(); + classArrayEditor.setAsText("java.lang.String[],java.util.Map[],int[],float[][][]"); + Class[] classes = (Class[]) classArrayEditor.getValue(); + assertEquals(4, classes.length); + assertEquals(String[].class, classes[0]); + assertEquals(Map[].class, classes[1]); + assertEquals(int[].class, classes[2]); + assertEquals(float[][][].class, classes[3]); + assertEquals("java.lang.String[],java.util.Map[],int[],float[][][]", classArrayEditor.getAsText()); + // ensure setAsText can consume the return value of getAsText + classArrayEditor.setAsText(classArrayEditor.getAsText()); + } + + public void testClassArrayEditorSetAsTextWithNull() throws Exception { + ClassArrayEditor editor = new ClassArrayEditor(); + editor.setAsText(null); + assertNull(editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testClassArrayEditorSetAsTextWithEmptyString() throws Exception { + ClassArrayEditor editor = new ClassArrayEditor(); + editor.setAsText(""); + assertNull(editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testClassArrayEditorSetAsTextWithWhitespaceString() throws Exception { + ClassArrayEditor editor = new ClassArrayEditor(); + editor.setAsText("\n"); + assertNull(editor.getValue()); + assertEquals("", editor.getAsText()); + } + + public void testCharsetEditor() throws Exception { + CharsetEditor editor = new CharsetEditor(); + String name = "UTF-8"; + editor.setAsText(name); + Charset charset = Charset.forName(name); + assertEquals("Invalid Charset conversion", charset, editor.getValue()); + editor.setValue(charset); + assertEquals("Invalid Charset conversion", name, editor.getAsText()); + } + + + private static class TestBeanEditor extends PropertyEditorSupport { + + public void setAsText(String text) { + TestBean tb = new TestBean(); + StringTokenizer st = new StringTokenizer(text, "_"); + tb.setName(st.nextToken()); + tb.setAge(Integer.parseInt(st.nextToken())); + setValue(tb); + } + } + + + private static class OldValueAccessingTestBeanEditor extends PropertyEditorSupport { + + public void setAsText(String text) { + TestBean tb = new TestBean(); + StringTokenizer st = new StringTokenizer(text, "_"); + tb.setName(st.nextToken()); + tb.setAge(Integer.parseInt(st.nextToken())); + if (!tb.equals(getValue())) { + setValue(tb); + } + } + } + + + private static class PrimitiveArrayBean { + + private byte[] byteArray; + + private char[] charArray; + + public byte[] getByteArray() { + return byteArray; + } + + public void setByteArray(byte[] byteArray) { + this.byteArray = byteArray; + } + + public char[] getCharArray() { + return charArray; + } + + public void setCharArray(char[] charArray) { + this.charArray = charArray; + } + } + + + private static class CharBean { + + private char myChar; + + private Character myCharacter; + + public char getMyChar() { + return myChar; + } + + public void setMyChar(char myChar) { + this.myChar = myChar; + } + + public Character getMyCharacter() { + return myCharacter; + } + + public void setMyCharacter(Character myCharacter) { + this.myCharacter = myCharacter; + } + } + + + private static class OldCollectionsBean { + + private Vector vector; + + private Hashtable hashtable; + + public Vector getVector() { + return vector; + } + + public void setVector(Vector vector) { + this.vector = vector; + } + + public Hashtable getHashtable() { + return hashtable; + } + + public void setHashtable(Hashtable hashtable) { + this.hashtable = hashtable; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/FileEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/FileEditorTests.java new file mode 100644 index 00000000000..3686a74ab98 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/FileEditorTests.java @@ -0,0 +1,86 @@ + +package org.springframework.beans.propertyeditors; + +import java.beans.PropertyEditor; +import java.io.File; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; +import org.springframework.util.ClassUtils; + +/** + * @author Thomas Risberg + */ +public final class FileEditorTests extends TestCase { + + public void testClasspathFileName() throws Exception { + PropertyEditor fileEditor = new FileEditor(); + fileEditor.setAsText("classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + + ClassUtils.getShortName(getClass()) + ".class"); + Object value = fileEditor.getValue(); + assertTrue(value instanceof File); + File file = (File) value; + assertTrue(file.exists()); + } + + public void testWithNonExistentResource() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + + public void test() throws Exception { + PropertyEditor propertyEditor = new FileEditor(); + propertyEditor.setAsText("classpath:no_way_this_file_is_found.doc"); + } + }.runTest(); + } + + public void testWithNonExistentFile() throws Exception { + PropertyEditor fileEditor = new FileEditor(); + fileEditor.setAsText("file:no_way_this_file_is_found.doc"); + Object value = fileEditor.getValue(); + assertTrue(value instanceof File); + File file = (File) value; + assertTrue(!file.exists()); + } + + public void testAbsoluteFileName() throws Exception { + PropertyEditor fileEditor = new FileEditor(); + fileEditor.setAsText("/no_way_this_file_is_found.doc"); + Object value = fileEditor.getValue(); + assertTrue(value instanceof File); + File file = (File) value; + assertTrue(!file.exists()); + } + + public void testUnqualifiedFileNameFound() throws Exception { + PropertyEditor fileEditor = new FileEditor(); + String fileName = ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + + ".class"; + fileEditor.setAsText(fileName); + Object value = fileEditor.getValue(); + assertTrue(value instanceof File); + File file = (File) value; + assertTrue(file.exists()); + String absolutePath = file.getAbsolutePath(); + if (File.separatorChar == '\\') { + absolutePath = absolutePath.replace('\\', '/'); + } + assertTrue(absolutePath.endsWith(fileName)); + } + + public void testUnqualifiedFileNameNotFound() throws Exception { + PropertyEditor fileEditor = new FileEditor(); + String fileName = ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + + ".clazz"; + fileEditor.setAsText(fileName); + Object value = fileEditor.getValue(); + assertTrue(value instanceof File); + File file = (File) value; + assertFalse(file.exists()); + String absolutePath = file.getAbsolutePath(); + if (File.separatorChar == '\\') { + absolutePath = absolutePath.replace('\\', '/'); + } + assertTrue(absolutePath.endsWith(fileName)); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/InputStreamEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/InputStreamEditorTests.java new file mode 100644 index 00000000000..5b83da915e0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/InputStreamEditorTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; +import org.springframework.util.ClassUtils; + +import java.io.InputStream; + +/** + * Unit tests for the {@link InputStreamEditor} class. + * + * @author Rick Evans + */ +public final class InputStreamEditorTests extends TestCase { + + public void testCtorWithNullResourceEditor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new InputStreamEditor(null); + } + }.runTest(); + } + + public void testSunnyDay() throws Exception { + InputStream stream = null; + try { + String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class"; + InputStreamEditor editor = new InputStreamEditor(); + editor.setAsText(resource); + Object value = editor.getValue(); + assertNotNull(value); + assertTrue(value instanceof InputStream); + stream = (InputStream) value; + assertTrue(stream.available() > 0); + } finally { + if (stream != null) { + stream.close(); + } + } + } + + public void testWhenResourceDoesNotExist() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + String resource = "classpath:bingo!"; + InputStreamEditor editor = new InputStreamEditor(); + editor.setAsText(resource); + } + }.runTest(); + } + + public void testGetAsTextReturnsNullByDefault() throws Exception { + assertNull(new InputStreamEditor().getAsText()); + String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class"; + InputStreamEditor editor = new InputStreamEditor(); + editor.setAsText(resource); + assertNull(editor.getAsText()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/PropertiesEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/PropertiesEditorTests.java new file mode 100644 index 00000000000..3e8266ea2d2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/PropertiesEditorTests.java @@ -0,0 +1,159 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import junit.framework.TestCase; + +/** + * Test the conversion of Strings to {@link java.util.Properties} objects, + * and other property editors. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + */ +public class PropertiesEditorTests extends TestCase { + + public void testOneProperty() { + String s = "foo=bar"; + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(s); + Properties p = (Properties) pe.getValue(); + assertTrue("contains one entry", p.entrySet().size() == 1); + assertTrue("foo=bar", p.get("foo").equals("bar")); + } + + public void testTwoProperties() { + String s = "foo=bar with whitespace\n" + + "me=mi"; + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(s); + Properties p = (Properties) pe.getValue(); + assertTrue("contains two entries", p.entrySet().size() == 2); + assertTrue("foo=bar with whitespace", p.get("foo").equals("bar with whitespace")); + assertTrue("me=mi", p.get("me").equals("mi")); + } + + public void testHandlesEqualsInValue() { + String s = "foo=bar\n" + + "me=mi\n" + + "x=y=z"; + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(s); + Properties p = (Properties) pe.getValue(); + assertTrue("contains two entries", p.entrySet().size() == 3); + assertTrue("foo=bar", p.get("foo").equals("bar")); + assertTrue("me=mi", p.get("me").equals("mi")); + assertTrue("x='y=z'", p.get("x").equals("y=z")); + } + + public void testHandlesEmptyProperty() { + String s = "foo=bar\nme=mi\nx="; + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(s); + Properties p = (Properties) pe.getValue(); + assertTrue("contains two entries", p.entrySet().size() == 3); + assertTrue("foo=bar", p.get("foo").equals("bar")); + assertTrue("me=mi", p.get("me").equals("mi")); + assertTrue("x='y=z'", p.get("x").equals("")); + } + + public void testHandlesEmptyPropertyWithoutEquals() { + String s = "foo\nme=mi\nx=x"; + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(s); + Properties p = (Properties) pe.getValue(); + assertTrue("contains three entries", p.entrySet().size() == 3); + assertTrue("foo is empty", p.get("foo").equals("")); + assertTrue("me=mi", p.get("me").equals("mi")); + } + + /** + * Comments begin with # + */ + public void testIgnoresCommentLinesAndEmptyLines() { + String s = "#Ignore this comment\n" + + "foo=bar\n" + + "#Another=comment more junk /\n" + + "me=mi\n" + + "x=x\n" + + "\n"; + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(s); + Properties p = (Properties) pe.getValue(); + assertTrue("contains three entries", p.entrySet().size() == 3); + assertTrue("foo is bar", p.get("foo").equals("bar")); + assertTrue("me=mi", p.get("me").equals("mi")); + } + + /** + * We'll typically align by indenting with tabs or spaces. + * These should be ignored if at the beginning of a line. + * We must ensure that comment lines beginning with whitespace are + * still ignored: The standard syntax doesn't allow this on JDK 1.3. + */ + public void testIgnoresLeadingSpacesAndTabs() { + String s = " #Ignore this comment\n" + + "\t\tfoo=bar\n" + + "\t#Another comment more junk \n" + + " me=mi\n" + + "x=x\n" + + "\n"; + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(s); + Properties p = (Properties) pe.getValue(); + assertTrue("contains 3 entries, not " + p.size(), p.size() == 3); + assertTrue("foo is bar", p.get("foo").equals("bar")); + assertTrue("me=mi", p.get("me").equals("mi")); + } + + public void testNull() { + PropertiesEditor pe= new PropertiesEditor(); + pe.setAsText(null); + Properties p = (Properties) pe.getValue(); + assertEquals(0, p.size()); + } + + public void testEmptyString() { + PropertiesEditor pe = new PropertiesEditor(); + pe.setAsText(""); + Properties p = (Properties) pe.getValue(); + assertTrue("empty string means empty properties", p.isEmpty()); + } + + public void testUsingMapAsValueSource() throws Exception { + Map map = new HashMap(); + map.put("one", "1"); + map.put("two", "2"); + map.put("three", "3"); + PropertiesEditor pe = new PropertiesEditor(); + pe.setValue(map); + Object value = pe.getValue(); + assertNotNull(value); + assertTrue(value instanceof Properties); + Properties props = (Properties) value; + assertEquals(3, props.size()); + assertEquals("1", props.getProperty("one")); + assertEquals("2", props.getProperty("two")); + assertEquals("3", props.getProperty("three")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.java new file mode 100644 index 00000000000..444e3a3d7f8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.java @@ -0,0 +1,126 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +import java.util.ResourceBundle; + +/** + * Unit tests for the {@link ResourceBundleEditor} class. + * + * @author Rick Evans + */ +public final class ResourceBundleEditorTests extends TestCase { + + private static final String BASE_NAME = ResourceBundleEditorTests.class.getName(); + private static final String MESSAGE_KEY = "punk"; + + + public void testSetAsTextWithJustBaseName() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(BASE_NAME); + Object value = editor.getValue(); + assertNotNull("Returned ResourceBundle was null (must not be for valid setAsText(..) call).", value); + assertTrue("Returned object was not a ResourceBundle (must be for valid setAsText(..) call).", value instanceof ResourceBundle); + ResourceBundle bundle = (ResourceBundle) value; + String string = bundle.getString(MESSAGE_KEY); + assertEquals(MESSAGE_KEY, string); + } + + public void testSetAsTextWithBaseNameThatEndsInDefaultSeparator() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(BASE_NAME + "_"); + Object value = editor.getValue(); + assertNotNull("Returned ResourceBundle was null (must not be for valid setAsText(..) call).", value); + assertTrue("Returned object was not a ResourceBundle (must be for valid setAsText(..) call).", value instanceof ResourceBundle); + ResourceBundle bundle = (ResourceBundle) value; + String string = bundle.getString(MESSAGE_KEY); + assertEquals(MESSAGE_KEY, string); + } + + public void testSetAsTextWithBaseNameAndLanguageCode() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(BASE_NAME + "Lang" + "_en"); + Object value = editor.getValue(); + assertNotNull("Returned ResourceBundle was null (must not be for valid setAsText(..) call).", value); + assertTrue("Returned object was not a ResourceBundle (must be for valid setAsText(..) call).", value instanceof ResourceBundle); + ResourceBundle bundle = (ResourceBundle) value; + String string = bundle.getString(MESSAGE_KEY); + assertEquals("yob", string); + } + + public void testSetAsTextWithBaseNameLanguageAndCountryCode() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(BASE_NAME + "LangCountry" + "_en_GB"); + Object value = editor.getValue(); + assertNotNull("Returned ResourceBundle was null (must not be for valid setAsText(..) call).", value); + assertTrue("Returned object was not a ResourceBundle (must be for valid setAsText(..) call).", value instanceof ResourceBundle); + ResourceBundle bundle = (ResourceBundle) value; + String string = bundle.getString(MESSAGE_KEY); + assertEquals("chav", string); + } + + public void testSetAsTextWithTheKitchenSink() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(BASE_NAME + "LangCountryDialect" + "_en_GB_GLASGOW"); + Object value = editor.getValue(); + assertNotNull("Returned ResourceBundle was null (must not be for valid setAsText(..) call).", value); + assertTrue("Returned object was not a ResourceBundle (must be for valid setAsText(..) call).", value instanceof ResourceBundle); + ResourceBundle bundle = (ResourceBundle) value; + String string = bundle.getString(MESSAGE_KEY); + assertEquals("ned", string); + } + + public void testSetAsTextWithNull() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(null); + } + }.runTest(); + } + + public void testSetAsTextWithEmptyString() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(""); + } + }.runTest(); + } + + public void testSetAsTextWithWhiteSpaceString() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText(" "); + } + }.runTest(); + } + + public void testSetAsTextWithJustSeparatorString() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + ResourceBundleEditor editor = new ResourceBundleEditor(); + editor.setAsText("_"); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.properties new file mode 100644 index 00000000000..ecb69cb31fa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTests.properties @@ -0,0 +1 @@ +punk=punk \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountryDialect_en_GB_GLASGOW.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountryDialect_en_GB_GLASGOW.properties new file mode 100644 index 00000000000..70055b65aee --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountryDialect_en_GB_GLASGOW.properties @@ -0,0 +1 @@ +punk=ned \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountry_en_GB.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountry_en_GB.properties new file mode 100644 index 00000000000..4b790a4c7bd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLangCountry_en_GB.properties @@ -0,0 +1 @@ +punk=chav \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLang_en.properties b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLang_en.properties new file mode 100644 index 00000000000..de8a7b30222 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/ResourceBundleEditorTestsLang_en.properties @@ -0,0 +1 @@ +punk=yob \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java new file mode 100644 index 00000000000..3ef0b9efc7b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class StringArrayPropertyEditorTests extends TestCase { + + public void testWithDefaultSeparator() throws Exception { + StringArrayPropertyEditor editor = new StringArrayPropertyEditor(); + editor.setAsText("0,1,2"); + Object value = editor.getValue(); + assertNotNull(value); + assertTrue(value instanceof String[]); + String[] array = (String[]) value; + for (int i = 0; i < array.length; ++i) { + assertEquals("" + i, array[i]); + } + assertEquals("0,1,2", editor.getAsText()); + } + + public void testWithCustomSeparator() throws Exception { + StringArrayPropertyEditor editor = new StringArrayPropertyEditor(":"); + editor.setAsText("0:1:2"); + Object value = editor.getValue(); + assertTrue(value instanceof String[]); + String[] array = (String[]) value; + for (int i = 0; i < array.length; ++i) { + assertEquals("" + i, array[i]); + } + assertEquals("0:1:2", editor.getAsText()); + } + + public void testWithCharsToDelete() throws Exception { + StringArrayPropertyEditor editor = new StringArrayPropertyEditor(",", "\r\n", false); + editor.setAsText("0\r,1,\n2"); + Object value = editor.getValue(); + assertTrue(value instanceof String[]); + String[] array = (String[]) value; + for (int i = 0; i < array.length; ++i) { + assertEquals("" + i, array[i]); + } + assertEquals("0,1,2", editor.getAsText()); + } + + public void testWithEmptyArray() throws Exception { + StringArrayPropertyEditor editor = new StringArrayPropertyEditor(); + editor.setAsText(""); + Object value = editor.getValue(); + assertTrue(value instanceof String[]); + assertEquals(0, ((String[]) value).length); + } + + public void testWithEmptyArrayAsNull() throws Exception { + StringArrayPropertyEditor editor = new StringArrayPropertyEditor(",", true); + editor.setAsText(""); + assertNull(editor.getValue()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URIEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URIEditorTests.java new file mode 100644 index 00000000000..c9390414211 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URIEditorTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import java.beans.PropertyEditor; +import java.net.URI; + +import junit.framework.TestCase; + +import org.springframework.util.ClassUtils; + +/** + * @author Juergen Hoeller + */ +public class URIEditorTests extends TestCase { + + public void testStandardURI() throws Exception { + PropertyEditor uriEditor = new URIEditor(); + uriEditor.setAsText("mailto:juergen.hoeller@interface21.com"); + Object value = uriEditor.getValue(); + assertTrue(value instanceof URI); + URI uri = (URI) value; + assertEquals(uri.toString(), uriEditor.getAsText()); + } + + public void testStandardURL() throws Exception { + PropertyEditor uriEditor = new URIEditor(); + uriEditor.setAsText("http://www.springframework.org"); + Object value = uriEditor.getValue(); + assertTrue(value instanceof URI); + URI uri = (URI) value; + assertEquals(uri.toString(), uriEditor.getAsText()); + } + + public void testStandardURLWithWhitespace() throws Exception { + PropertyEditor uriEditor = new URIEditor(); + uriEditor.setAsText(" http://www.springframework.org "); + Object value = uriEditor.getValue(); + assertTrue(value instanceof URI); + URI uri = (URI) value; + assertEquals(uri.toString(), uriEditor.getAsText()); + } + + public void testClasspathURL() throws Exception { + PropertyEditor uriEditor = new URIEditor(getClass().getClassLoader()); + uriEditor.setAsText("classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + + "/" + ClassUtils.getShortName(getClass()) + ".class"); + Object value = uriEditor.getValue(); + assertTrue(value instanceof URI); + URI uri = (URI) value; + assertEquals(uri.toString(), uriEditor.getAsText()); + assertTrue(!uri.getScheme().startsWith("classpath")); + } + + public void testClasspathURLWithWhitespace() throws Exception { + PropertyEditor uriEditor = new URIEditor(getClass().getClassLoader()); + uriEditor.setAsText(" classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + + "/" + ClassUtils.getShortName(getClass()) + ".class "); + Object value = uriEditor.getValue(); + assertTrue(value instanceof URI); + URI uri = (URI) value; + assertEquals(uri.toString(), uriEditor.getAsText()); + assertTrue(!uri.getScheme().startsWith("classpath")); + } + + public void testClasspathURLAsIs() throws Exception { + PropertyEditor uriEditor = new URIEditor(); + uriEditor.setAsText("classpath:test.txt"); + Object value = uriEditor.getValue(); + assertTrue(value instanceof URI); + URI uri = (URI) value; + assertEquals(uri.toString(), uriEditor.getAsText()); + assertTrue(uri.getScheme().startsWith("classpath")); + } + + public void testWithNonExistentResource() throws Exception { + PropertyEditor uriEditor = new URIEditor(); + uriEditor.setAsText("gonna:/freak/in/the/morning/freak/in/the.evening"); + Object value = uriEditor.getValue(); + assertTrue(value instanceof URI); + URI uri = (URI) value; + assertEquals(uri.toString(), uriEditor.getAsText()); + } + + public void testSetAsTextWithNull() throws Exception { + PropertyEditor uriEditor = new URIEditor(); + uriEditor.setAsText(null); + assertNull(uriEditor.getValue()); + assertEquals("", uriEditor.getAsText()); + } + + public void testGetAsTextReturnsEmptyStringIfValueNotSet() throws Exception { + PropertyEditor uriEditor = new URIEditor(); + assertEquals("", uriEditor.getAsText()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URLEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URLEditorTests.java new file mode 100644 index 00000000000..1ac1be38c3d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/propertyeditors/URLEditorTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import java.beans.PropertyEditor; +import java.net.URL; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; +import org.springframework.util.ClassUtils; + +/** + * @author Rick Evans + */ +public final class URLEditorTests extends TestCase { + + public void testStandardURI() throws Exception { + PropertyEditor urlEditor = new URLEditor(); + urlEditor.setAsText("mailto:juergen.hoeller@interface21.com"); + Object value = urlEditor.getValue(); + assertTrue(value instanceof URL); + URL url = (URL) value; + assertEquals(url.toExternalForm(), urlEditor.getAsText()); + } + + public void testStandardURL() throws Exception { + PropertyEditor urlEditor = new URLEditor(); + urlEditor.setAsText("http://www.springframework.org"); + Object value = urlEditor.getValue(); + assertTrue(value instanceof URL); + URL url = (URL) value; + assertEquals(url.toExternalForm(), urlEditor.getAsText()); + } + + public void testClasspathURL() throws Exception { + PropertyEditor urlEditor = new URLEditor(); + urlEditor.setAsText("classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + + "/" + ClassUtils.getShortName(getClass()) + ".class"); + Object value = urlEditor.getValue(); + assertTrue(value instanceof URL); + URL url = (URL) value; + assertEquals(url.toExternalForm(), urlEditor.getAsText()); + assertTrue(!url.getProtocol().startsWith("classpath")); + } + + public void testWithNonExistentResource() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PropertyEditor urlEditor = new URLEditor(); + urlEditor.setAsText("gonna:/freak/in/the/morning/freak/in/the.evening"); + } + }.runTest(); + } + + public void testSetAsTextWithNull() throws Exception { + PropertyEditor urlEditor = new URLEditor(); + urlEditor.setAsText(null); + assertNull(urlEditor.getValue()); + assertEquals("", urlEditor.getAsText()); + } + + public void testGetAsTextReturnsEmptyStringIfValueNotSet() throws Exception { + PropertyEditor urlEditor = new URLEditor(); + assertEquals("", urlEditor.getAsText()); + } + + public void testCtorWithNullResourceEditor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new URLEditor(null); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/support/DerivedFromProtectedBaseBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/support/DerivedFromProtectedBaseBean.java new file mode 100644 index 00000000000..fc41a86301f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/support/DerivedFromProtectedBaseBean.java @@ -0,0 +1,25 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.support; + +/** + * @author Juergen Hoeller + * @since 29.07.2004 + */ +public class DerivedFromProtectedBaseBean extends ProtectedBaseBean { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/support/PagedListHolderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/support/PagedListHolderTests.java new file mode 100644 index 00000000000..42b04bf6c02 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/support/PagedListHolderTests.java @@ -0,0 +1,219 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.support; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.TestBean; + +/** + * @author Juergen Hoeller + * @author Jean-Pierre PAWLAK + * @since 20.05.2003 + */ +public class PagedListHolderTests extends TestCase { + + public void testPagedListHolder() { + TestBean tb1 = new TestBean(); + tb1.setName("eva"); + tb1.setAge(25); + TestBean tb2 = new TestBean(); + tb2.setName("juergen"); + tb2.setAge(99); + TestBean tb3 = new TestBean(); + tb3.setName("Rod"); + tb3.setAge(32); + List tbs = new ArrayList(); + tbs.add(tb1); + tbs.add(tb2); + tbs.add(tb3); + + PagedListHolder holder = new PagedListHolder(tbs); + assertTrue("Correct source", holder.getSource() == tbs); + assertTrue("Correct number of elements", holder.getNrOfElements() == 3); + assertTrue("Correct number of pages", holder.getPageCount() == 1); + assertTrue("Correct page size", holder.getPageSize() == PagedListHolder.DEFAULT_PAGE_SIZE); + assertTrue("Correct page number", holder.getPage() == 0); + assertTrue("First page", holder.isFirstPage()); + assertTrue("Last page", holder.isLastPage()); + assertTrue("Correct first element", holder.getFirstElementOnPage() == 0); + assertTrue("Correct first element", holder.getLastElementOnPage() == 2); + assertTrue("Correct page list size", holder.getPageList().size() == 3); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb1); + assertTrue("Correct page list contents", holder.getPageList().get(1) == tb2); + assertTrue("Correct page list contents", holder.getPageList().get(2) == tb3); + + holder.setPageSize(2); + assertTrue("Correct number of pages", holder.getPageCount() == 2); + assertTrue("Correct page size", holder.getPageSize() == 2); + assertTrue("Correct page number", holder.getPage() == 0); + assertTrue("First page", holder.isFirstPage()); + assertFalse("Last page", holder.isLastPage()); + assertTrue("Correct first element", holder.getFirstElementOnPage() == 0); + assertTrue("Correct last element", holder.getLastElementOnPage() == 1); + assertTrue("Correct page list size", holder.getPageList().size() == 2); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb1); + assertTrue("Correct page list contents", holder.getPageList().get(1) == tb2); + + holder.setPage(1); + assertTrue("Correct page number", holder.getPage() == 1); + assertFalse("First page", holder.isFirstPage()); + assertTrue("Last page", holder.isLastPage()); + assertTrue("Correct first element", holder.getFirstElementOnPage() == 2); + assertTrue("Correct last element", holder.getLastElementOnPage() == 2); + assertTrue("Correct page list size", holder.getPageList().size() == 1); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb3); + + holder.setPageSize(3); + assertTrue("Correct number of pages", holder.getPageCount() == 1); + assertTrue("Correct page size", holder.getPageSize() == 3); + assertTrue("Correct page number", holder.getPage() == 0); + assertTrue("First page", holder.isFirstPage()); + assertTrue("Last page", holder.isLastPage()); + assertTrue("Correct first element", holder.getFirstElementOnPage() == 0); + assertTrue("Correct last element", holder.getLastElementOnPage() == 2); + + holder.setPage(1); + holder.setPageSize(2); + assertTrue("Correct number of pages", holder.getPageCount() == 2); + assertTrue("Correct page size", holder.getPageSize() == 2); + assertTrue("Correct page number", holder.getPage() == 1); + assertFalse("First page", holder.isFirstPage()); + assertTrue("Last page", holder.isLastPage()); + assertTrue("Correct first element", holder.getFirstElementOnPage() == 2); + assertTrue("Correct last element", holder.getLastElementOnPage() == 2); + + holder.setPageSize(2); + holder.setPage(1); + ((MutableSortDefinition) holder.getSort()).setProperty("name"); + ((MutableSortDefinition) holder.getSort()).setIgnoreCase(false); + holder.resort(); + assertTrue("Correct source", holder.getSource() == tbs); + assertTrue("Correct number of elements", holder.getNrOfElements() == 3); + assertTrue("Correct number of pages", holder.getPageCount() == 2); + assertTrue("Correct page size", holder.getPageSize() == 2); + assertTrue("Correct page number", holder.getPage() == 0); + assertTrue("First page", holder.isFirstPage()); + assertFalse("Last page", holder.isLastPage()); + assertTrue("Correct first element", holder.getFirstElementOnPage() == 0); + assertTrue("Correct last element", holder.getLastElementOnPage() == 1); + assertTrue("Correct page list size", holder.getPageList().size() == 2); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb3); + assertTrue("Correct page list contents", holder.getPageList().get(1) == tb1); + + ((MutableSortDefinition) holder.getSort()).setProperty("name"); + holder.resort(); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb2); + assertTrue("Correct page list contents", holder.getPageList().get(1) == tb1); + + ((MutableSortDefinition) holder.getSort()).setProperty("name"); + holder.resort(); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb3); + assertTrue("Correct page list contents", holder.getPageList().get(1) == tb1); + + holder.setPage(1); + assertTrue("Correct page list size", holder.getPageList().size() == 1); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb2); + + ((MutableSortDefinition) holder.getSort()).setProperty("age"); + holder.resort(); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb1); + assertTrue("Correct page list contents", holder.getPageList().get(1) == tb3); + + ((MutableSortDefinition) holder.getSort()).setIgnoreCase(true); + holder.resort(); + assertTrue("Correct page list contents", holder.getPageList().get(0) == tb1); + assertTrue("Correct page list contents", holder.getPageList().get(1) == tb3); + + holder.nextPage(); + assertEquals(1, holder.getPage()); + holder.previousPage(); + assertEquals(0, holder.getPage()); + holder.nextPage(); + assertEquals(1, holder.getPage()); + holder.nextPage(); + assertEquals(1, holder.getPage()); + holder.previousPage(); + assertEquals(0, holder.getPage()); + holder.previousPage(); + assertEquals(0, holder.getPage()); + } + + + + public static class MockFilter { + + private String name = ""; + private String age = ""; + private String extendedInfo = ""; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAge() { + return age; + } + + public void setAge(String age) { + this.age = age; + } + + public String getExtendedInfo() { + return extendedInfo; + } + + public void setExtendedInfo(String extendedInfo) { + this.extendedInfo = extendedInfo; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MockFilter)) return false; + + final MockFilter mockFilter = (MockFilter) o; + + if (!age.equals(mockFilter.age)) return false; + if (!extendedInfo.equals(mockFilter.extendedInfo)) return false; + if (!name.equals(mockFilter.name)) return false; + + return true; + } + + public int hashCode() { + int result; + result = name.hashCode(); + result = 29 * result + age.hashCode(); + result = 29 * result + extendedInfo.hashCode(); + return result; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/beans/support/ProtectedBaseBean.java b/org.springframework.testsuite/src/test/java/org/springframework/beans/support/ProtectedBaseBean.java new file mode 100644 index 00000000000..84c8e675a0b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/beans/support/ProtectedBaseBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.support; + +/** + * @author Juergen Hoeller + * @since 29.07.2004 + */ +class ProtectedBaseBean { + + private String someProperty; + + public void setSomeProperty(String someProperty) { + this.someProperty = someProperty; + } + + public String getSomeProperty() { + return someProperty; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java new file mode 100644 index 00000000000..d187414aa14 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java @@ -0,0 +1,222 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.ehcache; + +import junit.framework.TestCase; +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.Ehcache; +import net.sf.ehcache.constructs.blocking.BlockingCache; +import net.sf.ehcache.constructs.blocking.CacheEntryFactory; +import net.sf.ehcache.constructs.blocking.SelfPopulatingCache; +import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory; +import net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache; + +import org.springframework.core.io.ClassPathResource; + +/** + * @author Dmitriy Kopylenko + * @author Juergen Hoeller + * @since 27.09.2004 + */ +public class EhCacheSupportTests extends TestCase { + + public void testLoadingBlankCacheManager() throws Exception { + EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean(); + assertEquals(CacheManager.class, cacheManagerFb.getObjectType()); + assertTrue("Singleton property", cacheManagerFb.isSingleton()); + cacheManagerFb.afterPropertiesSet(); + try { + CacheManager cm = (CacheManager) cacheManagerFb.getObject(); + assertTrue("Loaded CacheManager with no caches", cm.getCacheNames().length == 0); + Cache myCache1 = cm.getCache("myCache1"); + assertTrue("No myCache1 defined", myCache1 == null); + } + finally { + cacheManagerFb.destroy(); + } + } + + public void testLoadingCacheManagerFromConfigFile() throws Exception { + EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean(); + cacheManagerFb.setConfigLocation(new ClassPathResource("testEhcache.xml", getClass())); + cacheManagerFb.setCacheManagerName("myCacheManager"); + cacheManagerFb.afterPropertiesSet(); + try { + CacheManager cm = (CacheManager) cacheManagerFb.getObject(); + assertTrue("Correct number of caches loaded", cm.getCacheNames().length == 1); + Cache myCache1 = cm.getCache("myCache1"); + assertFalse("myCache1 is not eternal", myCache1.isEternal()); + assertTrue("myCache1.maxElements == 300", myCache1.getMaxElementsInMemory() == 300); + } + finally { + cacheManagerFb.destroy(); + } + } + + public void testEhCacheFactoryBeanWithDefaultCacheManager() throws Exception { + doTestEhCacheFactoryBean(false); + } + + public void testEhCacheFactoryBeanWithExplicitCacheManager() throws Exception { + doTestEhCacheFactoryBean(true); + } + + private void doTestEhCacheFactoryBean(boolean useCacheManagerFb) throws Exception { + Cache cache = null; + EhCacheManagerFactoryBean cacheManagerFb = null; + try { + EhCacheFactoryBean cacheFb = new EhCacheFactoryBean(); + assertEquals(Ehcache.class, cacheFb.getObjectType()); + assertTrue("Singleton property", cacheFb.isSingleton()); + if (useCacheManagerFb) { + cacheManagerFb = new EhCacheManagerFactoryBean(); + cacheManagerFb.setConfigLocation(new ClassPathResource("testEhcache.xml", getClass())); + cacheManagerFb.afterPropertiesSet(); + cacheFb.setCacheManager((CacheManager) cacheManagerFb.getObject()); + } + + cacheFb.setCacheName("myCache1"); + cacheFb.afterPropertiesSet(); + cache = (Cache) cacheFb.getObject(); + assertEquals("myCache1", cache.getName()); + if (useCacheManagerFb){ + assertEquals("myCache1.maxElements", 300, cache.getMaxElementsInMemory()); + } + else { + assertEquals("myCache1.maxElements", 10000, cache.getMaxElementsInMemory()); + } + + // Cache region is not defined. Should create one with default properties. + cacheFb = new EhCacheFactoryBean(); + if (useCacheManagerFb) { + cacheFb.setCacheManager((CacheManager) cacheManagerFb.getObject()); + } + cacheFb.setCacheName("undefinedCache"); + cacheFb.afterPropertiesSet(); + cache = (Cache) cacheFb.getObject(); + assertEquals("undefinedCache", cache.getName()); + assertTrue("default maxElements is correct", cache.getMaxElementsInMemory() == 10000); + assertTrue("default overflowToDisk is correct", cache.isOverflowToDisk()); + assertFalse("default eternal is correct", cache.isEternal()); + assertTrue("default timeToLive is correct", cache.getTimeToLiveSeconds() == 120); + assertTrue("default timeToIdle is correct", cache.getTimeToIdleSeconds() == 120); + assertTrue("default diskPersistent is correct", !cache.isDiskPersistent()); + assertTrue("default diskExpiryThreadIntervalSeconds is correct", cache.getDiskExpiryThreadIntervalSeconds() == 120); + + // overriding the default properties + cacheFb = new EhCacheFactoryBean(); + if (useCacheManagerFb) { + cacheFb.setCacheManager((CacheManager) cacheManagerFb.getObject()); + } + cacheFb.setBeanName("undefinedCache2"); + cacheFb.setMaxElementsInMemory(5); + cacheFb.setOverflowToDisk(false); + cacheFb.setEternal(true); + cacheFb.setTimeToLive(8); + cacheFb.setTimeToIdle(7); + cacheFb.setDiskPersistent(true); + cacheFb.setDiskExpiryThreadIntervalSeconds(10); + cacheFb.afterPropertiesSet(); + cache = (Cache) cacheFb.getObject(); + + assertEquals("undefinedCache2", cache.getName()); + assertTrue("overridden maxElements is correct", cache.getMaxElementsInMemory() == 5); + assertFalse("overridden overflowToDisk is correct", cache.isOverflowToDisk()); + assertTrue("overridden eternal is correct", cache.isEternal()); + assertTrue("default timeToLive is correct", cache.getTimeToLiveSeconds() == 8); + assertTrue("default timeToIdle is correct", cache.getTimeToIdleSeconds() == 7); + assertTrue("overridden diskPersistent is correct", cache.isDiskPersistent()); + assertTrue("overridden diskExpiryThreadIntervalSeconds is correct", cache.getDiskExpiryThreadIntervalSeconds() == 10); + } + finally { + if (useCacheManagerFb) { + cacheManagerFb.destroy(); + } + else { + CacheManager.getInstance().shutdown(); + } + } + } + + public void testEhCacheFactoryBeanWithBlockingCache() throws Exception { + EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean(); + cacheManagerFb.afterPropertiesSet(); + try { + CacheManager cm = (CacheManager) cacheManagerFb.getObject(); + EhCacheFactoryBean cacheFb = new EhCacheFactoryBean(); + cacheFb.setCacheManager(cm); + cacheFb.setCacheName("myCache1"); + cacheFb.setBlocking(true); + cacheFb.afterPropertiesSet(); + Ehcache myCache1 = cm.getEhcache("myCache1"); + assertTrue(myCache1 instanceof BlockingCache); + } + finally { + cacheManagerFb.destroy(); + } + } + + public void testEhCacheFactoryBeanWithSelfPopulatingCache() throws Exception { + EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean(); + cacheManagerFb.afterPropertiesSet(); + try { + CacheManager cm = (CacheManager) cacheManagerFb.getObject(); + EhCacheFactoryBean cacheFb = new EhCacheFactoryBean(); + cacheFb.setCacheManager(cm); + cacheFb.setCacheName("myCache1"); + cacheFb.setCacheEntryFactory(new CacheEntryFactory() { + public Object createEntry(Object key) throws Exception { + return key; + } + }); + cacheFb.afterPropertiesSet(); + Ehcache myCache1 = cm.getEhcache("myCache1"); + assertTrue(myCache1 instanceof SelfPopulatingCache); + assertEquals("myKey1", myCache1.get("myKey1").getValue()); + } + finally { + cacheManagerFb.destroy(); + } + } + + public void testEhCacheFactoryBeanWithUpdatingSelfPopulatingCache() throws Exception { + EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean(); + cacheManagerFb.afterPropertiesSet(); + try { + CacheManager cm = (CacheManager) cacheManagerFb.getObject(); + EhCacheFactoryBean cacheFb = new EhCacheFactoryBean(); + cacheFb.setCacheManager(cm); + cacheFb.setCacheName("myCache1"); + cacheFb.setCacheEntryFactory(new UpdatingCacheEntryFactory() { + public Object createEntry(Object key) throws Exception { + return key; + } + public void updateEntryValue(Object key, Object value) throws Exception { + } + }); + cacheFb.afterPropertiesSet(); + Ehcache myCache1 = cm.getEhcache("myCache1"); + assertTrue(myCache1 instanceof UpdatingSelfPopulatingCache); + assertEquals("myKey1", myCache1.get("myKey1").getValue()); + } + finally { + cacheManagerFb.destroy(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/testEhcache.xml b/org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/testEhcache.xml new file mode 100644 index 00000000000..dcac796151c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/cache/ehcache/testEhcache.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/ACATester.java b/org.springframework.testsuite/src/test/java/org/springframework/context/ACATester.java new file mode 100644 index 00000000000..1bda64a785f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/ACATester.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context; + +import java.util.Locale; + +public class ACATester implements ApplicationContextAware { + + private ApplicationContext ac; + + public void setApplicationContext(ApplicationContext ctx) throws ApplicationContextException { + // check reinitialization + if (this.ac != null) { + throw new IllegalStateException("Already initialized"); + } + + // check message source availability + if (ctx != null) { + try { + ctx.getMessage("code1", null, Locale.getDefault()); + } + catch (NoSuchMessageException ex) { + // expected + } + } + + this.ac = ctx; + } + + public ApplicationContext getApplicationContext() { + return ac; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/AbstractApplicationContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/AbstractApplicationContextTests.java new file mode 100644 index 00000000000..d014d770e16 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/AbstractApplicationContextTests.java @@ -0,0 +1,157 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context; + +import java.util.Locale; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.AbstractListableBeanFactoryTests; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.LifecycleBean; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class AbstractApplicationContextTests extends AbstractListableBeanFactoryTests { + + /** Must be supplied as XML */ + public static final String TEST_NAMESPACE = "testNamespace"; + + protected ConfigurableApplicationContext applicationContext; + + /** Subclass must register this */ + protected TestListener listener = new TestListener(); + + protected TestListener parentListener = new TestListener(); + + protected void setUp() throws Exception { + this.applicationContext = createContext(); + } + + protected BeanFactory getBeanFactory() { + return applicationContext; + } + + protected ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * Must register a TestListener. + * Must register standard beans. + * Parent must register rod with name Roderick + * and father with name Albert. + */ + protected abstract ConfigurableApplicationContext createContext() throws Exception; + + public void testContextAwareSingletonWasCalledBack() throws Exception { + ACATester aca = (ACATester) applicationContext.getBean("aca"); + assertTrue("has had context set", aca.getApplicationContext() == applicationContext); + Object aca2 = applicationContext.getBean("aca"); + assertTrue("Same instance", aca == aca2); + assertTrue("Says is singleton", applicationContext.isSingleton("aca")); + } + + public void testContextAwarePrototypeWasCalledBack() throws Exception { + ACATester aca = (ACATester) applicationContext.getBean("aca-prototype"); + assertTrue("has had context set", aca.getApplicationContext() == applicationContext); + Object aca2 = applicationContext.getBean("aca-prototype"); + assertTrue("NOT Same instance", aca != aca2); + assertTrue("Says is prototype", !applicationContext.isSingleton("aca-prototype")); + } + + public void testParentNonNull() { + assertTrue("parent isn't null", applicationContext.getParent() != null); + } + + public void testGrandparentNull() { + assertTrue("grandparent is null", applicationContext.getParent().getParent() == null); + } + + public void testOverrideWorked() throws Exception { + TestBean rod = (TestBean) applicationContext.getParent().getBean("rod"); + assertTrue("Parent's name differs", rod.getName().equals("Roderick")); + } + + public void testGrandparentDefinitionFound() throws Exception { + TestBean dad = (TestBean) applicationContext.getBean("father"); + assertTrue("Dad has correct name", dad.getName().equals("Albert")); + } + + public void testGrandparentTypedDefinitionFound() throws Exception { + TestBean dad = (TestBean) applicationContext.getBean("father", TestBean.class); + assertTrue("Dad has correct name", dad.getName().equals("Albert")); + } + + public void testCloseTriggersDestroy() { + LifecycleBean lb = (LifecycleBean) applicationContext.getBean("lifecycle"); + assertTrue("Not destroyed", !lb.isDestroyed()); + applicationContext.close(); + if (applicationContext.getParent() != null) { + ((ConfigurableApplicationContext) applicationContext.getParent()).close(); + } + assertTrue("Destroyed", lb.isDestroyed()); + applicationContext.close(); + if (applicationContext.getParent() != null) { + ((ConfigurableApplicationContext) applicationContext.getParent()).close(); + } + assertTrue("Destroyed", lb.isDestroyed()); + } + + public void testMessageSource() throws NoSuchMessageException { + assertEquals("message1", applicationContext.getMessage("code1", null, Locale.getDefault())); + assertEquals("message2", applicationContext.getMessage("code2", null, Locale.getDefault())); + + try { + applicationContext.getMessage("code0", null, Locale.getDefault()); + fail("looking for code0 should throw a NoSuchMessageException"); + } + catch (NoSuchMessageException ex) { + // that's how it should be + } + } + + public void testEvents() throws Exception { + listener.zeroCounter(); + parentListener.zeroCounter(); + assertTrue("0 events before publication", listener.getEventCount() == 0); + assertTrue("0 parent events before publication", parentListener.getEventCount() == 0); + this.applicationContext.publishEvent(new MyEvent(this)); + assertTrue("1 events after publication, not " + listener.getEventCount(), listener.getEventCount() == 1); + assertTrue("1 parent events after publication", parentListener.getEventCount() == 1); + } + + public void testBeanAutomaticallyHearsEvents() throws Exception { + //String[] listenerNames = ((ListableBeanFactory) applicationContext).getBeanDefinitionNames(ApplicationListener.class); + //assertTrue("listeners include beanThatListens", Arrays.asList(listenerNames).contains("beanThatListens")); + BeanThatListens b = (BeanThatListens) applicationContext.getBean("beanThatListens"); + b.zero(); + assertTrue("0 events before publication", b.getEventCount() == 0); + this.applicationContext.publishEvent(new MyEvent(this)); + assertTrue("1 events after publication, not " + b.getEventCount(), b.getEventCount() == 1); + } + + + public static class MyEvent extends ApplicationEvent { + + public MyEvent(Object source) { + super(source); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatBroadcasts.java b/org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatBroadcasts.java new file mode 100644 index 00000000000..f525d38fe16 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatBroadcasts.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context; + +/** + * @author Juergen Hoeller + */ +public class BeanThatBroadcasts implements ApplicationContextAware { + + public ApplicationContext applicationContext; + + public int receivedCount; + + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + if (applicationContext.getDisplayName().indexOf("listener") != -1) { + applicationContext.getBean("listener"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatListens.java b/org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatListens.java new file mode 100644 index 00000000000..9ab3f8ea40d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/BeanThatListens.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context; + +import java.util.Map; + +/** + * A stub {@link ApplicationListener}. + * + * @author Thomas Risberg + * @author Juergen Hoeller + */ +public class BeanThatListens implements ApplicationListener { + + private BeanThatBroadcasts beanThatBroadcasts; + + private int eventCount; + + + public BeanThatListens() { + } + + public BeanThatListens(BeanThatBroadcasts beanThatBroadcasts) { + this.beanThatBroadcasts = beanThatBroadcasts; + Map beans = beanThatBroadcasts.applicationContext.getBeansOfType(BeanThatListens.class); + if (!beans.isEmpty()) { + throw new IllegalStateException("Shouldn't have found any BeanThatListens instances"); + } + } + + + public void onApplicationEvent(ApplicationEvent event) { + eventCount++; + if (beanThatBroadcasts != null) { + beanThatBroadcasts.receivedCount++; + } + } + + public int getEventCount() { + return eventCount; + } + + public void zero() { + eventCount = 0; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/LifecycleContextBean.java b/org.springframework.testsuite/src/test/java/org/springframework/context/LifecycleContextBean.java new file mode 100644 index 00000000000..c3aba92b5f8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/LifecycleContextBean.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.LifecycleBean; + +/** + * Simple bean to test ApplicationContext lifecycle methods for beans + * + * @author Colin Sampaleanu + * @since 03.07.2004 + */ +public class LifecycleContextBean extends LifecycleBean implements ApplicationContextAware { + + protected ApplicationContext owningContext; + + public void setBeanFactory(BeanFactory beanFactory) { + super.setBeanFactory(beanFactory); + if (this.owningContext != null) + throw new RuntimeException("Factory called setBeanFactory after setApplicationContext"); + } + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + if (this.owningContext == null) + throw new RuntimeException("Factory didn't call setAppliationContext before afterPropertiesSet on lifecycle bean"); + } + + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (this.owningFactory == null) + throw new RuntimeException("Factory called setApplicationContext before setBeanFactory"); + + this.owningContext = applicationContext; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/TestListener.java b/org.springframework.testsuite/src/test/java/org/springframework/context/TestListener.java new file mode 100644 index 00000000000..d3fb51d0511 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/TestListener.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context; + +/** + * Listener that maintains a global count of events. + * + * @author Rod Johnson + * @since January 21, 2001 + */ +public class TestListener implements ApplicationListener { + + private int eventCount; + + public int getEventCount() { + return eventCount; + } + + public void zeroCounter() { + eventCount = 0; + } + + public void onApplicationEvent(ApplicationEvent e) { + ++eventCount; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextBeanFactoryReferenceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextBeanFactoryReferenceTests.java new file mode 100644 index 00000000000..11d79f4e81d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextBeanFactoryReferenceTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.access; + +import junit.framework.TestCase; + +import org.easymock.MockControl; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Unit test for ContextBeanFactoryReference + * + * @author Colin Sampaleanu + */ +public class ContextBeanFactoryReferenceTests extends TestCase { + + public void testAllOperations() { + MockControl control = MockControl.createControl(ConfigurableApplicationContext.class); + ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) control.getMock(); + + ctx.close(); + control.replay(); + + ContextBeanFactoryReference bfr = new ContextBeanFactoryReference(ctx); + + assertNotNull(bfr.getFactory()); + bfr.release(); + + try { + bfr.getFactory(); + } + catch (IllegalStateException e) { + // expected + } + + control.verify(); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextJndiBeanFactoryLocatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextJndiBeanFactoryLocatorTests.java new file mode 100644 index 00000000000..551102540aa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextJndiBeanFactoryLocatorTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.access; + +import junit.framework.TestCase; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.access.BootstrapException; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.jndi.SimpleNamingContextBuilder; + +/** + * @author Colin Sampaleanu + */ +public class ContextJndiBeanFactoryLocatorTests extends TestCase { + + public static final String BEAN_FACTORY_PATH_ENVIRONMENT_KEY = "java:comp/env/ejb/BeanFactoryPath"; + + public void testBeanFactoryPathRequiredFromJndiEnvironment() throws Exception { + // Set up initial context but don't bind anything + SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + + ContextJndiBeanFactoryLocator jbfl = new ContextJndiBeanFactoryLocator(); + try { + jbfl.useBeanFactory(BEAN_FACTORY_PATH_ENVIRONMENT_KEY); + fail(); + } + catch (BootstrapException ex) { + // Check for helpful JNDI message + assertTrue(ex.getMessage().indexOf(BEAN_FACTORY_PATH_ENVIRONMENT_KEY) != -1); + } + } + + public void testBeanFactoryPathFromJndiEnvironmentNotFound() throws Exception { + SimpleNamingContextBuilder sncb = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + + String bogusPath = "RUBBISH/com/xxxx/framework/server/test1.xml"; + + // Set up initial context + sncb.bind(BEAN_FACTORY_PATH_ENVIRONMENT_KEY, bogusPath); + + ContextJndiBeanFactoryLocator jbfl = new ContextJndiBeanFactoryLocator(); + try { + jbfl.useBeanFactory(BEAN_FACTORY_PATH_ENVIRONMENT_KEY); + fail(); + } + catch (BeansException ex) { + // Check for helpful JNDI message + assertTrue(ex.getMessage().indexOf(bogusPath) != -1); + } + } + + public void testBeanFactoryPathFromJndiEnvironmentNotValidXml() throws Exception { + SimpleNamingContextBuilder sncb = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + + String nonXmlPath = "com/xxxx/framework/server/SlsbEndpointBean.class"; + + // Set up initial context + sncb.bind(BEAN_FACTORY_PATH_ENVIRONMENT_KEY, nonXmlPath); + + ContextJndiBeanFactoryLocator jbfl = new ContextJndiBeanFactoryLocator(); + try { + jbfl.useBeanFactory(BEAN_FACTORY_PATH_ENVIRONMENT_KEY); + fail(); + } + catch (BeansException ex) { + // Check for helpful JNDI message + assertTrue(ex.getMessage().indexOf(nonXmlPath) != -1); + } + } + + public void testBeanFactoryPathFromJndiEnvironmentWithSingleFile() throws Exception { + SimpleNamingContextBuilder sncb = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + + String path = "org/springframework/beans/factory/xml/collections.xml"; + + // Set up initial context + sncb.bind(BEAN_FACTORY_PATH_ENVIRONMENT_KEY, path); + + ContextJndiBeanFactoryLocator jbfl = new ContextJndiBeanFactoryLocator(); + BeanFactory bf = jbfl.useBeanFactory(BEAN_FACTORY_PATH_ENVIRONMENT_KEY).getFactory(); + assertTrue(bf.containsBean("rod")); + assertTrue(bf instanceof ApplicationContext); + } + + public void testBeanFactoryPathFromJndiEnvironmentWithMultipleFiles() throws Exception { + SimpleNamingContextBuilder sncb = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + + String path = "/org/springframework/beans/factory/xml/collections.xml /org/springframework/beans/factory/xml/parent.xml"; + + // Set up initial context + sncb.bind(BEAN_FACTORY_PATH_ENVIRONMENT_KEY, path); + + ContextJndiBeanFactoryLocator jbfl = new ContextJndiBeanFactoryLocator(); + BeanFactory bf = jbfl.useBeanFactory(BEAN_FACTORY_PATH_ENVIRONMENT_KEY).getFactory(); + assertTrue(bf.containsBean("rod")); + assertTrue(bf.containsBean("inheritedTestBean")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextSingletonBeanFactoryLocatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextSingletonBeanFactoryLocatorTests.java new file mode 100644 index 00000000000..32068bd0098 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/access/ContextSingletonBeanFactoryLocatorTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.access; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.access.BeanFactoryLocator; +import org.springframework.beans.factory.access.BeanFactoryReference; +import org.springframework.beans.factory.access.SingletonBeanFactoryLocatorTests; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.util.ClassUtils; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + */ +public class ContextSingletonBeanFactoryLocatorTests extends SingletonBeanFactoryLocatorTests { + + public void testBaseBeanFactoryDefs() { + // Just test the base BeanFactory/AppContext defs we are going to work + // with in other tests. + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + new String[] {"/org/springframework/beans/factory/access/beans1.xml", + "/org/springframework/beans/factory/access/beans2.xml"}); + } + + public void testBasicFunctionality() { + // Just use definition file from the SingletonBeanFactoryLocator test, + // since it is completely valid. + ContextSingletonBeanFactoryLocator facLoc = new ContextSingletonBeanFactoryLocator( + "classpath*:" + ClassUtils.addResourcePathToPackagePath( + SingletonBeanFactoryLocatorTests.class, "ref1.xml")); + + basicFunctionalityTest(facLoc); + + BeanFactoryReference bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + BeanFactory fac = bfr.getFactory(); + assertTrue(fac instanceof ApplicationContext); + assertEquals("a.qualified.name.of.some.sort", ((ApplicationContext) fac).getId()); + assertEquals("a.qualified.name.of.some.sort", ((ApplicationContext) fac).getDisplayName()); + BeanFactoryReference bfr2 = facLoc.useBeanFactory("another.qualified.name"); + BeanFactory fac2 = bfr2.getFactory(); + assertEquals("another.qualified.name", ((ApplicationContext) fac2).getId()); + assertEquals("another.qualified.name", ((ApplicationContext) fac2).getDisplayName()); + assertTrue(fac2 instanceof ApplicationContext); + } + + /** + * This test can run multiple times, but due to static keyed lookup of the locators, + * 2nd and subsequent calls will actuall get back same locator instance. This is not + * really an issue, since the contained bean factories will still be loaded and released. + */ + public void testGetInstance() { + // Try with and without 'classpath*:' prefix, and with 'classpath:' prefix. + BeanFactoryLocator facLoc = ContextSingletonBeanFactoryLocator.getInstance( + ClassUtils.addResourcePathToPackagePath( + SingletonBeanFactoryLocatorTests.class, "ref1.xml")); + getInstanceTest1(facLoc); + + facLoc = ContextSingletonBeanFactoryLocator.getInstance( + "classpath*:" + ClassUtils.addResourcePathToPackagePath( + SingletonBeanFactoryLocatorTests.class, "ref1.xml")); + getInstanceTest2(facLoc); + + // This will actually get another locator instance, as the key is the resource name. + facLoc = ContextSingletonBeanFactoryLocator.getInstance( + "classpath:" + ClassUtils.addResourcePathToPackagePath( + SingletonBeanFactoryLocatorTests.class, "ref1.xml")); + getInstanceTest3(facLoc); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/access/DefaultLocatorFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/access/DefaultLocatorFactoryTests.java new file mode 100644 index 00000000000..3d0aa67148b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/access/DefaultLocatorFactoryTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.access; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.access.BeanFactoryLocator; + +/** + * @author Colin Sampaleanu + */ +public class DefaultLocatorFactoryTests extends TestCase { + + /* + * Class to test for BeanFactoryLocator getInstance() + */ + public void testGetInstance() { + BeanFactoryLocator bf = DefaultLocatorFactory.getInstance(); + BeanFactoryLocator bf2 = DefaultLocatorFactory.getInstance(); + assertTrue(bf.equals(bf2)); + } + + /* + * Class to test for BeanFactoryLocator getInstance(String) + */ + public void testGetInstanceString() { + BeanFactoryLocator bf = DefaultLocatorFactory.getInstance("my-bean-refs.xml"); + BeanFactoryLocator bf2 = DefaultLocatorFactory.getInstance("my-bean-refs.xml"); + assertTrue(bf.equals(bf2)); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java new file mode 100644 index 00000000000..3c45157c242 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.config; + +import java.util.Date; +import java.util.Map; + +import junit.framework.TestCase; +import org.springframework.beans.factory.config.PropertyOverrideConfigurer; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Arjen Poutsma + * @since 2.5.6 + */ +public class ContextNamespaceHandlerTests extends TestCase { + + private ApplicationContext applicationContext; + + protected void setUp() throws Exception { + applicationContext = new ClassPathXmlApplicationContext("contextNamespaceHandlerTests.xml", getClass()); + } + + public void testPropertyPlaceholder() throws Exception { + Map beans = applicationContext.getBeansOfType(PropertyPlaceholderConfigurer.class); + assertFalse("No PropertyPlaceHolderConfigurer found", beans.isEmpty()); + String s = (String) applicationContext.getBean("string"); + assertEquals("No properties replaced", "bar", s); + } + + public void testPropertyOverride() throws Exception { + Map beans = applicationContext.getBeansOfType(PropertyOverrideConfigurer.class); + assertFalse("No PropertyOverrideConfigurer found", beans.isEmpty()); + Date date = (Date) applicationContext.getBean("date"); + assertEquals("No properties overriden", 42, date.getMinutes()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/config/contextNamespaceHandlerTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/config/contextNamespaceHandlerTests.xml new file mode 100644 index 00000000000..c0b09682602 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/config/contextNamespaceHandlerTests.xml @@ -0,0 +1,27 @@ + + + + + bar + + + + + + + + + + 42 + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java new file mode 100644 index 00000000000..9069496e4ee --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java @@ -0,0 +1,208 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.event; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; +import org.easymock.internal.AlwaysMatcher; +import org.easymock.internal.EqualsMatcher; + +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanCurrentlyInCreationException; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.BeanThatBroadcasts; +import org.springframework.context.BeanThatListens; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.test.AssertThrows; + +/** + * Unit and integration tests for the ApplicationContext event support. + * + * @author Alef Arendsen + * @author Rick Evans + */ +public class ApplicationContextEventTests extends TestCase { + + private AbstractApplicationEventMulticaster getMulticaster() { + return new AbstractApplicationEventMulticaster() { + public void multicastEvent(ApplicationEvent event) { + } + }; + } + + public void testMulticasterNewCollectionClass() { + AbstractApplicationEventMulticaster mc = getMulticaster(); + + mc.addApplicationListener(new NoOpApplicationListener()); + + mc.setCollectionClass(ArrayList.class); + + assertEquals(1, mc.getApplicationListeners().size()); + assertEquals(ArrayList.class, mc.getApplicationListeners().getClass()); + } + + public void testMulticasterInvalidCollectionClass_NotEvenACollectionType() { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + AbstractApplicationEventMulticaster mc = getMulticaster(); + mc.setCollectionClass(ApplicationContextEventTests.class); + } + }.runTest(); + } + + public void testMulticasterInvalidCollectionClass_PassingAnInterfaceNotAConcreteClass() { + new AssertThrows(FatalBeanException.class) { + public void test() throws Exception { + AbstractApplicationEventMulticaster mc = getMulticaster(); + mc.setCollectionClass(List.class); + } + }.runTest(); + } + + public void testMulticasterNullCollectionClass() { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + AbstractApplicationEventMulticaster mc = getMulticaster(); + mc.setCollectionClass(null); + } + }.runTest(); + } + + public void testMulticasterRemoveAll() { + AbstractApplicationEventMulticaster mc = getMulticaster(); + mc.addApplicationListener(new NoOpApplicationListener()); + mc.removeAllListeners(); + + assertEquals(0, mc.getApplicationListeners().size()); + } + + public void testMulticasterRemoveOne() { + AbstractApplicationEventMulticaster mc = getMulticaster(); + ApplicationListener one = new NoOpApplicationListener(); + ApplicationListener two = new NoOpApplicationListener(); + mc.addApplicationListener(one); + mc.addApplicationListener(two); + + mc.removeApplicationListener(one); + + assertEquals(1, mc.getApplicationListeners().size()); + assertTrue("Remaining listener present", mc.getApplicationListeners().contains(two)); + } + + public void testSimpleApplicationEventMulticaster() { + MockControl ctrl = MockControl.createControl(ApplicationListener.class); + ApplicationListener listener = (ApplicationListener) ctrl.getMock(); + + ApplicationEvent evt = new ContextClosedEvent(new StaticApplicationContext()); + listener.onApplicationEvent(evt); + ctrl.setMatcher(new EqualsMatcher()); + + SimpleApplicationEventMulticaster smc = new SimpleApplicationEventMulticaster(); + smc.addApplicationListener(listener); + + ctrl.replay(); + + smc.multicastEvent(evt); + + ctrl.verify(); + } + + public void testEvenPublicationInterceptor() throws Throwable { + MockControl invCtrl = MockControl.createControl(MethodInvocation.class); + MethodInvocation invocation = (MethodInvocation) invCtrl.getMock(); + + MockControl ctxCtrl = MockControl.createControl(ApplicationContext.class); + ApplicationContext ctx = (ApplicationContext) ctxCtrl.getMock(); + + EventPublicationInterceptor interceptor = + new EventPublicationInterceptor(); + interceptor.setApplicationEventClass(MyEvent.class); + interceptor.setApplicationEventPublisher(ctx); + interceptor.afterPropertiesSet(); + + invocation.proceed(); + invCtrl.setReturnValue(new Object()); + + invocation.getThis(); + invCtrl.setReturnValue(new Object()); + ctx.publishEvent(new MyEvent(new Object())); + ctxCtrl.setDefaultMatcher(new AlwaysMatcher()); + + ctxCtrl.replay(); + invCtrl.replay(); + + interceptor.invoke(invocation); + + ctxCtrl.verify(); + invCtrl.verify(); + } + + public void testListenerAndBroadcasterWithUnresolvableCircularReference() { + StaticApplicationContext context = new StaticApplicationContext(); + context.setDisplayName("listener context"); + context.registerBeanDefinition("broadcaster", new RootBeanDefinition(BeanThatBroadcasts.class)); + RootBeanDefinition listenerDef = new RootBeanDefinition(BeanThatListens.class); + listenerDef.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("broadcaster")); + context.registerBeanDefinition("listener", listenerDef); + try { + context.refresh(); + fail("Should have thrown BeanCreationException with nested BeanCurrentlyInCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.contains(BeanCurrentlyInCreationException.class)); + } + } + + public void testListenerAndBroadcasterWithResolvableCircularReference() { + StaticApplicationContext context = new StaticApplicationContext(); + context.registerBeanDefinition("broadcaster", new RootBeanDefinition(BeanThatBroadcasts.class)); + RootBeanDefinition listenerDef = new RootBeanDefinition(BeanThatListens.class); + listenerDef.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("broadcaster")); + context.registerBeanDefinition("listener", listenerDef); + context.refresh(); + + BeanThatBroadcasts broadcaster = (BeanThatBroadcasts) context.getBean("broadcaster"); + context.publishEvent(new MyEvent(context)); + assertEquals("The event was not received by the listener", 2, broadcaster.receivedCount); + } + + + public static class MyEvent extends ApplicationEvent { + + public MyEvent(Object source) { + super(source); + } + } + + + private static final class NoOpApplicationListener implements ApplicationListener { + + public void onApplicationEvent(ApplicationEvent event) { + } + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java new file mode 100644 index 00000000000..8f4f919073a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.event; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.ITestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.TestListener; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.test.AssertThrows; + +/** + * @author Dmitriy Kopylenko + * @author Juergen Hoeller + * @author Rick Evans + */ +public class EventPublicationInterceptorTests extends TestCase { + + public void testWithNoApplicationEventClassSupplied() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); + ApplicationContext ctx = new StaticApplicationContext(); + interceptor.setApplicationEventPublisher(ctx); + interceptor.afterPropertiesSet(); + } + }.runTest(); + } + + public void testWithNonApplicationEventClassSupplied() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); + ApplicationContext ctx = new StaticApplicationContext(); + interceptor.setApplicationEventPublisher(ctx); + interceptor.setApplicationEventClass(getClass()); + interceptor.afterPropertiesSet(); + } + }.runTest(); + } + + public void testWithAbstractStraightApplicationEventClassSupplied() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); + ApplicationContext ctx = new StaticApplicationContext(); + interceptor.setApplicationEventPublisher(ctx); + interceptor.setApplicationEventClass(ApplicationEvent.class); + interceptor.afterPropertiesSet(); + } + }.runTest(); + } + + public void testWithApplicationEventClassThatDoesntExposeAValidCtor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); + ApplicationContext ctx = new StaticApplicationContext(); + interceptor.setApplicationEventPublisher(ctx); + interceptor.setApplicationEventClass(TestEventWithNoValidOneArgObjectCtor.class); + interceptor.afterPropertiesSet(); + } + }.runTest(); + } + + public void testExpectedBehavior() throws Exception { + TestBean target = new TestBean(); + final TestListener listener = new TestListener(); + + class TestContext extends StaticApplicationContext { + protected void onRefresh() throws BeansException { + addListener(listener); + } + } + + StaticApplicationContext ctx = new TestContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("applicationEventClass", TestEvent.class.getName()); + // should automatically receive applicationEventPublisher reference + ctx.registerSingleton("publisher", EventPublicationInterceptor.class, pvs); + ctx.registerSingleton("otherListener", FactoryBeanTestListener.class); + ctx.refresh(); + + EventPublicationInterceptor interceptor = + (EventPublicationInterceptor) ctx.getBean("publisher"); + ProxyFactory factory = new ProxyFactory(target); + factory.addAdvice(0, interceptor); + + ITestBean testBean = (ITestBean) factory.getProxy(); + + // invoke any method on the advised proxy to see if the interceptor has been invoked + testBean.getAge(); + + // two events: ContextRefreshedEvent and TestEvent + assertTrue("Interceptor must have published 2 events", listener.getEventCount() == 2); + TestListener otherListener = (TestListener) ctx.getBean("&otherListener"); + assertTrue("Interceptor must have published 2 events", otherListener.getEventCount() == 2); + } + + + public static class TestEvent extends ApplicationEvent { + + public TestEvent(Object source) { + super(source); + } + } + + + public static final class TestEventWithNoValidOneArgObjectCtor extends ApplicationEvent { + + public TestEventWithNoValidOneArgObjectCtor() { + super(""); + } + } + + + public static class FactoryBeanTestListener extends TestListener implements FactoryBean { + + public Object getObject() throws Exception { + return "test"; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/event/LifecycleEventTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/event/LifecycleEventTests.java new file mode 100644 index 00000000000..5fa2f37ccf5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/event/LifecycleEventTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.event; + +import junit.framework.TestCase; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.Lifecycle; +import org.springframework.context.support.StaticApplicationContext; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class LifecycleEventTests extends TestCase { + + public void testContextStartedEvent() { + StaticApplicationContext context = new StaticApplicationContext(); + context.registerSingleton("lifecycle", LifecycleTestBean.class); + context.registerSingleton("listener", LifecycleListener.class); + context.refresh(); + LifecycleTestBean lifecycleBean = (LifecycleTestBean) context.getBean("lifecycle"); + LifecycleListener listener = (LifecycleListener) context.getBean("listener"); + assertFalse(lifecycleBean.isRunning()); + assertEquals(0, listener.getStartedCount()); + context.start(); + assertTrue(lifecycleBean.isRunning()); + assertEquals(1, listener.getStartedCount()); + assertSame(context, listener.getApplicationContext()); + } + + public void testContextStoppedEvent() { + StaticApplicationContext context = new StaticApplicationContext(); + context.registerSingleton("lifecycle", LifecycleTestBean.class); + context.registerSingleton("listener", LifecycleListener.class); + context.refresh(); + LifecycleTestBean lifecycleBean = (LifecycleTestBean) context.getBean("lifecycle"); + LifecycleListener listener = (LifecycleListener) context.getBean("listener"); + assertFalse(lifecycleBean.isRunning()); + context.start(); + assertTrue(lifecycleBean.isRunning()); + assertEquals(0, listener.getStoppedCount()); + context.stop(); + assertFalse(lifecycleBean.isRunning()); + assertEquals(1, listener.getStoppedCount()); + assertSame(context, listener.getApplicationContext()); + } + + + private static class LifecycleListener implements ApplicationListener { + + private ApplicationContext context; + + private int startedCount; + + private int stoppedCount; + + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ContextStartedEvent) { + this.context = ((ContextStartedEvent) event).getApplicationContext(); + this.startedCount++; + } + else if (event instanceof ContextStoppedEvent) { + this.context = ((ContextStoppedEvent) event).getApplicationContext(); + this.stoppedCount++; + } + } + + public ApplicationContext getApplicationContext() { + return this.context; + } + + public int getStartedCount() { + return this.startedCount; + } + + public int getStoppedCount() { + return this.stoppedCount; + } + } + + + private static class LifecycleTestBean implements Lifecycle { + + private boolean running; + + public boolean isRunning() { + return this.running; + } + + public void start() { + this.running = true; + } + + public void stop() { + this.running = false; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/ApplicationContextLifecycleTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ApplicationContextLifecycleTests.java new file mode 100644 index 00000000000..4e46cc786af --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ApplicationContextLifecycleTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import junit.framework.TestCase; + +/** + * @author Mark Fisher + */ +public class ApplicationContextLifecycleTests extends TestCase { + + public void testBeansStart() { + AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass()); + context.start(); + LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1"); + LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2"); + LifecycleTestBean bean3 = (LifecycleTestBean) context.getBean("bean3"); + LifecycleTestBean bean4 = (LifecycleTestBean) context.getBean("bean4"); + String error = "bean was not started"; + assertTrue(error, bean1.isRunning()); + assertTrue(error, bean2.isRunning()); + assertTrue(error, bean3.isRunning()); + assertTrue(error, bean4.isRunning()); + } + + public void testBeansStop() { + AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass()); + context.start(); + LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1"); + LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2"); + LifecycleTestBean bean3 = (LifecycleTestBean) context.getBean("bean3"); + LifecycleTestBean bean4 = (LifecycleTestBean) context.getBean("bean4"); + String startError = "bean was not started"; + assertTrue(startError, bean1.isRunning()); + assertTrue(startError, bean2.isRunning()); + assertTrue(startError, bean3.isRunning()); + assertTrue(startError, bean4.isRunning()); + context.stop(); + String stopError = "bean was not stopped"; + assertFalse(stopError, bean1.isRunning()); + assertFalse(stopError, bean2.isRunning()); + assertFalse(stopError, bean3.isRunning()); + assertFalse(stopError, bean4.isRunning()); + } + + public void testStartOrder() { + AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass()); + context.start(); + LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1"); + LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2"); + LifecycleTestBean bean3 = (LifecycleTestBean) context.getBean("bean3"); + LifecycleTestBean bean4 = (LifecycleTestBean) context.getBean("bean4"); + String notStartedError = "bean was not started"; + assertTrue(notStartedError, bean1.getStartOrder() > 0); + assertTrue(notStartedError, bean2.getStartOrder() > 0); + assertTrue(notStartedError, bean3.getStartOrder() > 0); + assertTrue(notStartedError, bean4.getStartOrder() > 0); + String orderError = "dependent bean must start after the bean it depends on"; + assertTrue(orderError, bean2.getStartOrder() > bean1.getStartOrder()); + assertTrue(orderError, bean3.getStartOrder() > bean2.getStartOrder()); + assertTrue(orderError, bean4.getStartOrder() > bean2.getStartOrder()); + } + + public void testStopOrder() { + AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass()); + context.start(); + context.stop(); + LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1"); + LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2"); + LifecycleTestBean bean3 = (LifecycleTestBean) context.getBean("bean3"); + LifecycleTestBean bean4 = (LifecycleTestBean) context.getBean("bean4"); + String notStoppedError = "bean was not stopped"; + assertTrue(notStoppedError, bean1.getStopOrder() > 0); + assertTrue(notStoppedError, bean2.getStopOrder() > 0); + assertTrue(notStoppedError, bean3.getStopOrder() > 0); + assertTrue(notStoppedError, bean4.getStopOrder() > 0); + String orderError = "dependent bean must stop before the bean it depends on"; + assertTrue(orderError, bean2.getStopOrder() < bean1.getStopOrder()); + assertTrue(orderError, bean3.getStopOrder() < bean2.getStopOrder()); + assertTrue(orderError, bean4.getStopOrder() < bean2.getStopOrder()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/Assembler.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/Assembler.java new file mode 100644 index 00000000000..f3171912192 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/Assembler.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +/** + * @author Alef Arendsen + */ +public class Assembler implements TestIF { + + private Service service; + private Logic l; + private String name; + + public void setService(Service service) { + this.service = service; + } + + public void setLogic(Logic l) { + this.l = l; + } + + public void setBeanName(String name) { + this.name = name; + } + + public void test() { + } + + public void output() { + System.out.println("Bean " + name); + l.output(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/AutowiredService.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/AutowiredService.java new file mode 100644 index 00000000000..285e8348bde --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/AutowiredService.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import org.springframework.context.MessageSource; + +/** + * @author Juergen Hoeller + */ +public class AutowiredService { + + private MessageSource messageSource; + + public void setMessageSource(MessageSource messageSource) { + if (this.messageSource != null) { + throw new IllegalArgumentException("MessageSource should not be set twice"); + } + this.messageSource = messageSource; + } + + public MessageSource getMessageSource() { + return messageSource; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/ClassPathXmlApplicationContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ClassPathXmlApplicationContextTests.java new file mode 100644 index 00000000000..4f1c6c0b6a7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ClassPathXmlApplicationContextTests.java @@ -0,0 +1,371 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ResourceTestBean; +import org.springframework.beans.TypeMismatchException; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.CannotLoadBeanClassException; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ApplicationListener; +import org.springframework.context.MessageSource; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.ObjectUtils; + +/** + * @author Juergen Hoeller + */ +public class ClassPathXmlApplicationContextTests extends TestCase { + + public void testSingleConfigLocation() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/simpleContext.xml"); + assertTrue(ctx.containsBean("someMessageSource")); + ctx.close(); + } + + public void testMultipleConfigLocations() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + new String[] { + "/org/springframework/context/support/test/contextB.xml", + "/org/springframework/context/support/test/contextC.xml", + "/org/springframework/context/support/test/contextA.xml"}); + assertTrue(ctx.containsBean("service")); + assertTrue(ctx.containsBean("logicOne")); + assertTrue(ctx.containsBean("logicTwo")); + Service service = (Service) ctx.getBean("service"); + ctx.refresh(); + assertTrue(service.isProperlyDestroyed()); + service = (Service) ctx.getBean("service"); + ctx.close(); + assertTrue(service.isProperlyDestroyed()); + } + + public void testConfigLocationPattern() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/test/context*.xml"); + assertTrue(ctx.containsBean("service")); + assertTrue(ctx.containsBean("logicOne")); + assertTrue(ctx.containsBean("logicTwo")); + Service service = (Service) ctx.getBean("service"); + ctx.close(); + assertTrue(service.isProperlyDestroyed()); + } + + public void testSingleConfigLocationWithClass() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "simpleContext.xml", getClass()); + assertTrue(ctx.containsBean("someMessageSource")); + ctx.close(); + } + + public void testAliasWithPlaceholder() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + new String[] { + "/org/springframework/context/support/test/contextB.xml", + "/org/springframework/context/support/test/aliased-contextC.xml", + "/org/springframework/context/support/test/contextA.xml"}); + assertTrue(ctx.containsBean("service")); + assertTrue(ctx.containsBean("logicOne")); + assertTrue(ctx.containsBean("logicTwo")); + ctx.refresh(); + } + + public void testContextWithInvalidValueType() throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + new String[] {"/org/springframework/context/support/invalidValueType.xml"}, false); + try { + context.refresh(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.contains(TypeMismatchException.class)); + assertTrue(ex.toString().indexOf("someMessageSource") != -1); + assertTrue(ex.toString().indexOf("useCodeAsDefaultMessage") != -1); + checkExceptionFromInvalidValueType(ex); + checkExceptionFromInvalidValueType(new ExceptionInInitializerError(ex)); + assertFalse(context.isActive()); + } + } + + private void checkExceptionFromInvalidValueType(Throwable ex) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ex.printStackTrace(new PrintStream(baos)); + String dump = FileCopyUtils.copyToString( + new InputStreamReader(new ByteArrayInputStream(baos.toByteArray()))); + assertTrue(dump.indexOf("someMessageSource") != -1); + assertTrue(dump.indexOf("useCodeAsDefaultMessage") != -1); + } + + public void testContextWithInvalidLazyClass() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "invalidClass.xml", getClass()); + assertTrue(ctx.containsBean("someMessageSource")); + try { + ctx.getBean("someMessageSource"); + fail("Should have thrown CannotLoadBeanClassException"); + } + catch (CannotLoadBeanClassException ex) { + assertTrue(ex.contains(ClassNotFoundException.class)); + } + ctx.close(); + } + + public void testContextWithClassNameThatContainsPlaceholder() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "classWithPlaceholder.xml", getClass()); + assertTrue(ctx.containsBean("someMessageSource")); + assertTrue(ctx.getBean("someMessageSource") instanceof StaticMessageSource); + ctx.close(); + } + + public void testMultipleConfigLocationsWithClass() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + new String[] {"test/contextB.xml", "test/contextC.xml", "test/contextA.xml"}, getClass()); + assertTrue(ctx.containsBean("service")); + assertTrue(ctx.containsBean("logicOne")); + assertTrue(ctx.containsBean("logicTwo")); + ctx.close(); + } + + public void testFactoryBeanAndApplicationListener() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/test/context*.xml"); + ctx.getBeanFactory().registerSingleton("manualFBAAL", new FactoryBeanAndApplicationListener()); + assertEquals(2, ctx.getBeansOfType(ApplicationListener.class).size()); + ctx.close(); + } + + public void testMessageSourceAware() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/test/context*.xml"); + MessageSource messageSource = (MessageSource) ctx.getBean("messageSource"); + Service service1 = (Service) ctx.getBean("service"); + assertEquals(ctx, service1.getMessageSource()); + Service service2 = (Service) ctx.getBean("service2"); + assertEquals(ctx, service2.getMessageSource()); + AutowiredService autowiredService1 = (AutowiredService) ctx.getBean("autowiredService"); + assertEquals(messageSource, autowiredService1.getMessageSource()); + AutowiredService autowiredService2 = (AutowiredService) ctx.getBean("autowiredService2"); + assertEquals(messageSource, autowiredService2.getMessageSource()); + ctx.close(); + } + + public void testResourceArrayPropertyEditor() throws IOException { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/test/context*.xml"); + Service service = (Service) ctx.getBean("service"); + assertEquals(3, service.getResources().length); + List resources = Arrays.asList(service.getResources()); + assertTrue(resources.contains( + new FileSystemResource(new ClassPathResource("/org/springframework/context/support/test/contextA.xml").getFile()))); + assertTrue(resources.contains( + new FileSystemResource(new ClassPathResource("/org/springframework/context/support/test/contextB.xml").getFile()))); + assertTrue(resources.contains( + new FileSystemResource(new ClassPathResource("/org/springframework/context/support/test/contextC.xml").getFile()))); + ctx.close(); + } + + public void testChildWithProxy() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/test/context*.xml"); + ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext( + new String[] {"/org/springframework/context/support/childWithProxy.xml"}, ctx); + assertTrue(AopUtils.isAopProxy(child.getBean("assemblerOne"))); + assertTrue(AopUtils.isAopProxy(child.getBean("assemblerTwo"))); + ctx.close(); + } + + public void testAliasForParentContext() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/simpleContext.xml"); + assertTrue(ctx.containsBean("someMessageSource")); + + ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext( + new String[] {"/org/springframework/context/support/aliasForParent.xml"}, ctx); + assertTrue(child.containsBean("someMessageSource")); + assertTrue(child.containsBean("yourMessageSource")); + assertTrue(child.containsBean("myMessageSource")); + assertTrue(child.isSingleton("someMessageSource")); + assertTrue(child.isSingleton("yourMessageSource")); + assertTrue(child.isSingleton("myMessageSource")); + assertEquals(StaticMessageSource.class, child.getType("someMessageSource")); + assertEquals(StaticMessageSource.class, child.getType("yourMessageSource")); + assertEquals(StaticMessageSource.class, child.getType("myMessageSource")); + + Object someMs = child.getBean("someMessageSource"); + Object yourMs = child.getBean("yourMessageSource"); + Object myMs = child.getBean("myMessageSource"); + assertSame(someMs, yourMs); + assertSame(someMs, myMs); + + String[] aliases = child.getAliases("someMessageSource"); + assertEquals(2, aliases.length); + assertEquals("myMessageSource", aliases[0]); + assertEquals("yourMessageSource", aliases[1]); + aliases = child.getAliases("myMessageSource"); + assertEquals(2, aliases.length); + assertEquals("someMessageSource", aliases[0]); + assertEquals("yourMessageSource", aliases[1]); + + child.close(); + ctx.close(); + } + + public void testAliasThatOverridesParent() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/org/springframework/context/support/simpleContext.xml"); + Object someMs = ctx.getBean("someMessageSource"); + + ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext( + new String[] {"/org/springframework/context/support/aliasThatOverridesParent.xml"}, ctx); + Object myMs = child.getBean("myMessageSource"); + Object someMs2 = child.getBean("someMessageSource"); + assertSame(myMs, someMs2); + assertNotSame(someMs, someMs2); + assertOneMessageSourceOnly(child, myMs); + } + + public void testAliasThatOverridesEarlierBean() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + new String[] {"/org/springframework/context/support/simpleContext.xml", + "/org/springframework/context/support/aliasThatOverridesParent.xml"}); + Object myMs = ctx.getBean("myMessageSource"); + Object someMs2 = ctx.getBean("someMessageSource"); + assertSame(myMs, someMs2); + assertOneMessageSourceOnly(ctx, myMs); + } + + private void assertOneMessageSourceOnly(ClassPathXmlApplicationContext ctx, Object myMessageSource) { + String[] beanNamesForType = ctx.getBeanNamesForType(StaticMessageSource.class); + assertEquals(1, beanNamesForType.length); + assertEquals("myMessageSource", beanNamesForType[0]); + beanNamesForType = ctx.getBeanNamesForType(StaticMessageSource.class, true, true); + assertEquals(1, beanNamesForType.length); + assertEquals("myMessageSource", beanNamesForType[0]); + beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(ctx, StaticMessageSource.class); + assertEquals(1, beanNamesForType.length); + assertEquals("myMessageSource", beanNamesForType[0]); + beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(ctx, StaticMessageSource.class, true, true); + assertEquals(1, beanNamesForType.length); + assertEquals("myMessageSource", beanNamesForType[0]); + + Map beansOfType = ctx.getBeansOfType(StaticMessageSource.class); + assertEquals(1, beansOfType.size()); + assertSame(myMessageSource, beansOfType.values().iterator().next()); + beansOfType = ctx.getBeansOfType(StaticMessageSource.class, true, true); + assertEquals(1, beansOfType.size()); + assertSame(myMessageSource, beansOfType.values().iterator().next()); + beansOfType = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, StaticMessageSource.class); + assertEquals(1, beansOfType.size()); + assertSame(myMessageSource, beansOfType.values().iterator().next()); + beansOfType = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, StaticMessageSource.class, true, true); + assertEquals(1, beansOfType.size()); + assertSame(myMessageSource, beansOfType.values().iterator().next()); + } + + public void testResourceAndInputStream() throws IOException { + ClassPathXmlApplicationContext ctx = + new ClassPathXmlApplicationContext("/org/springframework/beans/factory/xml/resource.xml") { + public Resource getResource(String location) { + if ("classpath:org/springframework/beans/factory/xml/test.properties".equals(location)) { + return new ClassPathResource("test.properties", ClassPathXmlApplicationContextTests.class); + } + return super.getResource(location); + } + }; + ResourceTestBean resource1 = (ResourceTestBean) ctx.getBean("resource1"); + ResourceTestBean resource2 = (ResourceTestBean) ctx.getBean("resource2"); + assertTrue(resource1.getResource() instanceof ClassPathResource); + StringWriter writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource1.getResource().getInputStream()), writer); + assertEquals("contexttest", writer.toString()); + writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource1.getInputStream()), writer); + assertEquals("contexttest", writer.toString()); + writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource2.getResource().getInputStream()), writer); + assertEquals("contexttest", writer.toString()); + writer = new StringWriter(); + FileCopyUtils.copy(new InputStreamReader(resource2.getInputStream()), writer); + assertEquals("contexttest", writer.toString()); + ctx.close(); + } + + public void testGenericApplicationContextWithXmlBeanDefinitions() { + GenericApplicationContext ctx = new GenericApplicationContext(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(ctx); + reader.loadBeanDefinitions(new ClassPathResource("test/contextB.xml", getClass())); + reader.loadBeanDefinitions(new ClassPathResource("test/contextC.xml", getClass())); + reader.loadBeanDefinitions(new ClassPathResource("test/contextA.xml", getClass())); + ctx.refresh(); + assertTrue(ctx.containsBean("service")); + assertTrue(ctx.containsBean("logicOne")); + assertTrue(ctx.containsBean("logicTwo")); + ctx.close(); + } + + public void testGenericApplicationContextWithXmlBeanDefinitionsAndClassLoaderNull() { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.setClassLoader(null); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(ctx); + reader.loadBeanDefinitions(new ClassPathResource("test/contextB.xml", getClass())); + reader.loadBeanDefinitions(new ClassPathResource("test/contextC.xml", getClass())); + reader.loadBeanDefinitions(new ClassPathResource("test/contextA.xml", getClass())); + ctx.refresh(); + assertEquals(ObjectUtils.identityToString(ctx), ctx.getId()); + assertEquals(ObjectUtils.identityToString(ctx), ctx.getDisplayName()); + assertTrue(ctx.containsBean("service")); + assertTrue(ctx.containsBean("logicOne")); + assertTrue(ctx.containsBean("logicTwo")); + ctx.close(); + } + + public void testGenericApplicationContextWithXmlBeanDefinitionsAndSpecifiedId() { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.setId("testContext"); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(ctx); + reader.loadBeanDefinitions(new ClassPathResource("test/contextB.xml", getClass())); + reader.loadBeanDefinitions(new ClassPathResource("test/contextC.xml", getClass())); + reader.loadBeanDefinitions(new ClassPathResource("test/contextA.xml", getClass())); + ctx.refresh(); + assertEquals("testContext", ctx.getId()); + assertEquals("testContext", ctx.getDisplayName()); + assertTrue(ctx.containsBean("service")); + assertTrue(ctx.containsBean("logicOne")); + assertTrue(ctx.containsBean("logicTwo")); + ctx.close(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/FactoryBeanAndApplicationListener.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/FactoryBeanAndApplicationListener.java new file mode 100644 index 00000000000..b0a90824d44 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/FactoryBeanAndApplicationListener.java @@ -0,0 +1,28 @@ +package org.springframework.context.support; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +/** + * @author Juergen Hoeller + * @since 06.10.2004 + */ +public class FactoryBeanAndApplicationListener implements FactoryBean, ApplicationListener { + + public Object getObject() throws Exception { + return ""; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + + public void onApplicationEvent(ApplicationEvent event) { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/LifecycleTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/LifecycleTestBean.java new file mode 100644 index 00000000000..8c220888378 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/LifecycleTestBean.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import org.springframework.context.Lifecycle; + +/** + * @author Mark Fisher + */ +public class LifecycleTestBean implements Lifecycle { + + private static int startCounter; + + private static int stopCounter; + + + private int startOrder; + + private int stopOrder; + + private boolean running; + + + public int getStartOrder() { + return startOrder; + } + + public int getStopOrder() { + return stopOrder; + } + + public boolean isRunning() { + return this.running; + } + + public void start() { + this.startOrder = ++startCounter; + this.running = true; + } + + public void stop() { + this.stopOrder = ++stopCounter; + this.running = false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/Logic.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/Logic.java new file mode 100644 index 00000000000..ee1974670ce --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/Logic.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanNameAware; + + +public class Logic implements BeanNameAware { + + private Log log = LogFactory.getLog(Logic.class); + private String name; + private Assembler a; + + public void setAssembler(Assembler a) { + this.a = a; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String) + */ + public void setBeanName(String name) { + this.name = name; + } + + public void output() { + System.out.println("Bean " + name); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java new file mode 100644 index 00000000000..6379d9a791f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java @@ -0,0 +1,270 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import java.util.Locale; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.core.JdkVersion; + +/** + * @author Juergen Hoeller + * @since 03.02.2004 + */ +public class ResourceBundleMessageSourceTests extends TestCase { + + public void testMessageAccessWithDefaultMessageSource() { + doTestMessageAccess(false, true, false, false, false); + } + + public void testMessageAccessWithDefaultMessageSourceAndMessageFormat() { + doTestMessageAccess(false, true, false, false, true); + } + + public void testMessageAccessWithDefaultMessageSourceAndFallbackToGerman() { + doTestMessageAccess(false, true, true, true, false); + } + + public void testMessageAccessWithReloadableMessageSource() { + doTestMessageAccess(true, true, false, false, false); + } + + public void testMessageAccessWithReloadableMessageSourceAndMessageFormat() { + doTestMessageAccess(true, true, false, false, true); + } + + public void testMessageAccessWithReloadableMessageSourceAndFallbackToGerman() { + doTestMessageAccess(true, true, true, true, false); + } + + public void testMessageAccessWithReloadableMessageSourceAndFallbackTurnedOff() { + doTestMessageAccess(true, false, false, false, false); + } + + public void testMessageAccessWithReloadableMessageSourceAndFallbackTurnedOffAndFallbackToGerman() { + doTestMessageAccess(true, false, true, true, false); + } + + protected void doTestMessageAccess( + boolean reloadable, boolean fallbackToSystemLocale, + boolean expectGermanFallback, boolean useCodeAsDefaultMessage, boolean alwaysUseMessageFormat) { + + StaticApplicationContext ac = new StaticApplicationContext(); + if (reloadable) { + StaticApplicationContext parent = new StaticApplicationContext(); + parent.refresh(); + ac.setParent(parent); + } + + MutablePropertyValues pvs = new MutablePropertyValues(); + String basepath = "org/springframework/context/support/"; + String[] basenames = null; + if (reloadable) { + basenames = new String[] { + "classpath:" + basepath + "messages", + "classpath:" + basepath + "more-messages"}; + } + else { + basenames = new String[] { + basepath + "messages", + basepath + "more-messages"}; + } + pvs.addPropertyValue("basenames", basenames); + if (!fallbackToSystemLocale) { + pvs.addPropertyValue("fallbackToSystemLocale", Boolean.FALSE); + } + if (useCodeAsDefaultMessage) { + pvs.addPropertyValue("useCodeAsDefaultMessage", Boolean.TRUE); + } + if (alwaysUseMessageFormat) { + pvs.addPropertyValue("alwaysUseMessageFormat", Boolean.TRUE); + } + Class clazz = reloadable ? + (Class) ReloadableResourceBundleMessageSource.class : ResourceBundleMessageSource.class; + ac.registerSingleton("messageSource", clazz, pvs); + ac.refresh(); + + Locale.setDefault(expectGermanFallback ? Locale.GERMAN : Locale.CANADA); + assertEquals("message1", ac.getMessage("code1", null, Locale.ENGLISH)); + assertEquals(fallbackToSystemLocale && expectGermanFallback ? "nachricht2" : "message2", + ac.getMessage("code2", null, Locale.ENGLISH)); + + assertEquals("nachricht2", ac.getMessage("code2", null, Locale.GERMAN)); + assertEquals("nochricht2", ac.getMessage("code2", null, new Locale("DE", "at"))); + assertEquals("noochricht2", ac.getMessage("code2", null, new Locale("DE", "at", "oo"))); + + if (reloadable && JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) { + assertEquals("nachricht2xml", ac.getMessage("code2", null, Locale.GERMANY)); + } + + MessageSourceAccessor accessor = new MessageSourceAccessor(ac); + LocaleContextHolder.setLocale(new Locale("DE", "at")); + try { + assertEquals("nochricht2", accessor.getMessage("code2")); + } + finally { + LocaleContextHolder.setLocale(null); + } + + assertEquals("message3", ac.getMessage("code3", null, Locale.ENGLISH)); + MessageSourceResolvable resolvable = new DefaultMessageSourceResolvable("code3"); + assertEquals("message3", ac.getMessage(resolvable, Locale.ENGLISH)); + resolvable = new DefaultMessageSourceResolvable(new String[] {"code4", "code3"}); + assertEquals("message3", ac.getMessage(resolvable, Locale.ENGLISH)); + + assertEquals("message3", ac.getMessage("code3", null, Locale.ENGLISH)); + resolvable = new DefaultMessageSourceResolvable(new String[] {"code4", "code3"}); + assertEquals("message3", ac.getMessage(resolvable, Locale.ENGLISH)); + + Object[] args = new Object[] {"Hello", new DefaultMessageSourceResolvable(new String[] {"code1"})}; + assertEquals("Hello, message1", ac.getMessage("hello", args, Locale.ENGLISH)); + + // test default message without and with args + assertEquals("default", ac.getMessage(null, null, "default", Locale.ENGLISH)); + assertEquals("default", ac.getMessage(null, args, "default", Locale.ENGLISH)); + assertEquals("{0}, default", ac.getMessage(null, null, "{0}, default", Locale.ENGLISH)); + assertEquals("Hello, default", ac.getMessage(null, args, "{0}, default", Locale.ENGLISH)); + + // test resolvable with default message, without and with args + resolvable = new DefaultMessageSourceResolvable(null, null, "default"); + assertEquals("default", ac.getMessage(resolvable, Locale.ENGLISH)); + resolvable = new DefaultMessageSourceResolvable(null, args, "default"); + assertEquals("default", ac.getMessage(resolvable, Locale.ENGLISH)); + resolvable = new DefaultMessageSourceResolvable(null, null, "{0}, default"); + assertEquals("{0}, default", ac.getMessage(resolvable, Locale.ENGLISH)); + resolvable = new DefaultMessageSourceResolvable(null, args, "{0}, default"); + assertEquals("Hello, default", ac.getMessage(resolvable, Locale.ENGLISH)); + + // test message args + assertEquals("Arg1, Arg2", ac.getMessage("hello", new Object[] {"Arg1", "Arg2"}, Locale.ENGLISH)); + assertEquals("{0}, {1}", ac.getMessage("hello", null, Locale.ENGLISH)); + + if (alwaysUseMessageFormat) { + assertEquals("I'm", ac.getMessage("escaped", null, Locale.ENGLISH)); + } + else { + assertEquals("I''m", ac.getMessage("escaped", null, Locale.ENGLISH)); + } + assertEquals("I'm", ac.getMessage("escaped", new Object[] {"some arg"}, Locale.ENGLISH)); + + try { + assertEquals("code4", ac.getMessage("code4", null, Locale.GERMAN)); + if (!useCodeAsDefaultMessage) { + fail("Should have thrown NoSuchMessageException"); + } + } + catch (NoSuchMessageException ex) { + if (useCodeAsDefaultMessage) { + fail("Should have returned code as default message"); + } + } + } + + public void testDefaultApplicationContextMessageSource() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.refresh(); + assertEquals("default", ac.getMessage("code1", null, "default", Locale.ENGLISH)); + assertEquals("default value", ac.getMessage("code1", new Object[] {"value"}, "default {0}", Locale.ENGLISH)); + } + + public void testResourceBundleMessageSourceStandalone() { + ResourceBundleMessageSource ms = new ResourceBundleMessageSource(); + ms.setBasename("org/springframework/context/support/messages"); + assertEquals("message1", ms.getMessage("code1", null, Locale.ENGLISH)); + assertEquals("nachricht2", ms.getMessage("code2", null, Locale.GERMAN)); + } + + public void testResourceBundleMessageSourceWithWhitespaceInBasename() { + ResourceBundleMessageSource ms = new ResourceBundleMessageSource(); + ms.setBasename(" org/springframework/context/support/messages "); + assertEquals("message1", ms.getMessage("code1", null, Locale.ENGLISH)); + assertEquals("nachricht2", ms.getMessage("code2", null, Locale.GERMAN)); + } + + public void testReloadableResourceBundleMessageSourceStandalone() { + ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource(); + ms.setBasename("org/springframework/context/support/messages"); + assertEquals("message1", ms.getMessage("code1", null, Locale.ENGLISH)); + assertEquals("nachricht2", ms.getMessage("code2", null, Locale.GERMAN)); + } + + public void testReloadableResourceBundleMessageSourceWithWhitespaceInBasename() { + ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource(); + ms.setBasename(" org/springframework/context/support/messages "); + assertEquals("message1", ms.getMessage("code1", null, Locale.ENGLISH)); + assertEquals("nachricht2", ms.getMessage("code2", null, Locale.GERMAN)); + } + + public void testReloadableResourceBundleMessageSourceWithDefaultCharset() { + ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource(); + ms.setBasename("org/springframework/context/support/messages"); + ms.setDefaultEncoding("ISO-8859-1"); + assertEquals("message1", ms.getMessage("code1", null, Locale.ENGLISH)); + assertEquals("nachricht2", ms.getMessage("code2", null, Locale.GERMAN)); + } + + public void testReloadableResourceBundleMessageSourceWithInappropriateDefaultCharset() { + ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource(); + ms.setBasename("org/springframework/context/support/messages"); + ms.setDefaultEncoding("unicode"); + Properties fileCharsets = new Properties(); + fileCharsets.setProperty("org/springframework/context/support/messages_de", "unicode"); + ms.setFileEncodings(fileCharsets); + ms.setFallbackToSystemLocale(false); + try { + ms.getMessage("code1", null, Locale.ENGLISH); + fail("Should have thrown NoSuchMessageException"); + } + catch (NoSuchMessageException ex) { + // expected + } + } + + public void testReloadableResourceBundleMessageSourceWithInappropriateEnglishCharset() { + ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource(); + ms.setBasename("org/springframework/context/support/messages"); + ms.setFallbackToSystemLocale(false); + Properties fileCharsets = new Properties(); + fileCharsets.setProperty("org/springframework/context/support/messages", "unicode"); + ms.setFileEncodings(fileCharsets); + try { + ms.getMessage("code1", null, Locale.ENGLISH); + fail("Should have thrown NoSuchMessageException"); + } + catch (NoSuchMessageException ex) { + // expected + } + } + + public void testReloadableResourceBundleMessageSourceWithInappropriateGermanCharset() { + ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource(); + ms.setBasename("org/springframework/context/support/messages"); + ms.setFallbackToSystemLocale(false); + Properties fileCharsets = new Properties(); + fileCharsets.setProperty("org/springframework/context/support/messages_de", "unicode"); + ms.setFileEncodings(fileCharsets); + assertEquals("message1", ms.getMessage("code1", null, Locale.ENGLISH)); + assertEquals("message2", ms.getMessage("code2", null, Locale.GERMAN)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceMapFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceMapFactoryBeanTests.java new file mode 100644 index 00000000000..d45c2f7084d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/ResourceMapFactoryBeanTests.java @@ -0,0 +1,75 @@ +package org.springframework.context.support; + +import java.util.Map; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * @author Juergen Hoeller + * @since 25.04.2004 + */ +public class ResourceMapFactoryBeanTests extends TestCase { + + public void testResourceMapFactoryBeanWithoutContext() { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + Properties props = new Properties(); + props.setProperty("test1", "classpath:org/springframework/context/support/contextA.xml"); + props.setProperty("test2", "classpath:org/springframework/context/support/contextB.xml"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", props); + RootBeanDefinition bd = new RootBeanDefinition(ResourceMapFactoryBean.class, pvs); + beanFactory.registerBeanDefinition("resourceMap", bd); + Map result = (Map) beanFactory.getBean("resourceMap"); + assertEquals(2, result.size()); + assertTrue(result.get("test1") instanceof ClassPathResource); + assertTrue(((Resource) result.get("test1")).getDescription().indexOf("contextA.xml") != -1); + assertTrue(((Resource) result.get("test2")).getDescription().indexOf("contextB.xml") != -1); + } + + public void testResourceMapFactoryBeanWithContext() { + StaticApplicationContext context = new StaticApplicationContext() { + public Resource getResource(String location) { + return super.getResource("classpath:org/springframework/context/support/context" + location); + } + }; + DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory(); + Properties props = new Properties(); + props.setProperty("test1", "A.xml"); + props.setProperty("test2", "B.xml"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", props); + RootBeanDefinition bd = new RootBeanDefinition(ResourceMapFactoryBean.class, pvs); + beanFactory.registerBeanDefinition("resourceMap", bd); + context.refresh(); + Map result = (Map) beanFactory.getBean("resourceMap"); + assertEquals(2, result.size()); + assertTrue(result.get("test1") instanceof ClassPathResource); + assertTrue(((Resource) result.get("test1")).getDescription().indexOf("contextA.xml") != -1); + assertTrue(((Resource) result.get("test2")).getDescription().indexOf("contextB.xml") != -1); + } + + public void testResourceMapFactoryBeanWithResourceBasePath() { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + Properties props = new Properties(); + props.setProperty("test1", "A.xml"); + props.setProperty("test2", "B.xml"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", props); + pvs.addPropertyValue("resourceBasePath", "classpath:org/springframework/context/support/context"); + RootBeanDefinition bd = new RootBeanDefinition(ResourceMapFactoryBean.class, pvs); + beanFactory.registerBeanDefinition("resourceMap", bd); + Map result = (Map) beanFactory.getBean("resourceMap"); + assertEquals(2, result.size()); + assertTrue(result.get("test1") instanceof ClassPathResource); + assertTrue(((Resource) result.get("test1")).getDescription().indexOf("contextA.xml") != -1); + assertTrue(((Resource) result.get("test2")).getDescription().indexOf("contextB.xml") != -1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/Service.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/Service.java new file mode 100644 index 00000000000..8778978bd80 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/Service.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import org.springframework.beans.factory.BeanCreationNotAllowedException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; + +/** + * @author Alef Arendsen + * @author Juergen Hoeller + */ +public class Service implements ApplicationContextAware, MessageSourceAware, DisposableBean { + + private ApplicationContext applicationContext; + + private MessageSource messageSource; + + private Resource[] resources; + + private boolean properlyDestroyed = false; + + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + public void setMessageSource(MessageSource messageSource) { + if (this.messageSource != null) { + throw new IllegalArgumentException("MessageSource should not be set twice"); + } + this.messageSource = messageSource; + } + + public MessageSource getMessageSource() { + return messageSource; + } + + public void setResources(Resource[] resources) { + this.resources = resources; + } + + public Resource[] getResources() { + return resources; + } + + + public void destroy() { + this.properlyDestroyed = true; + Thread thread = new Thread() { + public void run() { + Assert.isTrue(applicationContext.getBean("messageSource") instanceof StaticMessageSource); + try { + applicationContext.getBean("service2"); + // Should have thrown BeanCreationNotAllowedException + properlyDestroyed = false; + } + catch (BeanCreationNotAllowedException ex) { + // expected + } + } + }; + thread.start(); + try { + thread.join(); + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + public boolean isProperlyDestroyed() { + return properlyDestroyed; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextMulticasterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextMulticasterTests.java new file mode 100644 index 00000000000..9bfe88b2cc2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextMulticasterTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; +import org.springframework.context.ACATester; +import org.springframework.context.AbstractApplicationContextTests; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.BeanThatListens; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.event.SimpleApplicationEventMulticaster; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.EncodedResource; + +/** + * Tests for static application context with custom application event multicaster. + * + * @author Juergen Hoeller + */ +public class StaticApplicationContextMulticasterTests extends AbstractApplicationContextTests { + + protected StaticApplicationContext sac; + + /** Run for each test */ + protected ConfigurableApplicationContext createContext() throws Exception { + StaticApplicationContext parent = new StaticApplicationContext(); + Map m = new HashMap(); + m.put("name", "Roderick"); + parent.registerPrototype("rod", TestBean.class, new MutablePropertyValues(m)); + m.put("name", "Albert"); + parent.registerPrototype("father", TestBean.class, new MutablePropertyValues(m)); + parent.registerSingleton(StaticApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, + TestApplicationEventMulticaster.class, null); + parent.refresh(); + parent.addListener(parentListener) ; + + parent.getStaticMessageSource().addMessage("code1", Locale.getDefault(), "message1"); + + this.sac = new StaticApplicationContext(parent); + sac.registerSingleton("beanThatListens", BeanThatListens.class, new MutablePropertyValues()); + sac.registerSingleton("aca", ACATester.class, new MutablePropertyValues()); + sac.registerPrototype("aca-prototype", ACATester.class, new MutablePropertyValues()); + PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(sac.getDefaultListableBeanFactory()); + Resource resource = new ClassPathResource("testBeans.properties", getClass()); + reader.loadBeanDefinitions(new EncodedResource(resource, "ISO-8859-1")); + sac.refresh(); + sac.addListener(listener); + + sac.getStaticMessageSource().addMessage("code2", Locale.getDefault(), "message2"); + + return sac; + } + + /** Overridden */ + public void testCount() { + assertCount(15); + } + + public void testEvents() throws Exception { + TestApplicationEventMulticaster.counter = 0; + super.testEvents(); + assertEquals(1, TestApplicationEventMulticaster.counter); + } + + + public static class TestApplicationEventMulticaster extends SimpleApplicationEventMulticaster { + + private static int counter = 0; + + public void multicastEvent(ApplicationEvent event) { + super.multicastEvent(event); + counter++; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextTests.java new file mode 100644 index 00000000000..d98528b2306 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticApplicationContextTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; +import org.springframework.context.ACATester; +import org.springframework.context.AbstractApplicationContextTests; +import org.springframework.context.BeanThatListens; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.io.ClassPathResource; + +/** + * Tests for static application context. + * + * @author Rod Johnson + */ +public class StaticApplicationContextTests extends AbstractApplicationContextTests { + + protected StaticApplicationContext sac; + + /** Run for each test */ + protected ConfigurableApplicationContext createContext() throws Exception { + StaticApplicationContext parent = new StaticApplicationContext(); + Map m = new HashMap(); + m.put("name", "Roderick"); + parent.registerPrototype("rod", TestBean.class, new MutablePropertyValues(m)); + m.put("name", "Albert"); + parent.registerPrototype("father", TestBean.class, new MutablePropertyValues(m)); + parent.refresh(); + parent.addListener(parentListener) ; + + parent.getStaticMessageSource().addMessage("code1", Locale.getDefault(), "message1"); + + this.sac = new StaticApplicationContext(parent); + sac.registerSingleton("beanThatListens", BeanThatListens.class, new MutablePropertyValues()); + sac.registerSingleton("aca", ACATester.class, new MutablePropertyValues()); + sac.registerPrototype("aca-prototype", ACATester.class, new MutablePropertyValues()); + PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(sac.getDefaultListableBeanFactory()); + reader.loadBeanDefinitions(new ClassPathResource("testBeans.properties", getClass())); + sac.refresh(); + sac.addListener(listener); + + sac.getStaticMessageSource().addMessage("code2", Locale.getDefault(), "message2"); + + return sac; + } + + /** Overridden */ + public void testCount() { + assertCount(15); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticMessageSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticMessageSourceTests.java new file mode 100644 index 00000000000..47e72fb9116 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/StaticMessageSourceTests.java @@ -0,0 +1,262 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; +import org.springframework.context.ACATester; +import org.springframework.context.AbstractApplicationContextTests; +import org.springframework.context.BeanThatListens; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class StaticMessageSourceTests extends AbstractApplicationContextTests { + + protected static final String MSG_TXT1_US = + "At '{1,time}' on \"{1,date}\", there was \"{2}\" on planet {0,number,integer}."; + protected static final String MSG_TXT1_UK = + "At '{1,time}' on \"{1,date}\", there was \"{2}\" on station number {0,number,integer}."; + protected static final String MSG_TXT2_US = + "This is a test message in the message catalog with no args."; + protected static final String MSG_TXT3_US = + "This is another test message in the message catalog with no args."; + + protected StaticApplicationContext sac; + + /** Overridden */ + public void testCount() { + // These are only checked for current Ctx (not parent ctx) + assertCount(15); + } + + public void testMessageSource() throws NoSuchMessageException { + // Do nothing here since super is looking for errorCodes we + // do NOT have in the Context + } + + public void testGetMessageWithDefaultPassedInAndFoundInMsgCatalog() { + // Try with Locale.US + assertTrue("valid msg from staticMsgSource with default msg passed in returned msg from msg catalog for Locale.US", + sac.getMessage("message.format.example2", null, "This is a default msg if not found in MessageSource.", Locale.US) + .equals("This is a test message in the message catalog with no args.")); + } + + public void testGetMessageWithDefaultPassedInAndNotFoundInMsgCatalog() { + // Try with Locale.US + assertTrue("bogus msg from staticMsgSource with default msg passed in returned default msg for Locale.US", + sac.getMessage("bogus.message", null, "This is a default msg if not found in MessageSource.", Locale.US) + .equals("This is a default msg if not found in MessageSource.")); + } + + /** + * We really are testing the AbstractMessageSource class here. + * The underlying implementation uses a hashMap to cache messageFormats + * once a message has been asked for. This test is an attempt to + * make sure the cache is being used properly. + * @see org.springframework.context.support.AbstractMessageSource for more details. + */ + public void testGetMessageWithMessageAlreadyLookedFor() { + Object[] arguments = { + new Integer(7), new Date(System.currentTimeMillis()), + "a disturbance in the Force" + }; + + // The first time searching, we don't care about for this test + // Try with Locale.US + sac.getMessage("message.format.example1", arguments, Locale.US); + + // Now msg better be as expected + assertTrue("2nd search within MsgFormat cache returned expected message for Locale.US", + sac.getMessage("message.format.example1", arguments, Locale.US).indexOf( + "there was \"a disturbance in the Force\" on planet 7.") != -1); + + Object[] newArguments = { + new Integer(8), new Date(System.currentTimeMillis()), + "a disturbance in the Force" + }; + + // Now msg better be as expected even with different args + assertTrue("2nd search within MsgFormat cache with different args returned expected message for Locale.US", + sac.getMessage("message.format.example1", newArguments, Locale.US) + .indexOf("there was \"a disturbance in the Force\" on planet 8.") != -1); + } + + /** + * Example taken from the javadocs for the java.text.MessageFormat class + */ + public void testGetMessageWithNoDefaultPassedInAndFoundInMsgCatalog() { + Object[] arguments = { + new Integer(7), new Date(System.currentTimeMillis()), + "a disturbance in the Force" + }; + + /* + Try with Locale.US + Since the msg has a time value in it, we will use String.indexOf(...) + to just look for a substring without the time. This is because it is + possible that by the time we store a time variable in this method + and the time the ResourceBundleMessageSource resolves the msg the + minutes of the time might not be the same. + */ + assertTrue("msg from staticMsgSource for Locale.US substituting args for placeholders is as expected", + sac.getMessage("message.format.example1", arguments, Locale.US) + .indexOf("there was \"a disturbance in the Force\" on planet 7.") != -1); + + // Try with Locale.UK + assertTrue("msg from staticMsgSource for Locale.UK substituting args for placeholders is as expected", + sac.getMessage("message.format.example1", arguments, Locale.UK) + .indexOf("there was \"a disturbance in the Force\" on station number 7.") != -1); + + // Try with Locale.US - Use a different test msg that requires no args + assertTrue("msg from staticMsgSource for Locale.US that requires no args is as expected", + sac.getMessage("message.format.example2", null, Locale.US) + .equals("This is a test message in the message catalog with no args.")); + } + + public void testGetMessageWithNoDefaultPassedInAndNotFoundInMsgCatalog() { + // Expecting an exception + try { + // Try with Locale.US + sac.getMessage("bogus.message", null, Locale.US); + + fail("bogus msg from staticMsgSource for Locale.US without default msg should have thrown exception"); + } + catch (NoSuchMessageException tExcept) { + assertTrue("bogus msg from staticMsgSource for Locale.US without default msg threw expected exception", true); + } + } + + public void testMessageSourceResolvable() { + // first code valid + String[] codes1 = new String[] {"message.format.example3", "message.format.example2"}; + MessageSourceResolvable resolvable1 = new DefaultMessageSourceResolvable(codes1, null, "default"); + try { + assertTrue("correct message retrieved", MSG_TXT3_US.equals(sac.getMessage(resolvable1, Locale.US))); + } + catch (NoSuchMessageException ex) { + fail("Should not throw NoSuchMessageException"); + } + + // only second code valid + String[] codes2 = new String[] {"message.format.example99", "message.format.example2"}; + MessageSourceResolvable resolvable2 = new DefaultMessageSourceResolvable(codes2, null, "default"); + try { + assertTrue("correct message retrieved", MSG_TXT2_US.equals(sac.getMessage(resolvable2, Locale.US))); + } + catch (NoSuchMessageException ex) { + fail("Should not throw NoSuchMessageException"); + } + + // no code valid, but default given + String[] codes3 = new String[] {"message.format.example99", "message.format.example98"}; + MessageSourceResolvable resolvable3 = new DefaultMessageSourceResolvable(codes3, null, "default"); + try { + assertTrue("correct message retrieved", "default".equals(sac.getMessage(resolvable3, Locale.US))); + } + catch (NoSuchMessageException ex) { + fail("Should not throw NoSuchMessageException"); + } + + // no code valid, no default + String[] codes4 = new String[] {"message.format.example99", "message.format.example98"}; + MessageSourceResolvable resolvable4 = new DefaultMessageSourceResolvable(codes4); + try { + sac.getMessage(resolvable4, Locale.US); + fail("Should have thrown NoSuchMessageException"); + } + catch (NoSuchMessageException ex) { + // expected + } + } + + /** Run for each test */ + protected ConfigurableApplicationContext createContext() throws Exception { + StaticApplicationContext parent = new StaticApplicationContext(); + + Map m = new HashMap(); + m.put("name", "Roderick"); + parent.registerPrototype("rod", org.springframework.beans.TestBean.class, new MutablePropertyValues(m)); + m.put("name", "Albert"); + parent.registerPrototype("father", org.springframework.beans.TestBean.class, new MutablePropertyValues(m)); + + parent.refresh(); + parent.addListener(parentListener); + + this.sac = new StaticApplicationContext(parent); + + sac.registerSingleton("beanThatListens", BeanThatListens.class, new MutablePropertyValues()); + + sac.registerSingleton("aca", ACATester.class, new MutablePropertyValues()); + + sac.registerPrototype("aca-prototype", ACATester.class, new MutablePropertyValues()); + + PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(sac.getDefaultListableBeanFactory()); + reader.loadBeanDefinitions(new ClassPathResource("testBeans.properties", getClass())); + sac.refresh(); + sac.addListener(listener); + + StaticMessageSource messageSource = sac.getStaticMessageSource(); + Map usMessages = new HashMap(3); + usMessages.put("message.format.example1", MSG_TXT1_US); + usMessages.put("message.format.example2", MSG_TXT2_US); + usMessages.put("message.format.example3", MSG_TXT3_US); + messageSource.addMessages(usMessages, Locale.US); + messageSource.addMessage("message.format.example1", Locale.UK, MSG_TXT1_UK); + + return sac; + } + + public void testNestedMessageSourceWithParamInChild() { + StaticMessageSource source = new StaticMessageSource(); + StaticMessageSource parent = new StaticMessageSource(); + source.setParentMessageSource(parent); + + source.addMessage("param", Locale.ENGLISH, "value"); + parent.addMessage("with.param", Locale.ENGLISH, "put {0} here"); + + MessageSourceResolvable resolvable = new DefaultMessageSourceResolvable( + new String[] {"with.param"}, new Object[] {new DefaultMessageSourceResolvable("param")}); + + assertEquals("put value here", source.getMessage(resolvable, Locale.ENGLISH)); + } + + public void testNestedMessageSourceWithParamInParent() { + StaticMessageSource source = new StaticMessageSource(); + StaticMessageSource parent = new StaticMessageSource(); + source.setParentMessageSource(parent); + + parent.addMessage("param", Locale.ENGLISH, "value"); + source.addMessage("with.param", Locale.ENGLISH, "put {0} here"); + + MessageSourceResolvable resolvable = new DefaultMessageSourceResolvable( + new String[] {"with.param"}, new Object[] {new DefaultMessageSourceResolvable("param")}); + + assertEquals("put value here", source.getMessage(resolvable, Locale.ENGLISH)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/TestIF.java b/org.springframework.testsuite/src/test/java/org/springframework/context/support/TestIF.java new file mode 100644 index 00000000000..d458965dc3d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/TestIF.java @@ -0,0 +1,21 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +public interface TestIF { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasForParent.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasForParent.xml new file mode 100644 index 00000000000..3f66e034998 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasForParent.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasThatOverridesParent.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasThatOverridesParent.xml new file mode 100644 index 00000000000..8ab5e584a42 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/aliasThatOverridesParent.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/childWithProxy.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/childWithProxy.xml new file mode 100644 index 00000000000..ec31bf6e574 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/childWithProxy.xml @@ -0,0 +1,28 @@ + + + + + + + + + true + + + PROPAGATION_REQUIRED + + + + + + + + true + + + PROPAGATION_REQUIRED + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/classWithPlaceholder.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/classWithPlaceholder.xml new file mode 100644 index 00000000000..e2dcc3fff10 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/classWithPlaceholder.xml @@ -0,0 +1,17 @@ + + + + + + + + + StaticMessageSource + singleton + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidClass.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidClass.xml new file mode 100644 index 00000000000..3e7509aec74 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidClass.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidValueType.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidValueType.xml new file mode 100644 index 00000000000..6a07f13fbab --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/invalidValueType.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/lifecycleTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/lifecycleTests.xml new file mode 100644 index 00000000000..f38a0d3d747 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/lifecycleTests.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages.properties new file mode 100644 index 00000000000..90fb2bb9b22 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages.properties @@ -0,0 +1,5 @@ + code1 = mess\ + age1 +code2=message2 +hello={0}, {1} +escaped=I''m diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de.properties new file mode 100644 index 00000000000..a9a00b17a0d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de.properties @@ -0,0 +1 @@ +code2=nachricht2 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT.properties new file mode 100644 index 00000000000..1f363cc4732 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT.properties @@ -0,0 +1 @@ +code2=nochricht2 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT_oo.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT_oo.properties new file mode 100644 index 00000000000..b0a94283a08 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_AT_oo.properties @@ -0,0 +1 @@ +code2=noochricht2 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_DE.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_DE.xml new file mode 100644 index 00000000000..fe84234b5f1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/messages_de_DE.xml @@ -0,0 +1,8 @@ + + + + + + nachricht2xml + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/more-messages.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/more-messages.properties new file mode 100644 index 00000000000..1a76f24fc98 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/more-messages.properties @@ -0,0 +1 @@ +code3=message3 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/override.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/override.properties new file mode 100644 index 00000000000..37e7f13ad0a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/override.properties @@ -0,0 +1,2 @@ +wrappedAssemblerOne.proxyTargetClass=true +wrappedAssemblerTwo.proxyTargetClass=true diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/placeholder.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/placeholder.properties new file mode 100644 index 00000000000..6c9d0976218 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/placeholder.properties @@ -0,0 +1,3 @@ +targetName=wrappedAssemblerOne +logicName=logicTwo +realLogicName=realLogic diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/simpleContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/simpleContext.xml new file mode 100644 index 00000000000..c32ed74147c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/simpleContext.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/test.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test.properties new file mode 100644 index 00000000000..6cfa0eae111 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test.properties @@ -0,0 +1 @@ +contexttest \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/aliased-contextC.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/aliased-contextC.xml new file mode 100644 index 00000000000..3c46c30820f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/aliased-contextC.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextA.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextA.xml new file mode 100644 index 00000000000..55f9cdfd699 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextA.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PROPAGATION_REQUIRED + + + + + + + + + + + PROPAGATION_REQUIRED + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextB.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextB.xml new file mode 100644 index 00000000000..261ce0698b6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextB.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextC.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextC.xml new file mode 100644 index 00000000000..c1abb93e2a3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/contextC.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/import1.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/import1.xml new file mode 100644 index 00000000000..f49285b811f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/import1.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/subtest/import2.xml b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/subtest/import2.xml new file mode 100644 index 00000000000..74b2f73fd27 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/test/subtest/import2.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/context/support/testBeans.properties b/org.springframework.testsuite/src/test/java/org/springframework/context/support/testBeans.properties new file mode 100644 index 00000000000..1eab846bc5e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/context/support/testBeans.properties @@ -0,0 +1,42 @@ +# this must only be used for ApplicationContexts, some classes are only appropriate for application contexts + +rod.(class)=org.springframework.beans.TestBean +rod.name=Rod +rod.age=31 + +roderick.(parent)=rod +roderick.name=Roderick + +kerry.(class)=org.springframework.beans.TestBean +kerry.name=Kerry +kerry.age=34 +kerry.spouse(ref)=rod + +kathy.(class)=org.springframework.beans.TestBean +kathy.(singleton)=false + +typeMismatch.(class)=org.springframework.beans.TestBean +typeMismatch.name=typeMismatch +typeMismatch.age=34x +typeMismatch.spouse(ref)=rod +typeMismatch.(singleton)=false + +validEmpty.(class)=org.springframework.beans.TestBean + +listenerVeto.(class)=org.springframework.beans.TestBean + +typeMismatch.name=typeMismatch +typeMismatch.age=34x +typeMismatch.spouse(ref)=rod + +singletonFactory.(class)=org.springframework.beans.factory.DummyFactory +singletonFactory.singleton=true + +prototypeFactory.(class)=org.springframework.beans.factory.DummyFactory +prototypeFactory.singleton=false + +mustBeInitialized.(class)=org.springframework.beans.factory.MustBeInitialized + +lifecycle.(class)=org.springframework.context.LifecycleContextBean + +lifecyclePostProcessor.(class)=org.springframework.beans.factory.LifecycleBean$PostProcessor diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/AbstractControlFlowTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/AbstractControlFlowTests.java new file mode 100644 index 00000000000..2136a269d9f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/AbstractControlFlowTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + */ +public abstract class AbstractControlFlowTests extends TestCase { + + protected abstract ControlFlow createControlFlow(); + + /* + * Class to test for boolean under(Class) + */ + public void testUnderClassAndMethod() { + new One().test(); + new Two().testing(); + new Three().test(); + } + + /* + public void testUnderPackage() { + ControlFlow cflow = new ControlFlow(); + assertFalse(cflow.underPackage("org.springframework.aop")); + assertTrue(cflow.underPackage("org.springframework.aop.support")); + assertFalse(cflow.underPackage("com.interface21")); + } + */ + + + public class One { + + public void test() { + ControlFlow cflow = createControlFlow(); + assertTrue(cflow.under(One.class)); + assertTrue(cflow.under(AbstractControlFlowTests.class)); + assertFalse(cflow.under(Two.class)); + assertTrue(cflow.under(One.class, "test")); + assertFalse(cflow.under(One.class, "hashCode")); + } + + } + + + public class Two { + + public void testing() { + ControlFlow cflow = createControlFlow(); + assertTrue(cflow.under(Two.class)); + assertTrue(cflow.under(AbstractControlFlowTests.class)); + assertFalse(cflow.under(One.class)); + assertFalse(cflow.under(Two.class, "test")); + assertTrue(cflow.under(Two.class, "testing")); + } + } + + + public class Three { + + public void test() { + testing(); + } + + private void testing() { + ControlFlow cflow = createControlFlow(); + assertTrue(cflow.under(Three.class)); + assertTrue(cflow.under(AbstractControlFlowTests.class)); + assertFalse(cflow.under(One.class)); + assertTrue(cflow.under(Three.class, "test")); + assertTrue(cflow.under(Three.class, "testing")); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/AttributeAccessorSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/AttributeAccessorSupportTests.java new file mode 100644 index 00000000000..d35b1b34fd9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/AttributeAccessorSupportTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import junit.framework.TestCase; + +import java.util.Arrays; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class AttributeAccessorSupportTests extends TestCase { + + private static final String NAME = "foo"; + + private static final String VALUE = "bar"; + + private AttributeAccessor attributeAccessor; + + protected void setUp() throws Exception { + this.attributeAccessor = new AttributeAccessorSupport() { + }; + } + + public void testSetAndGet() throws Exception { + this.attributeAccessor.setAttribute(NAME, VALUE); + assertEquals(VALUE, this.attributeAccessor.getAttribute(NAME)); + } + + public void testSetAndHas() throws Exception { + assertFalse(this.attributeAccessor.hasAttribute(NAME)); + this.attributeAccessor.setAttribute(NAME, VALUE); + assertTrue(this.attributeAccessor.hasAttribute(NAME)); + } + + public void testRemove() throws Exception { + assertFalse(this.attributeAccessor.hasAttribute(NAME)); + this.attributeAccessor.setAttribute(NAME, VALUE); + assertEquals(VALUE, this.attributeAccessor.removeAttribute(NAME)); + assertFalse(this.attributeAccessor.hasAttribute(NAME)); + } + + public void testAttributeNames() throws Exception { + this.attributeAccessor.setAttribute(NAME, VALUE); + this.attributeAccessor.setAttribute("abc", "123"); + String[] attributeNames = this.attributeAccessor.attributeNames(); + Arrays.sort(attributeNames); + assertTrue(Arrays.binarySearch(attributeNames, NAME) > -1); + assertTrue(Arrays.binarySearch(attributeNames, "abc") > -1); + } + protected void tearDown() throws Exception { + this.attributeAccessor.removeAttribute(NAME); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/CollectionFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/CollectionFactoryTests.java new file mode 100644 index 00000000000..2bdd6df41a0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/CollectionFactoryTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +/** + * @author Darren Davison + * @author Juergen Hoeller + */ +public class CollectionFactoryTests extends TestCase { + + public void testLinkedSet() { + Set set = CollectionFactory.createLinkedSetIfPossible(16); + assertTrue(set instanceof LinkedHashSet); + } + + public void testLinkedMap() { + Map map = CollectionFactory.createLinkedMapIfPossible(16); + assertTrue(map instanceof LinkedHashMap); + } + + public void testIdentityMap() { + Map map = CollectionFactory.createIdentityMapIfPossible(16); + assertTrue(map instanceof IdentityHashMap); + } + + public void testConcurrentMap() { + Map map = CollectionFactory.createConcurrentMapIfPossible(16); + assertTrue(map.getClass().getName().endsWith("ConcurrentHashMap")); + } + + public void testConcurrentMapWithExplicitInterface() { + ConcurrentMap map = CollectionFactory.createConcurrentMap(16); + assertTrue(map.getClass().getSuperclass().getName().endsWith("ConcurrentHashMap")); + map.putIfAbsent("key", "value1"); + map.putIfAbsent("key", "value2"); + assertEquals("value1", map.get("key")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/ConstantsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/ConstantsTests.java new file mode 100644 index 00000000000..ee7b7187eb1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/ConstantsTests.java @@ -0,0 +1,253 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import java.util.Locale; +import java.util.Set; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + * @since 28.04.2003 + */ +public class ConstantsTests extends TestCase { + + public void testConstants() { + Constants c = new Constants(A.class); + assertEquals(A.class.getName(), c.getClassName()); + assertEquals(9, c.getSize()); + + assertEquals(c.asNumber("DOG").intValue(), A.DOG); + assertEquals(c.asNumber("dog").intValue(), A.DOG); + assertEquals(c.asNumber("cat").intValue(), A.CAT); + + try { + c.asNumber("bogus"); + fail("Can't get bogus field"); + } + catch (ConstantException expected) { + } + + assertTrue(c.asString("S1").equals(A.S1)); + try { + c.asNumber("S1"); + fail("Wrong type"); + } + catch (ConstantException expected) { + } + } + + public void testGetNames() { + Constants c = new Constants(A.class); + + Set names = c.getNames(""); + assertEquals(c.getSize(), names.size()); + assertTrue(names.contains("DOG")); + assertTrue(names.contains("CAT")); + assertTrue(names.contains("S1")); + + names = c.getNames("D"); + assertEquals(1, names.size()); + assertTrue(names.contains("DOG")); + + names = c.getNames("d"); + assertEquals(1, names.size()); + assertTrue(names.contains("DOG")); + } + + public void testGetValues() { + Constants c = new Constants(A.class); + + Set values = c.getValues(""); + assertEquals(7, values.size()); + assertTrue(values.contains(new Integer(0))); + assertTrue(values.contains(new Integer(66))); + assertTrue(values.contains("")); + + values = c.getValues("D"); + assertEquals(1, values.size()); + assertTrue(values.contains(new Integer(0))); + + values = c.getValues("prefix"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + + values = c.getValuesForProperty("myProperty"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + } + + public void testGetValuesInTurkey() { + Locale oldLocale = Locale.getDefault(); + Locale.setDefault(new Locale("tr", "")); + try { + Constants c = new Constants(A.class); + + Set values = c.getValues(""); + assertEquals(7, values.size()); + assertTrue(values.contains(new Integer(0))); + assertTrue(values.contains(new Integer(66))); + assertTrue(values.contains("")); + + values = c.getValues("D"); + assertEquals(1, values.size()); + assertTrue(values.contains(new Integer(0))); + + values = c.getValues("prefix"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + + values = c.getValuesForProperty("myProperty"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + } + finally { + Locale.setDefault(oldLocale); + } + } + + public void testSuffixAccess() { + Constants c = new Constants(A.class); + + Set names = c.getNamesForSuffix("_PROPERTY"); + assertEquals(2, names.size()); + assertTrue(names.contains("NO_PROPERTY")); + assertTrue(names.contains("YES_PROPERTY")); + + Set values = c.getValuesForSuffix("_PROPERTY"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(3))); + assertTrue(values.contains(new Integer(4))); + } + + public void testToCode() { + Constants c = new Constants(A.class); + + assertEquals(c.toCode(new Integer(0), ""), "DOG"); + assertEquals(c.toCode(new Integer(0), "D"), "DOG"); + assertEquals(c.toCode(new Integer(0), "DO"), "DOG"); + assertEquals(c.toCode(new Integer(0), "DoG"), "DOG"); + assertEquals(c.toCode(new Integer(66), ""), "CAT"); + assertEquals(c.toCode(new Integer(66), "C"), "CAT"); + assertEquals(c.toCode(new Integer(66), "ca"), "CAT"); + assertEquals(c.toCode(new Integer(66), "cAt"), "CAT"); + assertEquals(c.toCode("", ""), "S1"); + assertEquals(c.toCode("", "s"), "S1"); + assertEquals(c.toCode("", "s1"), "S1"); + try { + c.toCode("bogus", "bogus"); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + + assertEquals(c.toCodeForProperty(new Integer(1), "myProperty"), "MY_PROPERTY_NO"); + assertEquals(c.toCodeForProperty(new Integer(2), "myProperty"), "MY_PROPERTY_YES"); + try { + c.toCodeForProperty("bogus", "bogus"); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + + assertEquals(c.toCodeForSuffix(new Integer(0), ""), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(0), "G"), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(0), "OG"), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(0), "DoG"), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(66), ""), "CAT"); + assertEquals(c.toCodeForSuffix(new Integer(66), "T"), "CAT"); + assertEquals(c.toCodeForSuffix(new Integer(66), "at"), "CAT"); + assertEquals(c.toCodeForSuffix(new Integer(66), "cAt"), "CAT"); + assertEquals(c.toCodeForSuffix("", ""), "S1"); + assertEquals(c.toCodeForSuffix("", "1"), "S1"); + assertEquals(c.toCodeForSuffix("", "s1"), "S1"); + try { + c.toCodeForSuffix("bogus", "bogus"); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + } + + public void testGetValuesWithNullPrefix() throws Exception { + Constants c = new Constants(A.class); + Set values = c.getValues(null); + assertEquals("Must have returned *all* public static final values", 7, values.size()); + } + + public void testGetValuesWithEmptyStringPrefix() throws Exception { + Constants c = new Constants(A.class); + Set values = c.getValues(""); + assertEquals("Must have returned *all* public static final values", 7, values.size()); + } + + public void testGetValuesWithWhitespacedStringPrefix() throws Exception { + Constants c = new Constants(A.class); + Set values = c.getValues(" "); + assertEquals("Must have returned *all* public static final values", 7, values.size()); + } + + public void testWithClassThatExposesNoConstants() throws Exception { + Constants c = new Constants(NoConstants.class); + assertEquals(0, c.getSize()); + final Set values = c.getValues(""); + assertNotNull(values); + assertEquals(0, values.size()); + } + + public void testCtorWithNullClass() throws Exception { + try { + new Constants(null); + fail("Must have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) {} + } + + + private static final class NoConstants { + } + + + private static final class A { + + public static final int DOG = 0; + public static final int CAT = 66; + public static final String S1 = ""; + + public static final int PREFIX_NO = 1; + public static final int PREFIX_YES = 2; + + public static final int MY_PROPERTY_NO = 1; + public static final int MY_PROPERTY_YES = 2; + + public static final int NO_PROPERTY = 3; + public static final int YES_PROPERTY = 4; + + /** ignore these */ + protected static final int P = -1; + protected boolean f; + static final Object o = new Object(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/ConventionsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/ConventionsTests.java new file mode 100644 index 00000000000..ce42c75d7c2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/ConventionsTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; + +/** + * @author Rob Harrop + */ +public class ConventionsTests extends TestCase { + + public void testSimpleObject() { + TestBean testBean = new TestBean(); + assertEquals("Incorrect singular variable name", "testBean", Conventions.getVariableName(testBean)); + } + + public void testArray() { + TestBean[] testBeans = new TestBean[0]; + assertEquals("Incorrect plural array form", "testBeanList", Conventions.getVariableName(testBeans)); + } + + public void testCollections() { + List list = new ArrayList(); + list.add(new TestBean()); + assertEquals("Incorrect plural List form", "testBeanList", Conventions.getVariableName(list)); + + Set set = new HashSet(); + set.add(new TestBean()); + assertEquals("Incorrect plural Set form", "testBeanList", Conventions.getVariableName(set)); + + List emptyList = new ArrayList(); + try { + Conventions.getVariableName(emptyList); + fail("Should not be able to generate name for empty collection"); + } + catch(IllegalArgumentException ex) { + // success + } + } + + public void testAttributeNameToPropertyName() throws Exception { + assertEquals("transactionManager", Conventions.attributeNameToPropertyName("transaction-manager")); + assertEquals("pointcutRef", Conventions.attributeNameToPropertyName("pointcut-ref")); + assertEquals("lookupOnStartup", Conventions.attributeNameToPropertyName("lookup-on-startup")); + } + + public void testGetQualifiedAttributeName() throws Exception { + String baseName = "foo"; + Class cls = String.class; + String desiredResult = "java.lang.String.foo"; + assertEquals(desiredResult, Conventions.getQualifiedAttributeName(cls, baseName)); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/DefaultControlFlowTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/DefaultControlFlowTests.java new file mode 100644 index 00000000000..d527f769eac --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/DefaultControlFlowTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +/** + * Tests with ControlFlowFactory return. + * + * @author Rod Johnson + */ +public class DefaultControlFlowTests extends AbstractControlFlowTests { + + /** + * Necessary only because Eclipse won't run test suite unless + * it declares some methods as well as inherited methods. + */ + public void testThisClassPlease() { + } + + protected ControlFlow createControlFlow() { + return ControlFlowFactory.createControlFlow(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/Jdk14ControlFlowTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/Jdk14ControlFlowTests.java new file mode 100644 index 00000000000..040a6fcf20b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/Jdk14ControlFlowTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +/** + * Tests with ControlFlowFactory return. + * + * @author Rod Johnson + */ +public class Jdk14ControlFlowTests extends AbstractControlFlowTests { + + /** + * Necessary only because Eclipse won't run test suite unless it declares + * some methods as well as inherited methods + */ + public void testThisClassPlease() { + } + + protected ControlFlow createControlFlow() { + return ControlFlowFactory.createControlFlow(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java new file mode 100644 index 00000000000..f12d96f1303 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java @@ -0,0 +1,201 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; + +/** + * @author Adrian Colyer + */ +public class LocalVariableTableParameterNameDiscovererTests extends TestCase { + + private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); + + + public void testMethodParameterNameDiscoveryNoArgs() throws NoSuchMethodException { + Method getName = TestBean.class.getMethod("getName", new Class[0]); + String[] names = discoverer.getParameterNames(getName); + assertNotNull("should find method info", names); + assertEquals("no argument names", 0, names.length); + } + + public void testMethodParameterNameDiscoveryWithArgs() throws NoSuchMethodException { + Method setName = TestBean.class.getMethod("setName", new Class[]{String.class}); + String[] names = discoverer.getParameterNames(setName); + assertNotNull("should find method info", names); + assertEquals("one argument", 1, names.length); + assertEquals("name", names[0]); + } + + public void testConsParameterNameDiscoveryNoArgs() throws NoSuchMethodException { + Constructor noArgsCons = TestBean.class.getConstructor(new Class[0]); + String[] names = discoverer.getParameterNames(noArgsCons); + assertNotNull("should find cons info", names); + assertEquals("no argument names", 0, names.length); + } + + public void testConsParameterNameDiscoveryArgs() throws NoSuchMethodException { + Constructor twoArgCons = TestBean.class.getConstructor(new Class[]{String.class, int.class}); + String[] names = discoverer.getParameterNames(twoArgCons); + assertNotNull("should find cons info", names); + assertEquals("one argument", 2, names.length); + assertEquals("name", names[0]); + assertEquals("age", names[1]); + } + + public void testStaticMethodParameterNameDiscoveryNoArgs() throws NoSuchMethodException { + Method m = getClass().getMethod("staticMethodNoLocalVars", new Class[0]); + String[] names = discoverer.getParameterNames(m); + assertNotNull("should find method info", names); + assertEquals("no argument names", 0, names.length); + } + + public void testOverloadedStaticMethod() throws Exception { + Class clazz = this.getClass(); + + Method m1 = clazz.getMethod("staticMethod", new Class[]{Long.TYPE, Long.TYPE}); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + + Method m2 = clazz.getMethod("staticMethod", new Class[]{Long.TYPE, Long.TYPE, Long.TYPE}); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("three arguments", 3, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + assertEquals("z", names[2]); + } + + public void testOverloadedStaticMethodInInnerClass() throws Exception { + Class clazz = InnerClass.class; + + Method m1 = clazz.getMethod("staticMethod", new Class[]{Long.TYPE}); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("one argument", 1, names.length); + assertEquals("x", names[0]); + + Method m2 = clazz.getMethod("staticMethod", new Class[]{Long.TYPE, Long.TYPE}); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + } + + public void testOverloadedMethod() throws Exception { + Class clazz = this.getClass(); + + Method m1 = clazz.getMethod("instanceMethod", new Class[]{Double.TYPE, Double.TYPE}); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + + Method m2 = clazz.getMethod("instanceMethod", new Class[]{Double.TYPE, Double.TYPE, Double.TYPE}); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("three arguments", 3, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + assertEquals("z", names[2]); + } + + public void testOverloadedMethodInInnerClass() throws Exception { + Class clazz = InnerClass.class; + + Method m1 = clazz.getMethod("instanceMethod", new Class[]{String.class}); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("one argument", 1, names.length); + assertEquals("aa", names[0]); + + Method m2 = clazz.getMethod("instanceMethod", new Class[]{String.class, String.class}); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("aa", names[0]); + assertEquals("bb", names[1]); + } + + + public static void staticMethodNoLocalVars() { + } + + public static long staticMethod(long x, long y) { + long u = x * y; + return u; + } + + public static long staticMethod(long x, long y, long z) { + long u = x * y * z; + return u; + } + + public double instanceMethod(double x, double y) { + double u = x * y; + return u; + } + + public double instanceMethod(double x, double y, double z) { + double u = x * y * z; + return u; + } + + + public static class InnerClass { + + public int waz = 0; + + public InnerClass() { + } + + public InnerClass(String firstArg, long secondArg, Object thirdArg) { + long foo = 0; + short bar = 10; + this.waz = (int) (foo + bar); + } + + public String instanceMethod(String aa) { + return aa; + } + + public String instanceMethod(String aa, String bb) { + return aa + bb; + } + + public static long staticMethod(long x) { + long u = x; + return u; + } + + public static long staticMethod(long x, long y) { + long u = x * y; + return u; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/NestedExceptionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/NestedExceptionTests.java new file mode 100644 index 00000000000..ddc7056802b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/NestedExceptionTests.java @@ -0,0 +1,104 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class NestedExceptionTests extends TestCase { + + public void testNestedRuntimeExceptionWithNoRootCause() { + String mesg = "mesg of mine"; + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedRuntimeException nex = new NestedRuntimeException(mesg) {}; + assertNull(nex.getCause()); + assertEquals(nex.getMessage(), mesg); + + // Check printStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(mesg) == -1); + } + + public void testNestedRuntimeExceptionWithRootCause() { + String myMessage = "mesg for this exception"; + String rootCauseMesg = "this is the obscure message of the root cause"; + ServletException rootCause = new ServletException(rootCauseMesg); + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedRuntimeException nex = new NestedRuntimeException(myMessage, rootCause) {}; + assertEquals(nex.getCause(), rootCause); + assertTrue(nex.getMessage().indexOf(myMessage) != -1); + assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1); + + // check PrintStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1); + assertFalse(stackTrace.indexOf(rootCauseMesg) == -1); + } + + public void testNestedCheckedExceptionWithNoRootCause() { + String mesg = "mesg of mine"; + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedCheckedException nex = new NestedCheckedException(mesg) {}; + assertNull(nex.getCause()); + assertEquals(nex.getMessage(), mesg); + + // Check printStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(mesg) == -1); + } + + public void testNestedCheckedExceptionWithRootCause() { + String myMessage = "mesg for this exception"; + String rootCauseMesg = "this is the obscure message of the root cause"; + ServletException rootCause = new ServletException(rootCauseMesg); + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedCheckedException nex = new NestedCheckedException(myMessage, rootCause) {}; + assertEquals(nex.getCause(), rootCause); + assertTrue(nex.getMessage().indexOf(myMessage) != -1); + assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1); + + // check PrintStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1); + assertFalse(stackTrace.indexOf(rootCauseMesg) == -1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/OrderComparatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/OrderComparatorTests.java new file mode 100644 index 00000000000..9c9d515bab6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/OrderComparatorTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import junit.framework.TestCase; + +import java.util.Comparator; + +/** + * Unit tests for the {@link OrderComparator} class. + * + * @author Rick Evans + */ +public final class OrderComparatorTests extends TestCase { + + private Comparator comparator; + + + protected void setUp() throws Exception { + this.comparator = new OrderComparator(); + } + + + public void testCompareOrderedInstancesBefore() throws Exception { + assertEquals(-1, this.comparator.compare( + new StubOrdered(100), new StubOrdered(2000))); + } + + public void testCompareOrderedInstancesSame() throws Exception { + assertEquals(0, this.comparator.compare( + new StubOrdered(100), new StubOrdered(100))); + } + + public void testCompareOrderedInstancesAfter() throws Exception { + assertEquals(1, this.comparator.compare( + new StubOrdered(982300), new StubOrdered(100))); + } + + public void testCompareTwoNonOrderedInstancesEndsUpAsSame() throws Exception { + assertEquals(0, this.comparator.compare(new Object(), new Object())); + } + + + private static final class StubOrdered implements Ordered { + + private final int order; + + + public StubOrdered(int order) { + this.order = order; + } + + public int getOrder() { + return this.order; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java new file mode 100644 index 00000000000..c51d8c1dbfa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; + +public class PrioritizedParameterNameDiscovererTests extends TestCase { + + private static final String[] FOO_BAR = new String[] { "foo", "bar" }; + + private static final String[] SOMETHING_ELSE = new String[] { "something", "else" }; + + ParameterNameDiscoverer returnsFooBar = new ParameterNameDiscoverer() { + public String[] getParameterNames(Method m) { + return FOO_BAR; + } + public String[] getParameterNames(Constructor ctor) { + return FOO_BAR; + } + }; + + ParameterNameDiscoverer returnsSomethingElse = new ParameterNameDiscoverer() { + public String[] getParameterNames(Method m) { + return SOMETHING_ELSE; + } + public String[] getParameterNames(Constructor ctor) { + return SOMETHING_ELSE; + } + }; + + private final Method anyMethod; + private final Class anyClass = Object.class; + + public PrioritizedParameterNameDiscovererTests() throws SecurityException, NoSuchMethodException { + anyMethod = TestBean.class.getMethod("getAge", (Class[]) null); + } + + public void testNoParametersDiscoverers() { + ParameterNameDiscoverer pnd = new PrioritizedParameterNameDiscoverer(); + assertNull(pnd.getParameterNames(anyMethod)); + assertNull(pnd.getParameterNames((Constructor) null)); + } + + public void testOrderedParameterDiscoverers1() { + PrioritizedParameterNameDiscoverer pnd = new PrioritizedParameterNameDiscoverer(); + pnd.addDiscoverer(returnsFooBar); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames((Constructor) null))); + pnd.addDiscoverer(returnsSomethingElse); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames((Constructor) null))); + } + + public void testOrderedParameterDiscoverers2() { + PrioritizedParameterNameDiscoverer pnd = new PrioritizedParameterNameDiscoverer(); + pnd.addDiscoverer(returnsSomethingElse); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames((Constructor) null))); + pnd.addDiscoverer(returnsFooBar); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames((Constructor) null))); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/enums/LabeledEnumTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/enums/LabeledEnumTests.java new file mode 100644 index 00000000000..0e57814ac56 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/enums/LabeledEnumTests.java @@ -0,0 +1,183 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.enums; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import junit.framework.TestCase; + +/** + * @author Keith Donald + * @author Juergen Hoeller + * @author Sam Brannen + */ +public class LabeledEnumTests extends TestCase { + + private byte[] serializeObject(final Object obj) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.close(); + return baos.toByteArray(); + } + + private Object deserializeObject(final byte[] serializedBytes) throws IOException, ClassNotFoundException { + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serializedBytes)); + Object obj = ois.readObject(); + ois.close(); + return obj; + } + + private Object serializeAndDeserializeObject(Object obj) throws IOException, ClassNotFoundException { + return deserializeObject(serializeObject(obj)); + } + + public void testCodeFound() { + Dog golden = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(Dog.class, new Short((short) 11)); + Dog borderCollie = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(Dog.class, + new Short((short) 13)); + assertSame(golden, Dog.GOLDEN_RETRIEVER); + assertSame(borderCollie, Dog.BORDER_COLLIE); + } + + public void testCodeFoundForAbstractEnums() { + ValuedEnum one = (ValuedEnum) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(ValuedEnum.class, + new Short((short) 1)); + ValuedEnum two = (ValuedEnum) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(ValuedEnum.class, + new Short((short) 2)); + assertSame(one, ValuedEnum.ONE); + assertSame(two, ValuedEnum.TWO); + } + + public void testDeserializationOfInnerClassEnums() throws Exception { + assertSame(serializeAndDeserializeObject(Other.THING1), Other.THING1); + } + + public void testDeserializationOfStandAloneEnums() throws Exception { + assertSame(serializeAndDeserializeObject(StandAloneStaticLabeledEnum.ENUM1), + StandAloneStaticLabeledEnum.ENUM1); + } + + public void testLabelFound() { + Dog golden = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(Dog.class, "Golden Retriever"); + Dog borderCollie = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(Dog.class, "Border Collie"); + assertSame(golden, Dog.GOLDEN_RETRIEVER); + assertSame(borderCollie, Dog.BORDER_COLLIE); + } + + public void testLabelFoundForStandAloneEnum() { + StandAloneStaticLabeledEnum enum1 = (StandAloneStaticLabeledEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(StandAloneStaticLabeledEnum.class, "Enum1"); + StandAloneStaticLabeledEnum enum2 = (StandAloneStaticLabeledEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(StandAloneStaticLabeledEnum.class, "Enum2"); + assertSame(enum1, StandAloneStaticLabeledEnum.ENUM1); + assertSame(enum2, StandAloneStaticLabeledEnum.ENUM2); + } + + public void testLabelFoundForAbstractEnums() { + ValuedEnum one = (ValuedEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(ValuedEnum.class, "one"); + ValuedEnum two = (ValuedEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(ValuedEnum.class, "two"); + assertSame(one, ValuedEnum.ONE); + assertSame(two, ValuedEnum.TWO); + } + + public void testDoesNotMatchWrongClass() { + try { + LabeledEnum none = StaticLabeledEnumResolver.instance().getLabeledEnumByCode(Dog.class, + new Short((short) 1)); + fail("Should have failed"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testEquals() { + assertEquals("Code equality means equals", Dog.GOLDEN_RETRIEVER, new Dog(11, "Golden Retriever")); + assertFalse("Code inequality means notEquals", Dog.GOLDEN_RETRIEVER.equals(new Dog(12, "Golden Retriever"))); + } + + + private static class Other extends StaticLabeledEnum { + + public static final Other THING1 = new Other(1, "Thing1"); + public static final Other THING2 = new Other(2, "Thing2"); + + + private Other(int code, String name) { + super(code, name); + } + } + + + private static class Dog extends StaticLabeledEnum { + + public static final Dog GOLDEN_RETRIEVER = new Dog(11, null) { + + public String getLabel() { + return "Golden Retriever"; + } + + // Overriding getType() is no longer necessary as of Spring 2.5; + // however, this is left here to provide valid testing for + // backwards compatibility. + public Class getType() { + return Dog.class; + } + }; + + public static final Dog BORDER_COLLIE = new Dog(13, "Border Collie"); + public static final Dog WHIPPET = new Dog(14, "Whippet"); + + // Ignore this + public static final Other THING1 = Other.THING1; + + + private Dog(int code, String name) { + super(code, name); + } + } + + + private static abstract class ValuedEnum extends StaticLabeledEnum { + + public static final ValuedEnum ONE = new ValuedEnum(1, "one") { + public int getValue() { + return 1; + } + }; + + public static final ValuedEnum TWO = new ValuedEnum(2, "two") { + public int getValue() { + return 2; + } + }; + + private ValuedEnum(int code, String name) { + super(code, name); + } + + public abstract int getValue(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/enums/StandAloneStaticLabeledEnum.java b/org.springframework.testsuite/src/test/java/org/springframework/core/enums/StandAloneStaticLabeledEnum.java new file mode 100644 index 00000000000..078f39864c5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/enums/StandAloneStaticLabeledEnum.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.enums; + +/** + * Stand-alone static enum for use in {@link LabeledEnumTests}. + * + * @author Sam Brannen + * @since 2.5 + */ +public class StandAloneStaticLabeledEnum extends StaticLabeledEnum { + + private static final long serialVersionUID = 1L; + + public static final StandAloneStaticLabeledEnum ENUM1 = new StandAloneStaticLabeledEnum(1, "Enum1"); + public static final StandAloneStaticLabeledEnum ENUM2 = new StandAloneStaticLabeledEnum(2, "Enum2"); + + + private StandAloneStaticLabeledEnum(int code, String name) { + super(code, name); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceEditorTests.java new file mode 100644 index 00000000000..c9a4797c3a9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceEditorTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +import java.beans.PropertyEditor; + +/** + * Unit tests for the {@link ResourceEditor} class. + * + * @author Rick Evans + */ +public final class ResourceEditorTests extends TestCase { + + public void testSunnyDay() throws Exception { + PropertyEditor editor = new ResourceEditor(); + editor.setAsText("classpath:org/springframework/core/io/ResourceEditorTests.class"); + Resource resource = (Resource) editor.getValue(); + assertNotNull(resource); + assertTrue(resource.exists()); + } + + public void testCtorWithNullResourceLoader() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ResourceEditor(null); + } + }.runTest(); + } + + public void testSetAndGetAsTextWithNull() throws Exception { + PropertyEditor editor = new ResourceEditor(); + editor.setAsText(null); + assertEquals("", editor.getAsText()); + } + + public void testSetAndGetAsTextWithWhitespaceResource() throws Exception { + PropertyEditor editor = new ResourceEditor(); + editor.setAsText(" "); + assertEquals("", editor.getAsText()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceTests.java new file mode 100644 index 00000000000..8b01a3be688 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/io/ResourceTests.java @@ -0,0 +1,224 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashSet; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockServletContext; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.context.support.ServletContextResource; + +/** + * @author Juergen Hoeller + * @since 09.09.2004 + */ +public class ResourceTests extends TestCase { + + public void testByteArrayResource() throws IOException { + Resource resource = new ByteArrayResource("testString".getBytes()); + assertTrue(resource.exists()); + assertFalse(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals(resource, new ByteArrayResource("testString".getBytes())); + } + + public void testByteArrayResourceWithDescription() throws IOException { + Resource resource = new ByteArrayResource("testString".getBytes(), "my description"); + assertTrue(resource.exists()); + assertFalse(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals("my description", resource.getDescription()); + assertEquals(resource, new ByteArrayResource("testString".getBytes())); + } + + public void testInputStreamResource() throws IOException { + InputStream is = new ByteArrayInputStream("testString".getBytes()); + Resource resource = new InputStreamResource(is); + assertTrue(resource.exists()); + assertTrue(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals(resource, new InputStreamResource(is)); + } + + public void testInputStreamResourceWithDescription() throws IOException { + InputStream is = new ByteArrayInputStream("testString".getBytes()); + Resource resource = new InputStreamResource(is, "my description"); + assertTrue(resource.exists()); + assertTrue(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals("my description", resource.getDescription()); + assertEquals(resource, new InputStreamResource(is)); + } + + public void testClassPathResource() throws IOException { + Resource resource = new ClassPathResource("org/springframework/core/io/Resource.class"); + doTestResource(resource); + Resource resource2 = new ClassPathResource("org/springframework/core/../core/io/./Resource.class"); + assertEquals(resource, resource2); + Resource resource3 = new ClassPathResource("org/springframework/core/").createRelative("../core/io/./Resource.class"); + assertEquals(resource, resource3); + + // Check whether equal/hashCode works in a HashSet. + HashSet resources = new HashSet(); + resources.add(resource); + resources.add(resource2); + assertEquals(1, resources.size()); + } + + public void testClassPathResourceWithClassLoader() throws IOException { + Resource resource = + new ClassPathResource("org/springframework/core/io/Resource.class", getClass().getClassLoader()); + doTestResource(resource); + assertEquals(resource, + new ClassPathResource("org/springframework/core/../core/io/./Resource.class", getClass().getClassLoader())); + } + + public void testClassPathResourceWithClass() throws IOException { + Resource resource = new ClassPathResource("Resource.class", getClass()); + doTestResource(resource); + assertEquals(resource, new ClassPathResource("Resource.class", getClass())); + } + + public void testFileSystemResource() throws IOException { + Resource resource = new FileSystemResource(getClass().getResource("Resource.class").getFile()); + doTestResource(resource); + assertEquals(new FileSystemResource(getClass().getResource("Resource.class").getFile()), resource); + Resource resource2 = new FileSystemResource("core/io/Resource.class"); + assertEquals(resource2, new FileSystemResource("core/../core/io/./Resource.class")); + } + + public void testUrlResource() throws IOException { + Resource resource = new UrlResource(getClass().getResource("Resource.class")); + doTestResource(resource); + assertEquals(new UrlResource(getClass().getResource("Resource.class")), resource); + Resource resource2 = new UrlResource("file:core/io/Resource.class"); + assertEquals(resource2, new UrlResource("file:core/../core/io/./Resource.class")); + } + + public void testServletContextResource() throws IOException { + MockServletContext sc = new MockServletContext(); + Resource resource = new ServletContextResource(sc, "org/springframework/core/io/Resource.class"); + doTestResource(resource); + assertEquals(resource, new ServletContextResource(sc, "org/springframework/core/../core/io/./Resource.class")); + } + + private void doTestResource(Resource resource) throws IOException { + assertEquals("Resource.class", resource.getFilename()); + assertTrue(resource.getURL().getFile().endsWith("Resource.class")); + + Resource relative1 = resource.createRelative("ClassPathResource.class"); + assertEquals("ClassPathResource.class", relative1.getFilename()); + assertTrue(relative1.getURL().getFile().endsWith("ClassPathResource.class")); + assertTrue(relative1.exists()); + + Resource relative2 = resource.createRelative("support/ResourcePatternResolver.class"); + assertEquals("ResourcePatternResolver.class", relative2.getFilename()); + assertTrue(relative2.getURL().getFile().endsWith("ResourcePatternResolver.class")); + assertTrue(relative2.exists()); + + Resource relative3 = resource.createRelative("../SpringVersion.class"); + assertEquals("SpringVersion.class", relative3.getFilename()); + assertTrue(relative3.getURL().getFile().endsWith("SpringVersion.class")); + assertTrue(relative3.exists()); + } + + public void testClassPathResourceWithRelativePath() throws IOException { + Resource resource = new ClassPathResource("dir/"); + Resource relative = resource.createRelative("subdir"); + assertEquals(new ClassPathResource("dir/subdir"), relative); + } + + public void testFileSystemResourceWithRelativePath() throws IOException { + Resource resource = new FileSystemResource("dir/"); + Resource relative = resource.createRelative("subdir"); + assertEquals(new FileSystemResource("dir/subdir"), relative); + } + + public void testUrlResourceWithRelativePath() throws IOException { + Resource resource = new UrlResource("file:dir/"); + Resource relative = resource.createRelative("subdir"); + assertEquals(new UrlResource("file:dir/subdir"), relative); + } + + public void testServletContextResourceWithRelativePath() throws IOException { + MockServletContext sc = new MockServletContext(); + Resource resource = new ServletContextResource(sc, "dir/"); + Resource relative = resource.createRelative("subdir"); + assertEquals(new ServletContextResource(sc, "dir/subdir"), relative); + } + + /* + public void testNonFileResourceExists() throws Exception { + Resource resource = new UrlResource("http://www.springframework.org"); + assertTrue(resource.exists()); + } + */ + + public void testAbstractResourceExceptions() throws Exception { + final String name = "test-resource"; + + Resource resource = new AbstractResource() { + public String getDescription() { + return name; + } + public InputStream getInputStream() { + return null; + } + }; + + try { + resource.getURL(); + fail("FileNotFoundException should have been thrown"); + } + catch (FileNotFoundException ex) { + assertTrue(ex.getMessage().indexOf(name) != -1); + } + try { + resource.getFile(); + fail("FileNotFoundException should have been thrown"); + } + catch (FileNotFoundException ex) { + assertTrue(ex.getMessage().indexOf(name) != -1); + } + try { + resource.createRelative("/testing"); + fail("FileNotFoundException should have been thrown"); + } + catch (FileNotFoundException ex) { + assertTrue(ex.getMessage().indexOf(name) != -1); + } + try { + resource.getFilename(); + fail("IllegalStateException should have been thrown"); + } + catch (IllegalStateException ex) { + assertTrue(ex.getMessage().indexOf(name) != -1); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java new file mode 100644 index 00000000000..52253d8e8e0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io.support; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.core.io.Resource; + +/** + * If this test case fails, uncomment diagnostics in + * assertProtocolAndFilenames method. + * + * @author Oliver Hutchison + * @author Juergen Hoeller + * @since 17.11.2004 + */ +public class PathMatchingResourcePatternResolverTests extends TestCase { + + private static final String[] CLASSES_IN_CORE_IO_SUPPORT = + new String[] {"EncodedResource.class", "LocalizedResourceHelper.class", + "PathMatchingResourcePatternResolver.class", + "PropertiesLoaderSupport.class", "PropertiesLoaderUtils.class", + "ResourceArrayPropertyEditor.class", + "ResourcePatternResolver.class", "ResourcePatternUtils.class"}; + + private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT = + new String[] {"PathMatchingResourcePatternResolverTests.class"}; + + private static final String[] CLASSES_IN_AOPALLIANCE = + new String[] {"Advice.class", "AspectException.class", "ConstructorInterceptor.class", + "ConstructorInvocation.class", "Interceptor.class", "Invocation.class", + "Joinpoint.class", "MethodInterceptor.class", "MethodInvocation.class"}; + + private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + + + public void testInvalidPrefixWithPatternElementInIt() throws IOException { + try { + resolver.getResources("xx**:**/*.xy"); + fail("Should have thrown FileNotFoundException"); + } + catch (FileNotFoundException ex) { + // expected + } + } + + public void testSingleResourceOnFileSystem() throws IOException { + Resource[] resources = + resolver.getResources("org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.class"); + assertEquals(1, resources.length); + assertProtocolAndFilename(resources[0], "file", "PathMatchingResourcePatternResolverTests.class"); + } + + public void testSingleResourceInJar() throws IOException { + Resource[] resources = resolver.getResources("java/net/URL.class"); + assertEquals(1, resources.length); + assertProtocolAndFilename(resources[0], "jar", "URL.class"); + } + + public void testClasspathStarWithPatternOnFileSystem() throws IOException { + Resource[] resources = resolver.getResources("classpath*:org/springframework/core/io/sup*/*.class"); + // Have to exclude Clover-generated class files here, + // as we might be running as part of a Clover test run. + List noCloverResources = new ArrayList(); + for (int i = 0; i < resources.length; i++) { + if (resources[i].getFilename().indexOf("$__CLOVER_") == -1) { + noCloverResources.add(resources[i]); + } + } + resources = (Resource[]) noCloverResources.toArray(new Resource[noCloverResources.size()]); + assertProtocolAndFilenames(resources, "file", CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT); + } + + public void testClasspathWithPatternInJar() throws IOException { + Resource[] resources = resolver.getResources("classpath:org/aopalliance/**/*.class"); + assertProtocolAndFilenames(resources, "jar", CLASSES_IN_AOPALLIANCE); + } + + public void testClasspathStartWithPatternInJar() throws IOException { + Resource[] resources = resolver.getResources("classpath*:org/aopalliance/**/*.class"); + assertProtocolAndFilenames(resources, "jar", CLASSES_IN_AOPALLIANCE); + } + + private void assertProtocolAndFilename(Resource resource, String urlProtocol, String fileName) throws IOException { + assertProtocolAndFilenames(new Resource[] {resource}, urlProtocol, new String[] {fileName}); + } + + private void assertProtocolAndFilenames( + Resource[] resources, String urlProtocol, String[] fileNames1, String[] fileNames2) throws IOException { + List fileNames = new ArrayList(Arrays.asList(fileNames1)); + fileNames.addAll(Arrays.asList(fileNames2)); + assertProtocolAndFilenames(resources, urlProtocol, (String[]) fileNames.toArray(new String[fileNames.size()])); + } + + private void assertProtocolAndFilenames(Resource[] resources, String urlProtocol, String[] fileNames) + throws IOException { + + // Uncomment the following if you encounter problems with matching against the file system + // It shows file locations. +// String[] actualNames = new String[resources.length]; +// for (int i = 0; i < resources.length; i++) { +// actualNames[i] = resources[i].getFilename(); +// } +// List sortedActualNames = new LinkedList(Arrays.asList(actualNames)); +// List expectedNames = new LinkedList(Arrays.asList(fileNames)); +// Collections.sort(sortedActualNames); +// Collections.sort(expectedNames); +// +// System.out.println("-----------"); +// System.out.println("Expected: " + StringUtils.collectionToCommaDelimitedString(expectedNames)); +// System.out.println("Actual: " + StringUtils.collectionToCommaDelimitedString(sortedActualNames)); +// for (int i = 0; i < resources.length; i++) { +// System.out.println(resources[i]); +// } + + assertEquals("Correct number of files found", fileNames.length, resources.length); + for (int i = 0; i < resources.length; i++) { + Resource resource = resources[i]; + assertEquals(urlProtocol, resource.getURL().getProtocol()); + assertFilenameIn(resource, fileNames); + } + } + + private void assertFilenameIn(Resource resource, String[] fileNames) { + for (int i = 0; i < fileNames.length; i++) { + if (resource.getFilename().endsWith(fileNames[i])) { + return; + } + } + fail("resource [" + resource + "] does not have a filename that matches and of the names in 'fileNames'"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/style/ToStringCreatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/style/ToStringCreatorTests.java new file mode 100644 index 00000000000..928486b3962 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/style/ToStringCreatorTests.java @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.style; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.core.CollectionFactory; +import org.springframework.util.ObjectUtils; + +/** + * @author Keith Donald + */ +public class ToStringCreatorTests extends TestCase { + + private SomeObject s1, s2, s3; + + protected void setUp() throws Exception { + s1 = new SomeObject() { + public String toString() { + return "A"; + } + }; + s2 = new SomeObject() { + public String toString() { + return "B"; + } + }; + s3 = new SomeObject() { + public String toString() { + return "C"; + } + }; + } + + public void testDefaultStyleMap() { + final Map map = getMap(); + Object stringy = new Object() { + public String toString() { + return new ToStringCreator(this).append("familyFavoriteSport", map).toString(); + } + }; + assertEquals("[ToStringCreatorTests.4@" + ObjectUtils.getIdentityHexString(stringy) + + " familyFavoriteSport = map['Keri' -> 'Softball', 'Scot' -> 'Fishing', 'Keith' -> 'Flag Football']]", + stringy.toString()); + } + + private Map getMap() { + Map map = CollectionFactory.createLinkedMapIfPossible(3); + map.put("Keri", "Softball"); + map.put("Scot", "Fishing"); + map.put("Keith", "Flag Football"); + return map; + } + + public void testDefaultStyleArray() { + SomeObject[] array = new SomeObject[] { s1, s2, s3 }; + String str = new ToStringCreator(array).toString(); + assertEquals("[@" + ObjectUtils.getIdentityHexString(array) + + " array[A, B, C]]", str); + } + + public void testPrimitiveArrays() { + int[] integers = new int[] { 0, 1, 2, 3, 4 }; + String str = new ToStringCreator(integers).toString(); + assertEquals("[@" + ObjectUtils.getIdentityHexString(integers) + " array[0, 1, 2, 3, 4]]", str); + } + + public void testList() { + List list = new ArrayList(); + list.add(s1); + list.add(s2); + list.add(s3); + String str = new ToStringCreator(this).append("myLetters", list).toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + " myLetters = list[A, B, C]]", + str); + } + + public void testSet() { + Set set = CollectionFactory.createLinkedSetIfPossible(3); + set.add(s1); + set.add(s2); + set.add(s3); + String str = new ToStringCreator(this).append("myLetters", set).toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + " myLetters = set[A, B, C]]", + str); + } + + public void testClass() { + String str = new ToStringCreator(this).append("myClass", this.getClass()).toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + + " myClass = ToStringCreatorTests]", str); + } + + public void testMethod() throws Exception { + String str = new ToStringCreator(this).append("myMethod", this.getClass().getMethod("testMethod", null)) + .toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + + " myMethod = testMethod@ToStringCreatorTests]", str); + } + + + public static class SomeObject { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/task/MockRunnable.java b/org.springframework.testsuite/src/test/java/org/springframework/core/task/MockRunnable.java new file mode 100644 index 00000000000..8aa2d639546 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/task/MockRunnable.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.task; + +/** + * @author Juergen Hoeller + */ +public class MockRunnable implements Runnable { + + private boolean executed = false; + + public void run() { + this.executed = true; + } + + public boolean wasExecuted() { + return this.executed; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/task/NoOpRunnable.java b/org.springframework.testsuite/src/test/java/org/springframework/core/task/NoOpRunnable.java new file mode 100644 index 00000000000..88ce25e7450 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/task/NoOpRunnable.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.task; + +/** + * A no-op Runnable implementation. + * + * @author Rick Evans + */ +public class NoOpRunnable implements Runnable { + + public void run() { + // explicit no-op + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java new file mode 100644 index 00000000000..6dc78ff80df --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java @@ -0,0 +1,132 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.task; + +import junit.framework.TestCase; + +import org.springframework.util.ClassUtils; +import org.springframework.util.ConcurrencyThrottleSupport; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public final class SimpleAsyncTaskExecutorTests extends TestCase { + + public void testCannotExecuteWhenConcurrencyIsSwitchedOff() throws Exception { + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); + executor.setConcurrencyLimit(ConcurrencyThrottleSupport.NO_CONCURRENCY); + assertFalse(executor.isThrottleActive()); + try { + executor.execute(new NoOpRunnable()); + } + catch (IllegalStateException expected) { + } + } + + public void testThrottleIsNotActiveByDefault() throws Exception { + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); + assertFalse("Concurrency throttle must not default to being active (on)", executor.isThrottleActive()); + } + + public void testThreadNameGetsSetCorrectly() throws Exception { + final String customPrefix = "chankPop#"; + final Object monitor = new Object(); + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(customPrefix); + ThreadNameHarvester task = new ThreadNameHarvester(monitor); + executeAndWait(executor, task, monitor); + assertTrue(task.getThreadName().startsWith(customPrefix)); + } + + public void testThreadNameRevertsToDefaultIfSetToNull() throws Exception { + final Object monitor = new Object(); + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(null); + ThreadNameHarvester task = new ThreadNameHarvester(monitor); + executeAndWait(executor, task, monitor); + assertTrue(task.getThreadName().startsWith(ClassUtils.getShortName(SimpleAsyncTaskExecutor.class) + "-")); + } + + public void testThrowsExceptionWhenSuppliedWithNullRunnable() throws Exception { + try { + new SimpleAsyncTaskExecutor().execute(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + } + + private void executeAndWait(SimpleAsyncTaskExecutor executor, Runnable task, Object monitor) { + synchronized (monitor) { + executor.execute(task); + try { + monitor.wait(); + } + catch (InterruptedException ignored) { + } + } + } + + + private static final class NoOpRunnable implements Runnable { + + public void run() { + // no-op + } + } + + + private static abstract class AbstractNotifyingRunnable implements Runnable { + + private final Object monitor; + + protected AbstractNotifyingRunnable(Object monitor) { + this.monitor = monitor; + } + + public final void run() { + synchronized (this.monitor) { + try { + doRun(); + } + finally { + this.monitor.notifyAll(); + } + } + } + + protected abstract void doRun(); + } + + + private static final class ThreadNameHarvester extends AbstractNotifyingRunnable { + + private String threadName; + + protected ThreadNameHarvester(Object monitor) { + super(monitor); + } + + public String getThreadName() { + return this.threadName; + } + + protected void doRun() { + this.threadName = Thread.currentThread().getName(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/core/task/StubTaskExecutor.java b/org.springframework.testsuite/src/test/java/org/springframework/core/task/StubTaskExecutor.java new file mode 100644 index 00000000000..5270aff4d36 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/core/task/StubTaskExecutor.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.task; + +/** + * @author Juergen Hoeller + */ +public class StubTaskExecutor implements TaskExecutor { + + public void execute(Runnable task) { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/dao/support/ChainedPersistenceExceptionTranslatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/dao/support/ChainedPersistenceExceptionTranslatorTests.java new file mode 100644 index 00000000000..010da75e8f5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/dao/support/ChainedPersistenceExceptionTranslatorTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.dao.support; + +import junit.framework.TestCase; + +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.dao.support.DataAccessUtilsTests.MapPersistenceExceptionTranslator; + +/** + * @author Rod Johnson + * @since 2.0 + */ +public class ChainedPersistenceExceptionTranslatorTests extends TestCase { + + public void testEmpty() { + ChainedPersistenceExceptionTranslator pet = new ChainedPersistenceExceptionTranslator(); + //MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator(); + RuntimeException in = new RuntimeException("in"); + assertSame(in, DataAccessUtils.translateIfNecessary(in, pet)); + } + + public void testExceptionTranslationWithTranslation() { + MapPersistenceExceptionTranslator mpet1 = new MapPersistenceExceptionTranslator(); + RuntimeException in1 = new RuntimeException("in"); + InvalidDataAccessApiUsageException out1 = new InvalidDataAccessApiUsageException("out"); + InvalidDataAccessApiUsageException out2 = new InvalidDataAccessApiUsageException("out"); + mpet1.addTranslation(in1, out1); + + ChainedPersistenceExceptionTranslator chainedPet1 = new ChainedPersistenceExceptionTranslator(); + assertSame("Should not translate yet", in1, DataAccessUtils.translateIfNecessary(in1, chainedPet1)); + chainedPet1.addDelegate(mpet1); + assertSame("Should now translate", out1, DataAccessUtils.translateIfNecessary(in1, chainedPet1)); + + // Now add a new translator and verify it wins + MapPersistenceExceptionTranslator mpet2 = new MapPersistenceExceptionTranslator(); + mpet2.addTranslation(in1, out2); + chainedPet1.addDelegate(mpet2); + assertSame("Should still translate the same due to ordering", + out1, DataAccessUtils.translateIfNecessary(in1, chainedPet1)); + + ChainedPersistenceExceptionTranslator chainedPet2 = new ChainedPersistenceExceptionTranslator(); + chainedPet2.addDelegate(mpet2); + chainedPet2.addDelegate(mpet1); + assertSame("Should translate differently due to ordering", + out2, DataAccessUtils.translateIfNecessary(in1, chainedPet2)); + + RuntimeException in2 = new RuntimeException("in2"); + OptimisticLockingFailureException out3 = new OptimisticLockingFailureException("out2"); + assertNull(chainedPet2.translateExceptionIfPossible(in2)); + MapPersistenceExceptionTranslator mpet3 = new MapPersistenceExceptionTranslator(); + mpet3.addTranslation(in2, out3); + chainedPet2.addDelegate(mpet3); + assertSame(out3, chainedPet2.translateExceptionIfPossible(in2)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java new file mode 100644 index 00000000000..e0a4523bfb2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/dao/support/DataAccessUtilsTests.java @@ -0,0 +1,278 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.dao.support; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.TypeMismatchDataAccessException; + +/** + * @author Juergen Hoeller + * @since 20.10.2004 + */ +public class DataAccessUtilsTests extends TestCase { + + public void testWithEmptyCollection() { + Collection col = new HashSet(); + + assertNull(DataAccessUtils.uniqueResult(col)); + + try { + DataAccessUtils.requiredUniqueResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(0, ex.getActualSize()); + } + + try { + DataAccessUtils.objectResult(col, String.class); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(0, ex.getActualSize()); + } + + try { + DataAccessUtils.intResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(0, ex.getActualSize()); + } + + try { + DataAccessUtils.longResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(0, ex.getActualSize()); + } + } + + public void testWithTooLargeCollection() { + Collection col = new HashSet(); + col.add("test1"); + col.add("test2"); + + try { + DataAccessUtils.uniqueResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(2, ex.getActualSize()); + } + + try { + DataAccessUtils.requiredUniqueResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(2, ex.getActualSize()); + } + + try { + DataAccessUtils.objectResult(col, String.class); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(2, ex.getActualSize()); + } + + try { + DataAccessUtils.intResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(2, ex.getActualSize()); + } + + try { + DataAccessUtils.longResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(2, ex.getActualSize()); + } + } + + public void testWithInteger() { + Collection col = new HashSet(); + col.add(new Integer(5)); + + assertEquals(new Integer(5), DataAccessUtils.uniqueResult(col)); + assertEquals(new Integer(5), DataAccessUtils.requiredUniqueResult(col)); + assertEquals(new Integer(5), DataAccessUtils.objectResult(col, Integer.class)); + assertEquals("5", DataAccessUtils.objectResult(col, String.class)); + assertEquals(5, DataAccessUtils.intResult(col)); + assertEquals(5, DataAccessUtils.longResult(col)); + } + + public void testWithSameIntegerInstanceTwice() { + Integer i = new Integer(5); + Collection col = new ArrayList(); + col.add(i); + col.add(i); + + assertEquals(new Integer(5), DataAccessUtils.uniqueResult(col)); + assertEquals(new Integer(5), DataAccessUtils.requiredUniqueResult(col)); + assertEquals(new Integer(5), DataAccessUtils.objectResult(col, Integer.class)); + assertEquals("5", DataAccessUtils.objectResult(col, String.class)); + assertEquals(5, DataAccessUtils.intResult(col)); + assertEquals(5, DataAccessUtils.longResult(col)); + } + + public void testWithEquivalentIntegerInstanceTwice() { + Collection col = new ArrayList(); + col.add(new Integer(5)); + col.add(new Integer(5)); + + try { + DataAccessUtils.uniqueResult(col); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(2, ex.getActualSize()); + } + } + + public void testWithLong() { + Collection col = new HashSet(); + col.add(new Long(5)); + + assertEquals(new Long(5), DataAccessUtils.uniqueResult(col)); + assertEquals(new Long(5), DataAccessUtils.requiredUniqueResult(col)); + assertEquals(new Long(5), DataAccessUtils.objectResult(col, Long.class)); + assertEquals("5", DataAccessUtils.objectResult(col, String.class)); + assertEquals(5, DataAccessUtils.intResult(col)); + assertEquals(5, DataAccessUtils.longResult(col)); + } + + public void testWithString() { + Collection col = new HashSet(); + col.add("test1"); + + assertEquals("test1", DataAccessUtils.uniqueResult(col)); + assertEquals("test1", DataAccessUtils.requiredUniqueResult(col)); + assertEquals("test1", DataAccessUtils.objectResult(col, String.class)); + + try { + DataAccessUtils.intResult(col); + fail("Should have thrown TypeMismatchDataAccessException"); + } + catch (TypeMismatchDataAccessException ex) { + // expected + } + + try { + DataAccessUtils.longResult(col); + fail("Should have thrown TypeMismatchDataAccessException"); + } + catch (TypeMismatchDataAccessException ex) { + // expected + } + } + + public void testWithDate() { + Date date = new Date(); + Collection col = new HashSet(); + col.add(date); + + assertEquals(date, DataAccessUtils.uniqueResult(col)); + assertEquals(date, DataAccessUtils.requiredUniqueResult(col)); + assertEquals(date, DataAccessUtils.objectResult(col, Date.class)); + assertEquals(date.toString(), DataAccessUtils.objectResult(col, String.class)); + + try { + DataAccessUtils.intResult(col); + fail("Should have thrown TypeMismatchDataAccessException"); + } + catch (TypeMismatchDataAccessException ex) { + // expected + } + + try { + DataAccessUtils.longResult(col); + fail("Should have thrown TypeMismatchDataAccessException"); + } + catch (TypeMismatchDataAccessException ex) { + // expected + } + } + + public void testExceptionTranslationWithNoTranslation() { + MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator(); + RuntimeException in = new RuntimeException(); + assertSame(in, DataAccessUtils.translateIfNecessary(in, mpet)); + } + + public void testExceptionTranslationWithTranslation() { + MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator(); + RuntimeException in = new RuntimeException("in"); + InvalidDataAccessApiUsageException out = new InvalidDataAccessApiUsageException("out"); + mpet.addTranslation(in, out); + assertSame(out, DataAccessUtils.translateIfNecessary(in, mpet)); + } + + + public static class MapPersistenceExceptionTranslator implements PersistenceExceptionTranslator { + + /** + * Map: in to out + */ + private Map translations = new HashMap(); + + public void addTranslation(RuntimeException in, RuntimeException out) { + this.translations.put(in, out); + } + + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + return (DataAccessException) translations.get(ex); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jca/StubActivationSpec.java b/org.springframework.testsuite/src/test/java/org/springframework/jca/StubActivationSpec.java new file mode 100644 index 00000000000..9f38822a4e7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jca/StubActivationSpec.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jca; + +import javax.resource.ResourceException; +import javax.resource.spi.ActivationSpec; +import javax.resource.spi.InvalidPropertyException; +import javax.resource.spi.ResourceAdapter; + +/** + * @author Juergen Hoeller + */ +public class StubActivationSpec implements ActivationSpec { + + public void validate() throws InvalidPropertyException { + } + + public ResourceAdapter getResourceAdapter() { + return null; + } + + public void setResourceAdapter(ResourceAdapter resourceAdapter) throws ResourceException { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jca/StubResourceAdapter.java b/org.springframework.testsuite/src/test/java/org/springframework/jca/StubResourceAdapter.java new file mode 100644 index 00000000000..65dcd8b0172 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jca/StubResourceAdapter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jca; + +import javax.resource.ResourceException; +import javax.resource.spi.ActivationSpec; +import javax.resource.spi.BootstrapContext; +import javax.resource.spi.ResourceAdapter; +import javax.resource.spi.ResourceAdapterInternalException; +import javax.resource.spi.endpoint.MessageEndpointFactory; +import javax.transaction.xa.XAResource; + +/** + * @author Juergen Hoeller + */ +public class StubResourceAdapter implements ResourceAdapter { + + public void start(BootstrapContext bootstrapContext) throws ResourceAdapterInternalException { + } + + public void stop() { + } + + public void endpointActivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec) throws ResourceException { + } + + public void endpointDeactivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec) { + } + + public XAResource[] getXAResources(ActivationSpec[] activationSpecs) throws ResourceException { + return null; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciLocalTransactionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciLocalTransactionTests.java new file mode 100644 index 00000000000..3d29787774d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciLocalTransactionTests.java @@ -0,0 +1,187 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jca.cci; + +import javax.resource.ResourceException; +import javax.resource.cci.Connection; +import javax.resource.cci.ConnectionFactory; +import javax.resource.cci.Interaction; +import javax.resource.cci.InteractionSpec; +import javax.resource.cci.LocalTransaction; +import javax.resource.cci.Record; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.DataRetrievalFailureException; +import org.springframework.jca.cci.core.CciTemplate; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Thierry TEMPLIER + */ +public class CciLocalTransactionTests extends TestCase { + + /** + * Test if a transaction ( begin / commit ) is executed on the + * LocalTransaction when CciLocalTransactionManager is specified as + * transaction manager. + */ + public void testLocalTransactionCommit() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl localTransactionControl = MockControl.createControl(LocalTransaction.class); + LocalTransaction localTransaction = (LocalTransaction) localTransactionControl.getMock(); + MockControl recordControl = MockControl.createControl(Record.class); + final Record record = (Record) recordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createControl(InteractionSpec.class); + final InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection, 1); + + connection.getLocalTransaction(); + connectionControl.setReturnValue(localTransaction, 1); + + localTransaction.begin(); + localTransactionControl.setVoidCallable(1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, record, record); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.getLocalTransaction(); + connectionControl.setReturnValue(localTransaction); + + localTransaction.commit(); + localTransactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + localTransactionControl.replay(); + interactionControl.replay(); + + org.springframework.jca.cci.connection.CciLocalTransactionManager tm = new org.springframework.jca.cci.connection.CciLocalTransactionManager(); + tm.setConnectionFactory(connectionFactory); + TransactionTemplate tt = new TransactionTemplate(tm); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(connectionFactory)); + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, record, record); + } + }); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + localTransactionControl.verify(); + } + + /** + * Test if a transaction ( begin / rollback ) is executed on the + * LocalTransaction when CciLocalTransactionManager is specified as + * transaction manager and a non-checked exception is thrown. + */ + public void testLocalTransactionRollback() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl localTransactionControl = MockControl.createControl(LocalTransaction.class); + LocalTransaction localTransaction = (LocalTransaction) localTransactionControl.getMock(); + MockControl recordControl = MockControl.createControl(Record.class); + final Record record = (Record) recordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createControl(InteractionSpec.class); + final InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.getLocalTransaction(); + connectionControl.setReturnValue(localTransaction); + + localTransaction.begin(); + localTransactionControl.setVoidCallable(1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, record, record); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.getLocalTransaction(); + connectionControl.setReturnValue(localTransaction); + + localTransaction.rollback(); + localTransactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + localTransactionControl.replay(); + interactionControl.replay(); + + org.springframework.jca.cci.connection.CciLocalTransactionManager tm = new org.springframework.jca.cci.connection.CciLocalTransactionManager(); + tm.setConnectionFactory(connectionFactory); + TransactionTemplate tt = new TransactionTemplate(tm); + + try { + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(connectionFactory)); + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, record, record); + throw new DataRetrievalFailureException("error"); + } + }); + } + catch (Exception ex) { + } + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + localTransactionControl.verify(); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciTemplateTests.java new file mode 100644 index 00000000000..2c421091589 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/CciTemplateTests.java @@ -0,0 +1,987 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jca.cci; + +import java.sql.SQLException; + +import javax.resource.NotSupportedException; +import javax.resource.ResourceException; +import javax.resource.cci.Connection; +import javax.resource.cci.ConnectionFactory; +import javax.resource.cci.ConnectionSpec; +import javax.resource.cci.IndexedRecord; +import javax.resource.cci.Interaction; +import javax.resource.cci.InteractionSpec; +import javax.resource.cci.MappedRecord; +import javax.resource.cci.Record; +import javax.resource.cci.RecordFactory; +import javax.resource.cci.ResultSet; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter; +import org.springframework.jca.cci.connection.NotSupportedRecordFactory; +import org.springframework.jca.cci.core.CciTemplate; +import org.springframework.jca.cci.core.ConnectionCallback; +import org.springframework.jca.cci.core.InteractionCallback; +import org.springframework.jca.cci.core.RecordCreator; +import org.springframework.jca.cci.core.RecordExtractor; + +/** + * @author Thierry Templier + * @author Juergen Hoeller + */ +public class CciTemplateTests extends TestCase { + + public void testCreateIndexedRecord() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl indexedRecordControl = MockControl.createStrictControl(IndexedRecord.class); + IndexedRecord indexedRecord = (IndexedRecord) indexedRecordControl.getMock(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + recordFactory.createIndexedRecord("name"); + recordFactoryControl.setReturnValue(indexedRecord, 1); + + connectionFactoryControl.replay(); + recordFactoryControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.createIndexedRecord("name"); + + connectionFactoryControl.verify(); + recordFactoryControl.verify(); + } + + public void testCreateMappedRecord() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl mappedRecordControl = MockControl.createStrictControl(MappedRecord.class); + MappedRecord mappedRecord = (MappedRecord) mappedRecordControl.getMock(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + recordFactory.createMappedRecord("name"); + recordFactoryControl.setReturnValue(mappedRecord, 1); + + connectionFactoryControl.replay(); + recordFactoryControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.createMappedRecord("name"); + + connectionFactoryControl.verify(); + recordFactoryControl.verify(); + } + + public void testTemplateExecuteInputOutput() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection, 1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction, 1); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, inputRecord, outputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testTemplateExecuteWithCreatorAndRecordFactoryNotSupported() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + final Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setThrowable(new NotSupportedException("not supported"), 1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.setOutputRecordCreator(new RecordCreator() { + public Record createRecord(RecordFactory recordFactory) { + assertTrue(recordFactory instanceof NotSupportedRecordFactory); + return outputRecord; + } + }); + ct.execute(interactionSpec, inputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testTemplateExecuteInputTrueWithCreator() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl creatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator creator = (RecordCreator) creatorControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + creator.createRecord(recordFactory); + creatorControl.setReturnValue(outputRecord); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + creatorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.setOutputRecordCreator(creator); + ct.execute(interactionSpec, inputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + creatorControl.verify(); + } + + public void testTemplateExecuteInputFalse() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputRecord); + interactionControl.setReturnValue(outputRecord, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, inputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testTemplateExecuteInputExtractorTrueWithCreator() throws ResourceException, SQLException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl extractorControl = MockControl.createStrictControl(RecordExtractor.class); + RecordExtractor extractor = (RecordExtractor) extractorControl.getMock(); + MockControl creatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator creator = (RecordCreator) creatorControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + Object obj = new Object(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + creator.createRecord(recordFactory); + creatorControl.setReturnValue(outputRecord); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + extractor.extractData(outputRecord); + extractorControl.setReturnValue(obj); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + extractorControl.replay(); + creatorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.setOutputRecordCreator(creator); + ct.execute(interactionSpec, inputRecord, extractor); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + extractorControl.verify(); + creatorControl.verify(); + } + + public void testTemplateExecuteInputExtractorFalse() throws ResourceException, SQLException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl extractorControl = MockControl.createStrictControl(RecordExtractor.class); + RecordExtractor extractor = (RecordExtractor) extractorControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + Object obj = new Object(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputRecord); + interactionControl.setReturnValue(outputRecord, 1); + + extractor.extractData(outputRecord); + extractorControl.setReturnValue(obj); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + extractorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, inputRecord, extractor); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + extractorControl.verify(); + } + + public void testTemplateExecuteInputGeneratorTrueWithCreator() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl generatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator generator = (RecordCreator) generatorControl.getMock(); + MockControl creatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator creator = (RecordCreator) creatorControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + generator.createRecord(recordFactory); + generatorControl.setReturnValue(inputRecord); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + creator.createRecord(recordFactory); + creatorControl.setReturnValue(outputRecord); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + generatorControl.replay(); + creatorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.setOutputRecordCreator(creator); + ct.execute(interactionSpec, generator); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + generatorControl.verify(); + creatorControl.verify(); + } + + public void testTemplateExecuteInputGeneratorFalse() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl generatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator generator = (RecordCreator) generatorControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + generator.createRecord(recordFactory); + generatorControl.setReturnValue(inputRecord); + + interaction.execute(interactionSpec, inputRecord); + interactionControl.setReturnValue(outputRecord, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + generatorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, generator); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + generatorControl.verify(); + } + + public void testTemplateExecuteInputGeneratorExtractorTrueWithCreator() throws ResourceException, SQLException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl generatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator generator = (RecordCreator) generatorControl.getMock(); + MockControl extractorControl = MockControl.createStrictControl(RecordExtractor.class); + RecordExtractor extractor = (RecordExtractor) extractorControl.getMock(); + MockControl creatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator creator = (RecordCreator) creatorControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + Object obj = new Object(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + creator.createRecord(recordFactory); + creatorControl.setReturnValue(outputRecord); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + generator.createRecord(recordFactory); + generatorControl.setReturnValue(inputRecord); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + extractor.extractData(outputRecord); + extractorControl.setReturnValue(obj); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + generatorControl.replay(); + extractorControl.replay(); + creatorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.setOutputRecordCreator(creator); + assertEquals(obj, ct.execute(interactionSpec, generator, extractor)); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + generatorControl.verify(); + extractorControl.verify(); + creatorControl.verify(); + } + + public void testTemplateExecuteInputGeneratorExtractorFalse() throws ResourceException, SQLException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl generatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator generator = (RecordCreator) generatorControl.getMock(); + MockControl extractorControl = MockControl.createStrictControl(RecordExtractor.class); + RecordExtractor extractor = (RecordExtractor) extractorControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + Object obj = new Object(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + generator.createRecord(recordFactory); + generatorControl.setReturnValue(inputRecord); + + interaction.execute(interactionSpec, inputRecord); + interactionControl.setReturnValue(outputRecord, 1); + + extractor.extractData(outputRecord); + extractorControl.setReturnValue(obj); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + generatorControl.replay(); + extractorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, generator, extractor); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + generatorControl.verify(); + extractorControl.verify(); + } + + public void testTemplateExecuteInputOutputConnectionSpec() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createStrictControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createStrictControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl connectionSpecControl = MockControl.createStrictControl(ConnectionSpec.class); + ConnectionSpec connectionSpec = (ConnectionSpec) connectionSpecControl.getMock(); + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(connectionSpec); + connectionFactoryControl.setReturnValue(connection, 1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction, 1); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + ConnectionSpecConnectionFactoryAdapter adapter = new ConnectionSpecConnectionFactoryAdapter(); + adapter.setTargetConnectionFactory(connectionFactory); + adapter.setConnectionSpec(connectionSpec); + CciTemplate ct = new CciTemplate(adapter); + ct.execute(interactionSpec, inputRecord, outputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testTemplateExecuteInputOutputResultsSetFalse() throws ResourceException, SQLException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl recordControl = MockControl.createStrictControl(Record.class); + Record record = (Record) recordControl.getMock(); + MockControl resultsetControl = MockControl.createStrictControl(ResultSet.class); + ResultSet resultset = (ResultSet) resultsetControl.getMock(); + MockControl generatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator generator = (RecordCreator) generatorControl.getMock(); + MockControl extractorControl = MockControl.createStrictControl(RecordExtractor.class); + RecordExtractor extractor = (RecordExtractor) extractorControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + Object obj = new Object(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + generator.createRecord(recordFactory); + generatorControl.setReturnValue(record); + + interaction.execute(interactionSpec, record); + interactionControl.setReturnValue(resultset, 1); + + extractor.extractData(resultset); + extractorControl.setReturnValue(obj); + + resultset.close(); + resultsetControl.setVoidCallable(1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + generatorControl.replay(); + extractorControl.replay(); + resultsetControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, generator, extractor); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + generatorControl.verify(); + extractorControl.verify(); + resultsetControl.verify(); + } + + public void testTemplateExecuteConnectionCallback() throws ResourceException, SQLException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl connectionCallbackControl = MockControl.createStrictControl(ConnectionCallback.class); + ConnectionCallback connectionCallback = (ConnectionCallback) connectionCallbackControl.getMock(); + + Object obj = new Object(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connectionCallback.doInConnection(connection, connectionFactory); + connectionCallbackControl.setReturnValue(obj); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + connectionCallbackControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(connectionCallback); + + connectionFactoryControl.verify(); + connectionControl.verify(); + connectionCallbackControl.verify(); + } + + public void testTemplateExecuteInteractionCallback() throws ResourceException, SQLException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl interactionCallbackControl = MockControl.createStrictControl(InteractionCallback.class); + InteractionCallback interactionCallback = (InteractionCallback) interactionCallbackControl.getMock(); + + Object obj = new Object(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interactionCallback.doInInteraction(interaction, connectionFactory); + interactionCallbackControl.setReturnValue(obj); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + interactionCallbackControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionCallback); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + interactionCallbackControl.verify(); + } + + public void testTemplateExecuteInputTrueTrueWithCreator() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + MockControl creatorControl = MockControl.createStrictControl(RecordCreator.class); + RecordCreator creator = (RecordCreator) creatorControl.getMock(); + + MockControl inputOutputRecordControl = MockControl.createStrictControl(Record.class); + Record inputOutputRecord = (Record) inputOutputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputOutputRecord, inputOutputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + creatorControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.setOutputRecordCreator(creator); + ct.execute(interactionSpec, inputOutputRecord, inputOutputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + creatorControl.verify(); + } + + public void testTemplateExecuteInputTrueTrue() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputOutputRecordControl = MockControl.createStrictControl(Record.class); + Record inputOutputRecord = (Record) inputOutputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputOutputRecord, inputOutputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + ct.execute(interactionSpec, inputOutputRecord, inputOutputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testTemplateExecuteInputFalseTrue() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createStrictControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createStrictControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createStrictControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputOutputRecordControl = MockControl.createStrictControl(Record.class); + Record inputOutputRecord = (Record) inputOutputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createStrictControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputOutputRecord); + interactionControl.setReturnValue(null, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + CciTemplate ct = new CciTemplate(connectionFactory); + Record tmpOutputRecord = (Record) ct.execute(interactionSpec, inputOutputRecord); + assertNull(tmpOutputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/EisOperationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/EisOperationTests.java new file mode 100644 index 00000000000..57386ce786c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jca/cci/EisOperationTests.java @@ -0,0 +1,338 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jca.cci; + +import javax.resource.ResourceException; +import javax.resource.cci.Connection; +import javax.resource.cci.ConnectionFactory; +import javax.resource.cci.Interaction; +import javax.resource.cci.InteractionSpec; +import javax.resource.cci.Record; +import javax.resource.cci.RecordFactory; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jca.cci.core.RecordCreator; +import org.springframework.jca.cci.object.MappingRecordOperation; +import org.springframework.jca.cci.object.SimpleRecordOperation; + +/** + * @author Thierry TEMPLIER + */ +public class EisOperationTests extends TestCase { + + public void testSimpleRecordOperation() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + SimpleRecordOperation query = new SimpleRecordOperation(connectionFactory, interactionSpec); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputRecord); + interactionControl.setReturnValue(outputRecord, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + query.execute(inputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testSimpleRecordOperationWithExplicitOutputRecord() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + SimpleRecordOperation operation = new SimpleRecordOperation(connectionFactory, interactionSpec); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection, 1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction, 1); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + operation.execute(inputRecord, outputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testSimpleRecordOperationWithInputOutputRecord() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl connectionControl = MockControl.createControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputOutputRecordControl = MockControl.createControl(Record.class); + Record inputOutputRecord = (Record) inputOutputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + SimpleRecordOperation query = new SimpleRecordOperation(connectionFactory, interactionSpec); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction); + + interaction.execute(interactionSpec, inputOutputRecord, inputOutputRecord); + interactionControl.setReturnValue(true, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + + query.execute(inputOutputRecord, inputOutputRecord); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + } + + public void testMappingRecordOperation() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + + MockControl interactionSpecControl = MockControl.createControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + MockControl callDetectorControl = MockControl.createControl(QueryCallDetector.class); + QueryCallDetector callDetector = (QueryCallDetector) callDetectorControl.getMock(); + + MappingRecordOperationImpl query = new MappingRecordOperationImpl(connectionFactory, interactionSpec); + query.setCallDetector(callDetector); + + Object inObj = new Object(); + Object outObj = new Object(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + callDetector.callCreateInputRecord(recordFactory, inObj); + callDetectorControl.setReturnValue(inputRecord, 1); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection, 1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction, 1); + + interaction.execute(interactionSpec, inputRecord); + interactionControl.setReturnValue(outputRecord, 1); + + callDetector.callExtractOutputData(outputRecord); + callDetectorControl.setReturnValue(outObj, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + callDetectorControl.replay(); + + assertSame(outObj, query.execute(inObj)); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + callDetectorControl.verify(); + } + + public void testMappingRecordOperationWithOutputRecordCreator() throws ResourceException { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + MockControl recordFactoryControl = MockControl.createStrictControl(RecordFactory.class); + RecordFactory recordFactory = (RecordFactory) recordFactoryControl.getMock(); + MockControl connectionControl = MockControl.createControl(Connection.class); + Connection connection = (Connection) connectionControl.getMock(); + MockControl interactionControl = MockControl.createControl(Interaction.class); + Interaction interaction = (Interaction) interactionControl.getMock(); + + MockControl inputRecordControl = MockControl.createControl(Record.class); + Record inputRecord = (Record) inputRecordControl.getMock(); + MockControl outputRecordControl = MockControl.createControl(Record.class); + Record outputRecord = (Record) outputRecordControl.getMock(); + MockControl outputCreatorControl = MockControl.createControl(RecordCreator.class); + RecordCreator outputCreator = (RecordCreator) outputCreatorControl.getMock(); + + MockControl interactionSpecControl = MockControl.createControl(InteractionSpec.class); + InteractionSpec interactionSpec = (InteractionSpec) interactionSpecControl.getMock(); + + MockControl callDetectorControl = MockControl.createControl(QueryCallDetector.class); + QueryCallDetector callDetector = (QueryCallDetector) callDetectorControl.getMock(); + + MappingRecordOperationImpl query = new MappingRecordOperationImpl(connectionFactory, interactionSpec); + query.setOutputRecordCreator(outputCreator); + query.setCallDetector(callDetector); + + Object inObj = new Object(); + Object outObj = new Object(); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + callDetector.callCreateInputRecord(recordFactory, inObj); + callDetectorControl.setReturnValue(inputRecord, 1); + + connectionFactory.getConnection(); + connectionFactoryControl.setReturnValue(connection, 1); + + connection.createInteraction(); + connectionControl.setReturnValue(interaction, 1); + + connectionFactory.getRecordFactory(); + connectionFactoryControl.setReturnValue(recordFactory, 1); + + outputCreator.createRecord(recordFactory); + outputCreatorControl.setReturnValue(outputRecord, 1); + + interaction.execute(interactionSpec, inputRecord, outputRecord); + interactionControl.setReturnValue(true, 1); + + callDetector.callExtractOutputData(outputRecord); + callDetectorControl.setReturnValue(outObj, 1); + + interaction.close(); + interactionControl.setVoidCallable(1); + + connection.close(); + connectionControl.setVoidCallable(1); + + connectionFactoryControl.replay(); + connectionControl.replay(); + interactionControl.replay(); + outputCreatorControl.replay(); + callDetectorControl.replay(); + + assertSame(outObj, query.execute(inObj)); + + connectionFactoryControl.verify(); + connectionControl.verify(); + interactionControl.verify(); + outputCreatorControl.verify(); + callDetectorControl.verify(); + } + + + private class MappingRecordOperationImpl extends MappingRecordOperation { + + private QueryCallDetector callDetector; + + public MappingRecordOperationImpl(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) { + super(connectionFactory, interactionSpec); + } + + public void setCallDetector(QueryCallDetector callDetector) { + this.callDetector = callDetector; + } + + protected Record createInputRecord(RecordFactory recordFactory, Object inputObject) { + return this.callDetector.callCreateInputRecord(recordFactory, inputObject); + } + + protected Object extractOutputData(Record outputRecord) throws ResourceException { + return this.callDetector.callExtractOutputData(outputRecord); + } + } + + + private interface QueryCallDetector { + + Record callCreateInputRecord(RecordFactory recordFactory, Object inputObject); + + Object callExtractOutputData(Record outputRecord); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jca/support/LocalConnectionFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jca/support/LocalConnectionFactoryBeanTests.java new file mode 100644 index 00000000000..b988bed10f5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jca/support/LocalConnectionFactoryBeanTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jca.support; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.springframework.test.AssertThrows; + +import javax.resource.spi.ConnectionManager; +import javax.resource.spi.ManagedConnectionFactory; + +/** + * Unit tests for the {@link LocalConnectionFactoryBean} class. + * + * @author Rick Evans + */ +public final class LocalConnectionFactoryBeanTests extends TestCase { + + public void testManagedConnectionFactoryIsRequired() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new LocalConnectionFactoryBean().afterPropertiesSet(); + } + }.runTest(); + } + + public void testIsSingleton() throws Exception { + LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean(); + assertTrue(factory.isSingleton()); + } + + public void testGetObjectTypeIsNullIfConnectionFactoryHasNotBeenConfigured() throws Exception { + LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean(); + assertNull(factory.getObjectType()); + } + + public void testCreatesVanillaConnectionFactoryIfNoConnectionManagerHasBeenConfigured() throws Exception { + + final Object CONNECTION_FACTORY = new Object(); + + MockControl mockManagedConnectionFactory = MockControl.createControl(ManagedConnectionFactory.class); + ManagedConnectionFactory managedConnectionFactory = (ManagedConnectionFactory) mockManagedConnectionFactory.getMock(); + + managedConnectionFactory.createConnectionFactory(); + mockManagedConnectionFactory.setReturnValue(CONNECTION_FACTORY); + mockManagedConnectionFactory.replay(); + + LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean(); + factory.setManagedConnectionFactory(managedConnectionFactory); + factory.afterPropertiesSet(); + assertEquals(CONNECTION_FACTORY, factory.getObject()); + + mockManagedConnectionFactory.verify(); + } + + public void testCreatesManagedConnectionFactoryIfAConnectionManagerHasBeenConfigured() throws Exception { + MockControl mockManagedConnectionFactory = MockControl.createControl(ManagedConnectionFactory.class); + ManagedConnectionFactory managedConnectionFactory = (ManagedConnectionFactory) mockManagedConnectionFactory.getMock(); + + MockControl mockConnectionManager = MockControl.createControl(ConnectionManager.class); + ConnectionManager connectionManager = (ConnectionManager) mockConnectionManager.getMock(); + + managedConnectionFactory.createConnectionFactory(connectionManager); + mockManagedConnectionFactory.setReturnValue(null); + + mockConnectionManager.replay(); + mockManagedConnectionFactory.replay(); + + LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean(); + factory.setManagedConnectionFactory(managedConnectionFactory); + factory.setConnectionManager(connectionManager); + factory.afterPropertiesSet(); + + mockManagedConnectionFactory.verify(); + mockConnectionManager.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/AbstractJdbcTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/AbstractJdbcTests.java new file mode 100644 index 00000000000..c8fecfdf969 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/AbstractJdbcTests.java @@ -0,0 +1,85 @@ +/* + * AbstractJdbcTests.java + * + * Copyright (C) 2002 by Interprise Software. All rights reserved. + */ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc; + +import java.sql.Connection; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +/** + * @author Trevor D. Cook + */ +public abstract class AbstractJdbcTests extends TestCase { + + protected MockControl ctrlDataSource; + protected DataSource mockDataSource; + protected MockControl ctrlConnection; + protected Connection mockConnection; + + /** + * Set to true if the user wants verification, indicated + * by a call to replay(). We need to make this optional, + * otherwise we setUp() will always result in verification failures + */ + private boolean shouldVerify; + + protected void setUp() throws Exception { + this.shouldVerify = false; + super.setUp(); + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setDefaultReturnValue(null); + mockConnection.close(); + ctrlConnection.setDefaultVoidCallable(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + } + + protected void replay() { + ctrlDataSource.replay(); + ctrlConnection.replay(); + this.shouldVerify = true; + } + + protected void tearDown() throws Exception { + super.tearDown(); + + // we shouldn't verify unless the user called replay() + if (shouldVerify()) { + ctrlDataSource.verify(); + //ctrlConnection.verify(); + } + } + + protected boolean shouldVerify() { + return this.shouldVerify; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/Customer.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/Customer.java new file mode 100644 index 00000000000..7c804be1d82 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/Customer.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc; + +/** + * @author Juergen Hoeller + */ +public class Customer { + + private int id; + + private String forename; + + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getForename() { + return forename; + } + + public void setForename(String forename) { + this.forename = forename; + } + + + public String toString() { + return "Customer: id=" + id + "; forename=" + forename; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java new file mode 100644 index 00000000000..271fadee7c7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java @@ -0,0 +1,145 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.jdbc.core.test.ConcretePerson; +import org.springframework.jdbc.core.test.Person; +import org.springframework.jdbc.datasource.SingleConnectionDataSource; +import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; + +/** + * Mock object based abstract class for RowMapper tests. + * Initializes mock objects and verifies results. + * + * @author Thomas Risberg + */ +public abstract class AbstractRowMapperTests extends TestCase { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + protected MockControl conControl; + protected Connection con; + protected MockControl rsmdControl; + protected ResultSetMetaData rsmd; + protected MockControl rsControl; + protected ResultSet rs; + protected MockControl stmtControl; + protected Statement stmt; + protected JdbcTemplate jdbcTemplate; + + protected void setUp() throws SQLException { + conControl = MockControl.createControl(Connection.class); + con = (Connection) conControl.getMock(); + con.isClosed(); + conControl.setDefaultReturnValue(false); + + rsmdControl = MockControl.createControl(ResultSetMetaData.class); + rsmd = (ResultSetMetaData)rsmdControl.getMock(); + rsmd.getColumnCount(); + rsmdControl.setReturnValue(4, 1); + rsmd.getColumnLabel(1); + rsmdControl.setReturnValue("name", 1); + rsmd.getColumnLabel(2); + rsmdControl.setReturnValue("age", 1); + rsmd.getColumnLabel(3); + rsmdControl.setReturnValue("birth_date", 1); + rsmd.getColumnLabel(4); + rsmdControl.setReturnValue("balance", 1); + rsmdControl.replay(); + + rsControl = MockControl.createControl(ResultSet.class); + rs = (ResultSet) rsControl.getMock(); + rs.getMetaData(); + rsControl.setReturnValue(rsmd, 1); + rs.next(); + rsControl.setReturnValue(true, 1); + rs.getString(1); + rsControl.setReturnValue("Bubba", 1); + rs.wasNull(); + rsControl.setReturnValue(false, 1); + rs.getLong(2); + rsControl.setReturnValue(22, 1); + rs.getTimestamp(3); + rsControl.setReturnValue(new Timestamp(1221222L), 1); + rs.getBigDecimal(4); + rsControl.setReturnValue(new BigDecimal("1234.56"), 1); + rs.next(); + rsControl.setReturnValue(false, 1); + rs.close(); + rsControl.setVoidCallable(1); + rsControl.replay(); + + stmtControl = MockControl.createControl(Statement.class); + stmt = (Statement) stmtControl.getMock(); + + con.createStatement(); + conControl.setReturnValue(stmt, 1); + stmt.executeQuery("select name, age, birth_date, balance from people"); + stmtControl.setReturnValue(rs, 1); + if (debugEnabled) { + stmt.getWarnings(); + stmtControl.setReturnValue(null, 1); + } + stmt.close(); + stmtControl.setVoidCallable(1); + + conControl.replay(); + stmtControl.replay(); + + jdbcTemplate = new JdbcTemplate(); + jdbcTemplate.setDataSource(new SingleConnectionDataSource(con, false)); + jdbcTemplate.setExceptionTranslator(new SQLStateSQLExceptionTranslator()); + jdbcTemplate.afterPropertiesSet(); + } + + protected void verifyPerson(Person bean) { + verify(); + assertEquals("Bubba", bean.getName()); + assertEquals(22L, bean.getAge()); + assertEquals(new java.util.Date(1221222L), bean.getBirth_date()); + assertEquals(new BigDecimal("1234.56"), bean.getBalance()); + } + + protected void verifyConcretePerson(ConcretePerson bean) { + verify(); + assertEquals("Bubba", bean.getName()); + assertEquals(22L, bean.getAge()); + assertEquals(new java.util.Date(1221222L), bean.getBirth_date()); + assertEquals(new BigDecimal("1234.56"), bean.getBalance()); + } + + private void verify() { + conControl.verify(); + rsControl.verify(); + rsmdControl.verify(); + stmtControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java new file mode 100644 index 00000000000..e877542898b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.sql.SQLException; +import java.util.List; + +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.jdbc.core.test.ConcretePerson; +import org.springframework.jdbc.core.test.ExtendedPerson; +import org.springframework.jdbc.core.test.Person; + +/** + * @author Thomas Risberg + * @author Juergen Hoeller + */ +public class BeanPropertyRowMapperTests extends AbstractRowMapperTests { + + public void testOverridingClassDefinedForMapping() { + BeanPropertyRowMapper mapper = new BeanPropertyRowMapper(Person.class); + try { + mapper.setMappedClass(Long.class); + fail("Setting new class should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + } + try { + mapper.setMappedClass(Person.class); + } + catch (InvalidDataAccessApiUsageException ex) { + fail("Setting same class should not have thrown InvalidDataAccessApiUsageException"); + } + } + + public void testStaticQueryWithRowMapper() throws SQLException { + List result = jdbcTemplate.query("select name, age, birth_date, balance from people", + new BeanPropertyRowMapper(Person.class)); + assertEquals(1, result.size()); + Person bean = (Person) result.get(0); + verifyPerson(bean); + } + + public void testMappingWithInheritance() throws SQLException { + List result = jdbcTemplate.query("select name, age, birth_date, balance from people", + new BeanPropertyRowMapper(ConcretePerson.class)); + assertEquals(1, result.size()); + ConcretePerson bean = (ConcretePerson) result.get(0); + verifyConcretePerson(bean); + } + + public void testMappingWithNoUnpopulatedFieldsFound() throws SQLException { + List result = jdbcTemplate.query("select name, age, birth_date, balance from people", + new BeanPropertyRowMapper(ConcretePerson.class, true)); + assertEquals(1, result.size()); + ConcretePerson bean = (ConcretePerson) result.get(0); + verifyConcretePerson(bean); + } + + public void testMappingWithUnpopulatedFieldsNotChecked() throws SQLException { + List result = jdbcTemplate.query("select name, age, birth_date, balance from people", + new BeanPropertyRowMapper(ExtendedPerson.class)); + assertEquals(1, result.size()); + ExtendedPerson bean = (ExtendedPerson) result.get(0); + verifyConcretePerson(bean); + } + + public void testMappingWithUnpopulatedFieldsNotAccepted() throws SQLException { + try { + List result = jdbcTemplate.query("select name, age, birth_date, balance from people", + new BeanPropertyRowMapper(ExtendedPerson.class, true)); + fail("Should have thrown InvalidDataAccessApiUsageException because of missing field"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java new file mode 100644 index 00000000000..9851a23923c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java @@ -0,0 +1,983 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; +import java.util.Map; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.jdbc.AbstractJdbcTests; + +/** + * @author Juergen Hoeller + * @since 19.12.2004 + */ +public class JdbcTemplateQueryTests extends AbstractJdbcTests { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl ctrlStatement; + private Statement mockStatement; + private MockControl ctrlPreparedStatement; + private PreparedStatement mockPreparedStatement; + private MockControl ctrlResultSet; + private ResultSet mockResultSet; + private MockControl ctrlResultSetMetaData; + private ResultSetMetaData mockResultSetMetaData; + + protected void setUp() throws Exception { + super.setUp(); + + ctrlStatement = MockControl.createControl(Statement.class); + mockStatement = (Statement) ctrlStatement.getMock(); + ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + } + + protected void replay() { + super.replay(); + ctrlStatement.replay(); + ctrlPreparedStatement.replay(); + ctrlResultSet.replay(); + ctrlResultSetMetaData.replay(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (shouldVerify()) { + ctrlStatement.verify(); + ctrlPreparedStatement.verify(); + ctrlResultSet.verify(); + ctrlResultSetMetaData.verify(); + } + } + + public void testQueryForList() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1, 2); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 2); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 2); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(12)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + List li = template.queryForList(sql); + assertEquals("All rows returned", 2, li.size()); + assertEquals("First row is Integer", 11, ((Integer)((Map)li.get(0)).get("age")).intValue()); + assertEquals("Second row is Integer", 12, ((Integer)((Map)li.get(1)).get("age")).intValue()); + } + + public void testQueryForListWithEmptyResult() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < 3"; + + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + List li = template.queryForList(sql); + assertEquals("All rows returned", 0, li.size()); + } + + public void testQueryForListWithSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + List li = template.queryForList(sql); + assertEquals("All rows returned", 1, li.size()); + assertEquals("First row is Integer", 11, ((Integer)((Map)li.get(0)).get("age")).intValue()); + } + + public void testQueryForListWithIntegerElement() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(11); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + List li = template.queryForList(sql, Integer.class); + assertEquals("All rows returned", 1, li.size()); + assertEquals("Element is Integer", 11, ((Integer) li.get(0)).intValue()); + } + + public void testQueryForMapWithSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + Map map = template.queryForMap(sql); + assertEquals("Wow is Integer", 11, ((Integer) map.get("age")).intValue()); + } + + public void testQueryForObjectThrowsIncorrectResultSizeForMoreThanOneRow() throws Exception { + String sql = "select pass from t_account where first_name='Alef'"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue("pass"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue("pass"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + try { + template.queryForObject(sql, String.class); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + } + } + + public void testQueryForObjectWithRowMapper() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + Object o = template.queryForObject(sql, new RowMapper() { + public Object mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Integer(rs.getInt(1)); + } + }); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForObjectWithString() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue("myvalue"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + assertEquals("myvalue", template.queryForObject(sql, String.class)); + } + + public void testQueryForObjectWithBigInteger() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue("22"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + assertEquals(new BigInteger("22"), template.queryForObject(sql, BigInteger.class)); + } + + public void testQueryForObjectWithBigDecimal() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getBigDecimal(1); + ctrlResultSet.setReturnValue(new BigDecimal(22.5)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + assertEquals(new BigDecimal(22.5), template.queryForObject(sql, BigDecimal.class)); + } + + public void testQueryForObjectWithInteger() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + assertEquals(new Integer(22), template.queryForObject(sql, Integer.class)); + } + + public void testQueryForObjectWithIntegerAndNull() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(0); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(true); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + assertNull(template.queryForObject(sql, Integer.class)); + } + + public void testQueryForInt() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + int i = template.queryForInt(sql); + assertEquals("Return of an int", 22, i); + } + + public void testQueryForLong() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getLong(1); + ctrlResultSet.setReturnValue(87); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + long l = template.queryForLong(sql); + assertEquals("Return of a long", 87, l); + } + + public void testQueryForListWithArgs() throws Exception { + doTestQueryForListWithArgs("SELECT AGE FROM CUSTMR WHERE ID < ?"); + } + + public void testQueryForListIsNotConfusedByNamedParameterPrefix() throws Exception { + doTestQueryForListWithArgs("SELECT AGE FROM PREFIX:CUSTMR WHERE ID < ?"); + } + + private void doTestQueryForListWithArgs(String sql) throws Exception { + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1, 2); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 2); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 2); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(12)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + List li = template.queryForList(sql, new Object[] {new Integer(3)}); + assertEquals("All rows returned", 2, li.size()); + assertEquals("First row is Integer", 11, ((Integer)((Map)li.get(0)).get("age")).intValue()); + assertEquals("Second row is Integer", 12, ((Integer)((Map)li.get(1)).get("age")).intValue()); + } + + public void testQueryForListWithArgsAndEmptyResult() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + List li = template.queryForList(sql, new Object[] {new Integer(3)}); + assertEquals("All rows returned", 0, li.size()); + } + + public void testQueryForListWithArgsAndSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + List li = template.queryForList(sql, new Object[] {new Integer(3)}); + assertEquals("All rows returned", 1, li.size()); + assertEquals("First row is Integer", 11, ((Integer)((Map)li.get(0)).get("age")).intValue()); + } + + public void testQueryForListWithArgsAndIntegerElementAndSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(11); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + List li = template.queryForList(sql, new Object[] {new Integer(3)}, Integer.class); + assertEquals("All rows returned", 1, li.size()); + assertEquals("First row is Integer", 11, ((Integer) li.get(0)).intValue()); + } + + public void testQueryForMapWithArgsAndSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + Map map = template.queryForMap(sql, new Object[] {new Integer(3)}); + assertEquals("Row is Integer", 11, ((Integer) map.get("age")).intValue()); + } + + public void testQueryForObjectWithArgsAndRowMapper() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + Object o = template.queryForObject(sql, new Object[] {new Integer(3)}, new RowMapper() { + public Object mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Integer(rs.getInt(1)); + } + }); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForObjectWithArgsAndInteger() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + Object o = template.queryForObject(sql, new Object[] {new Integer(3)}, Integer.class); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForIntWithArgs() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + int i = template.queryForInt(sql, new Object[] {new Integer(3)}); + assertEquals("Return of an int", 22, i); + } + + public void testQueryForLongWithArgs() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getLong(1); + ctrlResultSet.setReturnValue(87); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + long l = template.queryForLong(sql, new Object[] {new Integer(3)}); + assertEquals("Return of a long", 87, l); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java new file mode 100644 index 00000000000..2014c9daf5b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java @@ -0,0 +1,2057 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Statement; +import java.sql.Types; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.UncategorizedDataAccessException; +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.CannotGetJdbcConnectionException; +import org.springframework.jdbc.SQLWarningException; +import org.springframework.jdbc.UncategorizedSQLException; +import org.springframework.jdbc.core.support.AbstractInterruptibleBatchPreparedStatementSetter; +import org.springframework.jdbc.datasource.SingleConnectionDataSource; +import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; +import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; +import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor; +import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractorAdapter; + +/** + * Mock object based tests for JdbcTemplate. + * + * @author Rod Johnson + * @author Thomas Risberg + * @author Juergen Hoeller + */ +public class JdbcTemplateTests extends AbstractJdbcTests { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + + public void testBeanProperties() throws Exception { + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + assertTrue("datasource ok", template.getDataSource() == mockDataSource); + assertTrue("ignores warnings by default", template.isIgnoreWarnings()); + template.setIgnoreWarnings(false); + assertTrue("can set NOT to ignore warnings", !template.isIgnoreWarnings()); + } + + public void testUpdateCount() throws Exception { + final String sql = + "UPDATE INVOICE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + int idParam = 11111; + + MockControl ctrlPreparedStatement = + MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = + (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.setInt(1, idParam); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + ctrlPreparedStatement.replay(); + replay(); + + Dispatcher d = new Dispatcher(idParam, sql); + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + int rowsAffected = template.update(d); + assertTrue("1 update affected 1 row", rowsAffected == 1); + + /* + d = new Dispatcher(idParam); + rowsAffected = template.update(d); + assertTrue("bogus update affected 0 rows", rowsAffected == 0); + */ + + ctrlPreparedStatement.verify(); + } + + public void testBogusUpdate() throws Exception { + final String sql = + "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int idParam = 6666; + + // It's because Integers aren't canonical + SQLException sex = new SQLException("bad update"); + + MockControl ctrlPreparedStatement = + MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = + (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.setInt(1, idParam); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setThrowable(sex); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + ctrlPreparedStatement.replay(); + replay(); + + Dispatcher d = new Dispatcher(idParam, sql); + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + try { + template.update(d); + fail("Bogus update should throw exception"); + } + catch (UncategorizedDataAccessException ex) { + // pass + assertTrue( + "Correct exception", + ex instanceof UncategorizedSQLException); + assertTrue("Root cause is correct", ex.getCause() == sex); + //assertTrue("no update occurred", !je.getDataWasUpdated()); + } + + ctrlPreparedStatement.verify(); + } + + public void testStringsWithStaticSql() throws Exception { + doTestStrings(new JdbcTemplateCallback() { + public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { + template.query(sql, rch); + } + }, false, null, null, null, null); + } + + public void testStringsWithStaticSqlAndFetchSizeAndMaxRows() throws Exception { + doTestStrings(new JdbcTemplateCallback() { + public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { + template.query(sql, rch); + } + }, false, new Integer(10), new Integer(20), new Integer(30), null); + } + + public void testStringsWithEmptyPreparedStatementSetter() throws Exception { + doTestStrings(new JdbcTemplateCallback() { + public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { + template.query(sql, (PreparedStatementSetter) null, rch); + } + }, true, null, null, null, null); + } + + public void testStringsWithPreparedStatementSetter() throws Exception { + final Integer argument = new Integer(99); + doTestStrings(new JdbcTemplateCallback() { + public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { + template.query(sql, new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) throws SQLException { + ps.setObject(1, argument); + } + }, rch); + } + }, true, null, null, null, argument); + } + + public void testStringsWithEmptyPreparedStatementArgs() throws Exception { + doTestStrings(new JdbcTemplateCallback() { + public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { + template.query(sql, (Object[]) null, rch); + } + }, true, null, null, null, null); + } + + public void testStringsWithPreparedStatementArgs() throws Exception { + final Integer argument = new Integer(99); + doTestStrings(new JdbcTemplateCallback() { + public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { + template.query(sql, new Object[] {argument}, rch); + } + }, true, null, null, null, argument); + } + + private void doTestStrings( + JdbcTemplateCallback jdbcTemplateCallback, boolean usePreparedStatement, + Integer fetchSize, Integer maxRows, Integer queryTimeout, Object argument) + throws Exception { + + String sql = "SELECT FORENAME FROM CUSTMR"; + String[] results = { "rod", "gary", " portia" }; + + class StringHandler implements RowCallbackHandler { + private List list = new LinkedList(); + public void processRow(ResultSet rs) throws SQLException { + list.add(rs.getString(1)); + } + public String[] getStrings() { + return (String[]) list.toArray(new String[list.size()]); + } + } + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue(results[0]); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue(results[1]); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue(results[2]); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + if (fetchSize != null) { + mockStatement.setFetchSize(fetchSize.intValue()); + } + if (maxRows != null) { + mockStatement.setMaxRows(maxRows.intValue()); + } + if (queryTimeout != null) { + mockStatement.setQueryTimeout(queryTimeout.intValue()); + } + if (argument != null) { + mockStatement.setObject(1, argument); + } + if (usePreparedStatement) { + mockStatement.executeQuery(); + } + else { + mockStatement.executeQuery(sql); + } + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + if (usePreparedStatement) { + mockConnection.prepareStatement(sql); + } + else { + mockConnection.createStatement(); + } + ctrlConnection.setReturnValue(mockStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + StringHandler sh = new StringHandler(); + JdbcTemplate template = new JdbcTemplate(); + template.setDataSource(mockDataSource); + if (fetchSize != null) { + template.setFetchSize(fetchSize.intValue()); + } + if (maxRows != null) { + template.setMaxRows(maxRows.intValue()); + } + if (queryTimeout != null) { + template.setQueryTimeout(queryTimeout.intValue()); + } + jdbcTemplateCallback.doInJdbcTemplate(template, sql, sh); + + // Match + String[] forenames = sh.getStrings(); + assertTrue("same length", forenames.length == results.length); + for (int i = 0; i < forenames.length; i++) { + assertTrue("Row " + i + " matches", forenames[i].equals(results[i])); + } + + ctrlResultSet.verify(); + ctrlStatement.verify(); + } + + public void testLeaveConnectionOpenOnRequest() throws Exception { + String sql = "SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3"; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + ctrlStatement = MockControl.createControl(PreparedStatement.class); + mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.isClosed(); + ctrlConnection.setReturnValue(false, 2); + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + // if close is called entire test will fail + mockConnection.close(); + ctrlConnection.setDefaultThrowable(new RuntimeException()); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + SingleConnectionDataSource scf = new SingleConnectionDataSource(mockDataSource.getConnection(), false); + JdbcTemplate template2 = new JdbcTemplate(scf, false); + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template2.query(sql, rcch); + + ctrlResultSet.verify(); + ctrlStatement.verify(); + } + + public void testConnectionCallback() throws Exception { + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + template.setNativeJdbcExtractor(new PlainNativeJdbcExtractor()); + Object result = template.execute(new ConnectionCallback() { + public Object doInConnection(Connection con) { + assertSame(mockConnection, con); + return "test"; + } + }); + + assertEquals("test", result); + } + + public void testConnectionCallbackWithStatementSettings() throws Exception { + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockConnection.prepareStatement("some SQL"); + ctrlConnection.setReturnValue(mockStatement, 1); + mockStatement.setFetchSize(10); + ctrlStatement.setVoidCallable(1); + mockStatement.setMaxRows(20); + ctrlStatement.setVoidCallable(1); + mockStatement.close(); + ctrlStatement.setVoidCallable(1); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + Object result = template.execute(new ConnectionCallback() { + public Object doInConnection(Connection con) throws SQLException { + PreparedStatement ps = con.prepareStatement("some SQL"); + ps.close(); + assertSame(mockConnection, new PlainNativeJdbcExtractor().getNativeConnection(con)); + return "test"; + } + }); + + assertEquals("test", result); + } + + public void testCloseConnectionOnRequest() throws Exception { + String sql = "SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3"; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template.query(sql, rcch); + + ctrlResultSet.verify(); + ctrlStatement.verify(); + } + + /** + * Test that we see a runtime exception come back. + */ + public void testExceptionComesBack() throws Exception { + final String sql = "SELECT ID FROM CUSTMR"; + final RuntimeException rex = new RuntimeException("What I want to see"); + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + try { + template.query(sql, new RowCallbackHandler() { + public void processRow(ResultSet rs) { + throw rex; + } + }); + fail("Should have thrown exception"); + } + catch (RuntimeException ex) { + assertTrue("Wanted same exception back, not " + ex, ex == rex); + } + } + + /** + * Test update with static SQL. + */ + public void testSqlUpdate() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 4"; + int rowsAffected = 33; + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + mockStatement.executeUpdate(sql); + ctrlStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + ctrlStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + int actualRowsAffected = template.update(sql); + assertTrue("Actual rows affected is correct", actualRowsAffected == rowsAffected); + ctrlStatement.verify(); + } + + /** + * Test update with dynamic SQL. + */ + public void testSqlUpdateWithArguments() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ? and PR = ?"; + int rowsAffected = 33; + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.setObject(1, new Integer(4)); + ctrlStatement.setVoidCallable(); + mockStatement.setObject(2, new Float(1.4142), Types.NUMERIC, 2); + ctrlStatement.setVoidCallable(); + mockStatement.executeUpdate(); + ctrlStatement.setReturnValue(33); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockStatement); + ctrlStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + int actualRowsAffected = template.update(sql, + new Object[] {new Integer(4), new SqlParameterValue(Types.NUMERIC, 2, new Float(1.4142))}); + assertTrue("Actual rows affected is correct", actualRowsAffected == rowsAffected); + ctrlStatement.verify(); + } + + public void testSqlUpdateEncountersSqlException() throws Exception { + SQLException sex = new SQLException("bad update"); + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 4"; + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + mockStatement.executeUpdate(sql); + ctrlStatement.setThrowable(sex); + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + try { + template.update(sql); + } + catch (DataAccessException ex) { + assertTrue("root cause is correct", ex.getCause() == sex); + } + + ctrlStatement.verify(); + } + + public void testSqlUpdateWithThreadConnection() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 4"; + int rowsAffected = 33; + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + mockStatement.executeUpdate(sql); + ctrlStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + int actualRowsAffected = template.update(sql); + assertTrue( + "Actual rows affected is correct", + actualRowsAffected == rowsAffected); + + ctrlStatement.verify(); + } + + public void testBatchUpdate() throws Exception { + final String[] sql = {"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 1", + "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 2"}; + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + mockStatement.getConnection(); + ctrlStatement.setReturnValue(mockConnection); + mockStatement.addBatch(sql[0]); + ctrlStatement.setVoidCallable(); + mockStatement.addBatch(sql[1]); + ctrlStatement.setVoidCallable(); + mockStatement.executeBatch(); + ctrlStatement.setReturnValue(new int[] {1, 1}); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + + int[] actualRowsAffected = template.batchUpdate(sql); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + + ctrlStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testBatchUpdateWithNoBatchSupport() throws Exception { + final String[] sql = {"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 1", + "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 2"}; + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + mockStatement.getConnection(); + ctrlStatement.setReturnValue(mockConnection); + mockStatement.execute(sql[0]); + ctrlStatement.setReturnValue(false); + mockStatement.getUpdateCount(); + ctrlStatement.setReturnValue(1); + mockStatement.execute(sql[1]); + ctrlStatement.setReturnValue(false); + mockStatement.getUpdateCount(); + ctrlStatement.setReturnValue(1); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(false); + + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + + int[] actualRowsAffected = template.batchUpdate(sql); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + + ctrlStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testBatchUpdateWithNoBatchSupportAndSelect() throws Exception { + final String[] sql = {"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = 1", + "SELECT * FROM NOSUCHTABLE"}; + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + mockStatement.getConnection(); + ctrlStatement.setReturnValue(mockConnection); + mockStatement.execute(sql[0]); + ctrlStatement.setReturnValue(false); + mockStatement.getUpdateCount(); + ctrlStatement.setReturnValue(1); + mockStatement.execute(sql[1]); + ctrlStatement.setReturnValue(true); + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(false); + + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + + try { + template.batchUpdate(sql); + fail("Shouldn't have executed batch statement with a select"); + } + catch (DataAccessException ex) { + // pass + assertTrue("Check exception type", ex.getClass() == InvalidDataAccessApiUsageException.class); + } + + ctrlStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testBatchUpdateWithPreparedStatement() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int[] ids = new int[] { 100, 200 }; + final int[] rowsAffected = new int[] { 1, 2 }; + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setInt(1, ids[0]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setInt(1, ids[1]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeBatch(); + ctrlPreparedStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + BatchPreparedStatementSetter setter = + new BatchPreparedStatementSetter() { + public void setValues(PreparedStatement ps, int i) + throws SQLException { + ps.setInt(1, ids[i]); + } + public int getBatchSize() { + return ids.length; + } + }; + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + + int[] actualRowsAffected = template.batchUpdate(sql, setter); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testInterruptibleBatchUpdate() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int[] ids = new int[] { 100, 200 }; + final int[] rowsAffected = new int[] { 1, 2 }; + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setInt(1, ids[0]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setInt(1, ids[1]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeBatch(); + ctrlPreparedStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + BatchPreparedStatementSetter setter = + new InterruptibleBatchPreparedStatementSetter() { + public void setValues(PreparedStatement ps, int i) throws SQLException { + if (i < ids.length) { + ps.setInt(1, ids[i]); + } + } + public int getBatchSize() { + return 1000; + } + public boolean isBatchExhausted(int i) { + return (i >= ids.length); + } + }; + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + + int[] actualRowsAffected = template.batchUpdate(sql, setter); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testInterruptibleBatchUpdateWithBaseClass() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int[] ids = new int[] { 100, 200 }; + final int[] rowsAffected = new int[] { 1, 2 }; + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setInt(1, ids[0]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setInt(1, ids[1]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeBatch(); + ctrlPreparedStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + BatchPreparedStatementSetter setter = + new AbstractInterruptibleBatchPreparedStatementSetter() { + protected boolean setValuesIfAvailable(PreparedStatement ps, int i) throws SQLException { + if (i < ids.length) { + ps.setInt(1, ids[i]); + return true; + } + else { + return false; + } + } + }; + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + + int[] actualRowsAffected = template.batchUpdate(sql, setter); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testInterruptibleBatchUpdateWithBaseClassAndNoBatchSupport() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int[] ids = new int[] { 100, 200 }; + final int[] rowsAffected = new int[] { 1, 2 }; + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setInt(1, ids[0]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(rowsAffected[0]); + mockPreparedStatement.setInt(1, ids[1]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(rowsAffected[1]); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(false); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + BatchPreparedStatementSetter setter = + new AbstractInterruptibleBatchPreparedStatementSetter() { + protected boolean setValuesIfAvailable(PreparedStatement ps, int i) throws SQLException { + if (i < ids.length) { + ps.setInt(1, ids[i]); + return true; + } + else { + return false; + } + } + }; + + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + + int[] actualRowsAffected = template.batchUpdate(sql, setter); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testBatchUpdateWithPreparedStatementAndNoBatchSupport() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int[] ids = new int[] { 100, 200 }; + final int[] rowsAffected = new int[] { 1, 2 }; + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setInt(1, ids[0]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(rowsAffected[0]); + mockPreparedStatement.setInt(1, ids[1]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(rowsAffected[1]); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + ctrlPreparedStatement.replay(); + replay(); + + BatchPreparedStatementSetter setter = new BatchPreparedStatementSetter() { + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, ids[i]); + } + public int getBatchSize() { + return ids.length; + } + }; + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + int[] actualRowsAffected = template.batchUpdate(sql, setter); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + ctrlPreparedStatement.verify(); + } + + public void testBatchUpdateFails() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int[] ids = new int[] { 100, 200 }; + SQLException sex = new SQLException(); + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setInt(1, ids[0]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setInt(1, ids[1]); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeBatch(); + ctrlPreparedStatement.setThrowable(sex); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + ctrlConnection.reset(); + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 2); + mockConnection.close(); + ctrlConnection.setVoidCallable(2); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + BatchPreparedStatementSetter setter = new BatchPreparedStatementSetter() { + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, ids[i]); + } + public int getBatchSize() { + return ids.length; + } + }; + + try { + JdbcTemplate template = new JdbcTemplate(mockDataSource); + template.batchUpdate(sql, setter); + fail("Should have failed because of SQLException in bulk update"); + } + catch (DataAccessException ex) { + assertTrue("Root cause is SQLException", ex.getCause() == sex); + } + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testCouldntGetConnectionOrExceptionTranslator() throws SQLException { + SQLException sex = new SQLException("foo", "07xxx"); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + // Expect two calls (one call after caching data product name): make get metadata fail also + ctrlDataSource.setThrowable(sex, 2); + replay(); + + try { + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch); + fail("Shouldn't have executed query without a connection"); + } + catch (CannotGetJdbcConnectionException ex) { + // pass + assertTrue("Check root cause", ex.getCause() == sex); + } + + ctrlDataSource.verify(); + } + + public void testCouldntGetConnectionForOperationOrExceptionTranslator() throws SQLException { + SQLException sex = new SQLException("foo", "07xxx"); + + // Change behavior in setUp() because we only expect one call to getConnection(): + // none is necessary to get metadata for exception translator + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + // Expect two calls (one call after caching data product name): make get Metadata fail also + ctrlDataSource.setThrowable(sex, 2); + replay(); + + try { + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch); + fail("Shouldn't have executed query without a connection"); + } + catch (CannotGetJdbcConnectionException ex) { + // pass + assertTrue("Check root cause", ex.getCause() == sex); + } + + ctrlDataSource.verify(); + } + + public void testCouldntGetConnectionForOperationWithLazyExceptionTranslator() throws SQLException { + SQLException sex = new SQLException("foo", "07xxx"); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setThrowable(sex, 1); + replay(); + + try { + JdbcTemplate template2 = new JdbcTemplate(); + template2.setDataSource(mockDataSource); + template2.afterPropertiesSet(); + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template2.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch); + fail("Shouldn't have executed query without a connection"); + } + catch (CannotGetJdbcConnectionException ex) { + // pass + assertTrue("Check root cause", ex.getCause() == sex); + } + + ctrlDataSource.verify(); + } + + /** + * Verify that afterPropertiesSet invokes exception translator. + */ + public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitialized() throws SQLException { + SQLException sex = new SQLException("foo", "07xxx"); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + //mockConnection.getMetaData(); + //ctrlConnection.setReturnValue(null, 1); + //mockConnection.close(); + //ctrlConnection.setVoidCallable(1); + ctrlConnection.replay(); + + // Change behaviour in setUp() because we only expect one call to getConnection(): + // none is necessary to get metadata for exception translator + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + // Upfront call for metadata - no longer the case + //mockDataSource.getConnection(); + //ctrlDataSource.setReturnValue(mockConnection, 1); + // One call for operation + mockDataSource.getConnection(); + ctrlDataSource.setThrowable(sex, 2); + ctrlDataSource.replay(); + + try { + JdbcTemplate template = new JdbcTemplate(mockDataSource, false); + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch); + fail("Shouldn't have executed query without a connection"); + } + catch (CannotGetJdbcConnectionException ex) { + // pass + assertTrue("Check root cause", ex.getCause() == sex); + } + + ctrlDataSource.verify(); + ctrlConnection.verify(); + } + + public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedViaBeanProperty() + throws Exception { + doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(true); + } + + public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedInAfterPropertiesSet() + throws Exception { + doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(false); + } + + /** + * If beanProperty is true, initialize via exception translator bean property; + * if false, use afterPropertiesSet(). + */ + private void doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(boolean beanProperty) + throws SQLException { + + SQLException sex = new SQLException("foo", "07xxx"); + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + //mockConnection.getMetaData(); + //ctrlConnection.setReturnValue(null, 1); + //mockConnection.close(); + //ctrlConnection.setVoidCallable(1); + ctrlConnection.replay(); + + // Change behaviour in setUp() because we only expect one call to getConnection(): + // none is necessary to get metadata for exception translator + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + // Upfront call for metadata - no longer the case + //mockDataSource.getConnection(); + //ctrlDataSource.setReturnValue(mockConnection, 1); + // One call for operation + mockDataSource.getConnection(); + ctrlDataSource.setThrowable(sex, 2); + ctrlDataSource.replay(); + + try { + JdbcTemplate template2 = new JdbcTemplate(); + template2.setDataSource(mockDataSource); + template2.setLazyInit(false); + if (beanProperty) { + // This will get a connection. + template2.setExceptionTranslator(new SQLErrorCodeSQLExceptionTranslator(mockDataSource)); + } + else { + // This will cause creation of default SQL translator. + // Note that only call should be effective. + template2.afterPropertiesSet(); + template2.afterPropertiesSet(); + } + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template2.query( + "SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", + rcch); + fail("Shouldn't have executed query without a connection"); + } + catch (CannotGetJdbcConnectionException ex) { + // pass + assertTrue("Check root cause", ex.getCause() == sex); + } + + ctrlDataSource.verify(); + ctrlConnection.verify(); + } + + public void testPreparedStatementSetterSucceeds() throws Exception { + final String sql = "UPDATE FOO SET NAME=? WHERE ID = 1"; + final String name = "Gary"; + int expectedRowsUpdated = 1; + + MockControl ctrlPreparedStatement = + MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = + (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.setString(1, name); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(expectedRowsUpdated); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + ctrlPreparedStatement.replay(); + replay(); + + PreparedStatementSetter pss = new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) throws SQLException { + ps.setString(1, name); + } + }; + int actualRowsUpdated = + new JdbcTemplate(mockDataSource).update(sql, pss); + assertTrue( + "updated correct # of rows", + actualRowsUpdated == expectedRowsUpdated); + + ctrlPreparedStatement.verify(); + } + + public void testPreparedStatementSetterFails() throws Exception { + final String sql = "UPDATE FOO SET NAME=? WHERE ID = 1"; + final String name = "Gary"; + SQLException sex = new SQLException(); + + MockControl ctrlPreparedStatement = + MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = + (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.setString(1, name); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setThrowable(sex); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + + ctrlPreparedStatement.replay(); + replay(); + + PreparedStatementSetter pss = new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) throws SQLException { + ps.setString(1, name); + } + }; + try { + new JdbcTemplate(mockDataSource).update(sql, pss); + fail("Should have failed with SQLException"); + } + catch (DataAccessException ex) { + assertTrue("root cause was preserved", ex.getCause() == sex); + } + + ctrlPreparedStatement.verify(); + } + + public void testCouldntClose() throws Exception { + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + String sql = "SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3"; + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + SQLException sex = new SQLException("bar"); + mockResultSet.close(); + ctrlResultSet.setThrowable(sex); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setThrowable(sex); + mockConnection.close(); + ctrlConnection.setThrowable(sex); + + ctrlStatement.replay(); + ctrlResultSet.replay(); + replay(); + + JdbcTemplate template2 = new JdbcTemplate(mockDataSource); + RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + template2.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch); + + ctrlStatement.verify(); + ctrlResultSet.verify(); + } + + /** + * Mock objects allow us to produce warnings at will + */ + public void testFatalWarning() throws Exception { + String sql = "SELECT forename from custmr"; + SQLWarning warnings = new SQLWarning("My warning"); + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(warnings); + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + JdbcTemplate t = new JdbcTemplate(mockDataSource); + t.setIgnoreWarnings(false); + try { + t.query(sql, new RowCallbackHandler() { + public void processRow(ResultSet rs) throws SQLException { + rs.getByte(1); + } + }); + fail("Should have thrown exception on warning"); + } + catch (SQLWarningException ex) { + // Pass + assertTrue( + "Root cause of warning was correct", + ex.getCause() == warnings); + } + + ctrlResultSet.verify(); + ctrlStatement.verify(); + } + + public void testIgnoredWarning() throws Exception { + String sql = "SELECT forename from custmr"; + SQLWarning warnings = new SQLWarning("My warning"); + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = + MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = + (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + // Too long: truncation + JdbcTemplate template = new JdbcTemplate(mockDataSource); + template.setIgnoreWarnings(true); + template.query(sql, new RowCallbackHandler() { + public void processRow(ResultSet rs) + throws java.sql.SQLException { + rs.getByte(1); + } + }); + + ctrlResultSet.verify(); + ctrlStatement.verify(); + } + + public void testSQLErrorCodeTranslation() throws Exception { + final SQLException sex = new SQLException("I have a known problem", "99999", 1054); + final String sql = "SELECT ID FROM CUSTOMER"; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.getDatabaseProductName(); + ctrlDatabaseMetaData.setReturnValue("MySQL"); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + try { + template.query(sql, new RowCallbackHandler() { + public void processRow(ResultSet rs) throws SQLException { + throw sex; + } + }); + fail("Should have thrown BadSqlGrammarException"); + } + catch (BadSqlGrammarException ex) { + // expected + assertTrue("Wanted same exception back, not " + ex, sex == ex.getCause()); + } + + ctrlResultSet.verify(); + ctrlStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + + public void testSQLErrorCodeTranslationWithSpecifiedDbName() throws Exception { + final SQLException sex = new SQLException("I have a known problem", "99999", 1054); + final String sql = "SELECT ID FROM CUSTOMER"; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(); + template.setDataSource(mockDataSource); + template.setDatabaseProductName("MySQL"); + template.afterPropertiesSet(); + try { + template.query(sql, new RowCallbackHandler() { + public void processRow(ResultSet rs) throws SQLException { + throw sex; + } + }); + fail("Should have thrown BadSqlGrammarException"); + } + catch (BadSqlGrammarException ex) { + // expected + assertTrue("Wanted same exception back, not " + ex, sex == ex.getCause()); + } + + ctrlResultSet.verify(); + ctrlStatement.verify(); + } + + /** + * Test that we see an SQLException translated using Error Code. + * If we provide the SQLExceptionTranslator, we shouldn't use a connection + * to get the metadata + */ + public void testUseCustomSQLErrorCodeTranslator() throws Exception { + // Bad SQL state + final SQLException sex = new SQLException("I have a known problem", "07000", 1054); + final String sql = "SELECT ID FROM CUSTOMER"; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockStatement = (PreparedStatement) ctrlStatement.getMock(); + mockStatement.executeQuery(sql); + ctrlStatement.setReturnValue(mockResultSet); + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + // Change behaviour in setUp() because we only expect one call to getConnection(): + // none is necessary to get metadata for exception translator + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement, 1); + mockConnection.close(); + ctrlConnection.setVoidCallable(1); + ctrlConnection.replay(); + + ctrlDataSource = MockControl.createControl(DataSource.class); + mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setReturnValue(mockConnection, 1); + ctrlDataSource.replay(); + ///// end changed behaviour + + ctrlResultSet.replay(); + ctrlStatement.replay(); + + JdbcTemplate template = new JdbcTemplate(); + template.setDataSource(mockDataSource); + // Set custom exception translator + template.setExceptionTranslator(new SQLStateSQLExceptionTranslator()); + template.afterPropertiesSet(); + try { + template.query(sql, new RowCallbackHandler() { + public void processRow(ResultSet rs) + throws SQLException { + throw sex; + } + }); + fail("Should have thrown exception"); + } + catch (BadSqlGrammarException ex) { + assertTrue( + "Wanted same exception back, not " + ex, + sex == ex.getCause()); + } + + ctrlResultSet.verify(); + ctrlStatement.verify(); + + // We didn't call superclass replay() so we need to check these ourselves + ctrlDataSource.verify(); + ctrlConnection.verify(); + } + + public void testNativeJdbcExtractorInvoked() throws Exception { + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + final ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(2); + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + final Statement mockStatement = (Statement) ctrlStatement.getMock(); + if (debugEnabled) { + mockStatement.getWarnings(); + ctrlStatement.setReturnValue(null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + MockControl ctrlStatement2 = MockControl.createControl(Statement.class); + final Statement mockStatement2 = (Statement) ctrlStatement2.getMock(); + mockStatement2.executeQuery("my query"); + ctrlStatement2.setReturnValue(mockResultSet, 1); + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + final PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + MockControl ctrlPreparedStatement2 = MockControl.createControl(PreparedStatement.class); + final PreparedStatement mockPreparedStatement2 = (PreparedStatement) ctrlPreparedStatement2.getMock(); + mockPreparedStatement2.executeQuery(); + ctrlPreparedStatement2.setReturnValue(mockResultSet, 1); + + MockControl ctrlReturnResultSet = MockControl.createControl(ResultSet.class); + final ResultSet mockReturnResultSet = (ResultSet) ctrlReturnResultSet.getMock(); + mockReturnResultSet.next(); + ctrlReturnResultSet.setReturnValue(false); + mockReturnResultSet.close(); + ctrlReturnResultSet.setVoidCallable(2); + + MockControl ctrlCallableStatement = MockControl.createControl(CallableStatement.class); + final CallableStatement mockCallableStatement = (CallableStatement) ctrlCallableStatement.getMock(); + if (debugEnabled) { + mockCallableStatement.getWarnings(); + ctrlCallableStatement.setReturnValue(null); + } + mockCallableStatement.close(); + ctrlCallableStatement.setVoidCallable(); + MockControl ctrlCallableStatement2 = MockControl.createControl(CallableStatement.class); + final CallableStatement mockCallableStatement2 = (CallableStatement) ctrlCallableStatement2.getMock(); + mockCallableStatement2.execute(); + ctrlCallableStatement2.setReturnValue(true); + mockCallableStatement2.getUpdateCount(); + ctrlCallableStatement2.setReturnValue(-1); + mockCallableStatement2.getResultSet(); + ctrlCallableStatement2.setReturnValue(mockReturnResultSet); + mockCallableStatement2.getMoreResults(); + ctrlCallableStatement2.setReturnValue(false); + mockCallableStatement2.getUpdateCount(); + ctrlCallableStatement2.setReturnValue(-1); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + ctrlStatement2.replay(); + ctrlPreparedStatement.replay(); + ctrlPreparedStatement2.replay(); + ctrlReturnResultSet.replay();; + ctrlCallableStatement.replay(); + ctrlCallableStatement2.replay(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement, 1); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + template.setNativeJdbcExtractor(new NativeJdbcExtractor() { + public boolean isNativeConnectionNecessaryForNativeStatements() { + return false; + } + public boolean isNativeConnectionNecessaryForNativePreparedStatements() { + return false; + } + public boolean isNativeConnectionNecessaryForNativeCallableStatements() { + return false; + } + public Connection getNativeConnection(Connection con) { + return con; + } + public Connection getNativeConnectionFromStatement(Statement stmt) throws SQLException { + return stmt.getConnection(); + } + public Statement getNativeStatement(Statement stmt) { + assertTrue(stmt == mockStatement); + return mockStatement2; + } + public PreparedStatement getNativePreparedStatement(PreparedStatement ps) { + assertTrue(ps == mockPreparedStatement); + return mockPreparedStatement2; + } + public CallableStatement getNativeCallableStatement(CallableStatement cs) { + assertTrue(cs == mockCallableStatement); + return mockCallableStatement2; + } + public ResultSet getNativeResultSet(ResultSet rs) { + return rs; + } + }); + + template.query("my query", new ResultSetExtractor() { + public Object extractData(ResultSet rs2) { + assertEquals(mockResultSet, rs2); + return null; + } + }); + + template.query(new PreparedStatementCreator() { + public PreparedStatement createPreparedStatement(Connection conn) { + return mockPreparedStatement; + } + }, new ResultSetExtractor() { + public Object extractData(ResultSet rs2) { + assertEquals(mockResultSet, rs2); + return null; + } + }); + + template.call(new CallableStatementCreator() { + public CallableStatement createCallableStatement(Connection con) { + return mockCallableStatement; + } + }, + new ArrayList()); + + ctrlStatement.verify(); + ctrlStatement2.verify(); + ctrlPreparedStatement.verify(); + ctrlPreparedStatement2.verify(); + ctrlCallableStatement.verify(); + ctrlCallableStatement2.verify(); + } + + public void testStaticResultSetClosed() throws Exception { + MockControl ctrlResultSet; + ResultSet mockResultSet; + MockControl ctrlStatement; + Statement mockStatement; + MockControl ctrlResultSet2; + ResultSet mockResultSet2; + MockControl ctrlPreparedStatement; + PreparedStatement mockPreparedStatement; + + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + ctrlStatement = MockControl.createControl(Statement.class); + mockStatement = (Statement) ctrlStatement.getMock(); + mockStatement.executeQuery("my query"); + ctrlStatement.setReturnValue(mockResultSet); + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + ctrlResultSet2 = MockControl.createControl(ResultSet.class); + mockResultSet2 = (ResultSet) ctrlResultSet2.getMock(); + mockResultSet2.close(); + ctrlResultSet2.setVoidCallable(); + + ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet2); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + mockConnection.prepareStatement("my query"); + ctrlConnection.setReturnValue(mockPreparedStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + ctrlResultSet2.replay(); + ctrlPreparedStatement.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + + try { + template.query("my query", new ResultSetExtractor() { + public Object extractData(ResultSet rs) { + throw new InvalidDataAccessApiUsageException(""); + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // ok + } + + try { + template.query(new PreparedStatementCreator() { + public PreparedStatement createPreparedStatement(Connection con) throws SQLException { + return con.prepareStatement("my query"); + } + public String getSql() { + return null; + } + }, new ResultSetExtractor() { + public Object extractData(ResultSet rs2) { + throw new InvalidDataAccessApiUsageException(""); + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // ok + } + + // verify confirms if test is successful by checking if close() called + ctrlResultSet.verify(); + ctrlStatement.verify(); + ctrlResultSet2.verify(); + ctrlPreparedStatement.verify(); + } + + public void testExecuteClosed() throws Exception { + MockControl ctrlResultSet; + ResultSet mockResultSet; + MockControl ctrlCallable; + CallableStatement mockCallable; + + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + ctrlCallable = MockControl.createControl(CallableStatement.class); + mockCallable = (CallableStatement) ctrlCallable.getMock(); + mockCallable.execute(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getResultSet(); + ctrlCallable.setReturnValue(mockResultSet); + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("my query"); + ctrlConnection.setReturnValue(mockCallable); + + ctrlResultSet.replay(); + ctrlCallable.replay(); + replay(); + + List params = new ArrayList(); + params.add(new SqlReturnResultSet("", new RowCallbackHandler() { + public void processRow(ResultSet rs) { + throw new InvalidDataAccessApiUsageException(""); + } + + })); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + try { + template.call(new CallableStatementCreator() { + public CallableStatement createCallableStatement(Connection conn) + throws SQLException { + return conn.prepareCall("my query"); + } + }, params); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // ok + } + + // verify confirms if test is successful by checking if close() called + ctrlResultSet.verify(); + ctrlCallable.verify(); + } + + public void testCaseInsensitiveResultsMap() throws Exception { + + MockControl ctrlCallable; + CallableStatement mockCallable; + + ctrlCallable = MockControl.createControl(CallableStatement.class); + mockCallable = (CallableStatement) ctrlCallable.getMock(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(1); + ctrlCallable.setReturnValue("X"); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("my query"); + ctrlConnection.setReturnValue(mockCallable); + + ctrlCallable.replay(); + replay(); + + JdbcTemplate template = new JdbcTemplate(mockDataSource); + assertTrue("default should have been NOT case insensitive", !template.isResultsMapCaseInsensitive()); + + template.setResultsMapCaseInsensitive(true); + assertTrue("now it should have been set to case insensitive", template.isResultsMapCaseInsensitive()); + + List params = new ArrayList(); + params.add(new SqlOutParameter("a", 12)); + + Map out = template.call(new CallableStatementCreator() { + public CallableStatement createCallableStatement(Connection conn) + throws SQLException { + return conn.prepareCall("my query"); + } + }, params); + assertTrue("this should have been an Apache Commons Collections class", + out.getClass().getName().startsWith("org.apache.commons.collections.map")); + assertNotNull("we should have gotten the result with upper case", out.get("A")); + assertNotNull("we should have gotten the result with lower case", out.get("a")); + + ctrlCallable.verify(); + } + + + private static class PlainNativeJdbcExtractor extends NativeJdbcExtractorAdapter { + + protected Connection doGetNativeConnection(Connection con) throws SQLException { + return con; + } + } + + + private static interface JdbcTemplateCallback { + + void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch); + } + + + private static class Dispatcher implements PreparedStatementCreator, SqlProvider { + + private int id; + private String sql; + + public Dispatcher(int id, String sql) { + this.id = id; + this.sql = sql; + } + + public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { + PreparedStatement ps = conn.prepareStatement(sql); + ps.setInt(1, id); + return ps; + } + + public String getSql() { + return sql; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/RowMapperTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/RowMapperTests.java new file mode 100644 index 00000000000..bd992919cb2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/RowMapperTests.java @@ -0,0 +1,248 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.List; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.TestBean; +import org.springframework.jdbc.datasource.SingleConnectionDataSource; +import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; + +/** + * @author Juergen Hoeller + * @since 02.08.2004 + */ +public class RowMapperTests extends TestCase { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl conControl; + private Connection con; + private MockControl rsControl; + private ResultSet rs; + private JdbcTemplate jdbcTemplate; + private List result; + + protected void setUp() throws SQLException { + conControl = MockControl.createControl(Connection.class); + con = (Connection) conControl.getMock(); + con.isClosed(); + conControl.setDefaultReturnValue(false); + + rsControl = MockControl.createControl(ResultSet.class); + rs = (ResultSet) rsControl.getMock(); + rs.next(); + rsControl.setReturnValue(true, 1); + rs.getString(1); + rsControl.setReturnValue("tb1", 1); + rs.getInt(2); + rsControl.setReturnValue(1, 1); + rs.next(); + rsControl.setReturnValue(true, 1); + rs.getString(1); + rsControl.setReturnValue("tb2", 1); + rs.getInt(2); + rsControl.setReturnValue(2, 1); + rs.next(); + rsControl.setReturnValue(false, 1); + rs.close(); + rsControl.setVoidCallable(1); + rsControl.replay(); + + jdbcTemplate = new JdbcTemplate(); + jdbcTemplate.setDataSource(new SingleConnectionDataSource(con, false)); + jdbcTemplate.setExceptionTranslator(new SQLStateSQLExceptionTranslator()); + jdbcTemplate.afterPropertiesSet(); + } + + public void testStaticQueryWithRowMapper() throws SQLException { + MockControl stmtControl = MockControl.createControl(Statement.class); + Statement stmt = (Statement) stmtControl.getMock(); + + con.createStatement(); + conControl.setReturnValue(stmt, 1); + stmt.executeQuery("some SQL"); + stmtControl.setReturnValue(rs, 1); + if (debugEnabled) { + stmt.getWarnings(); + stmtControl.setReturnValue(null, 1); + } + stmt.close(); + stmtControl.setVoidCallable(1); + + conControl.replay(); + stmtControl.replay(); + + result = jdbcTemplate.query("some SQL", new TestRowMapper()); + + stmtControl.verify(); + verify(); + } + + public void testPreparedStatementCreatorWithRowMapper() throws SQLException { + MockControl psControl = MockControl.createControl(PreparedStatement.class); + final PreparedStatement ps = (PreparedStatement) psControl.getMock(); + + ps.executeQuery(); + psControl.setReturnValue(rs, 1); + if (debugEnabled) { + ps.getWarnings(); + psControl.setReturnValue(null, 1); + } + ps.close(); + psControl.setVoidCallable(1); + + conControl.replay(); + psControl.replay(); + + result = jdbcTemplate.query( + new PreparedStatementCreator() { + public PreparedStatement createPreparedStatement(Connection con) throws SQLException { + return ps; + } + }, new TestRowMapper()); + + psControl.verify(); + verify(); + } + + public void testPreparedStatementSetterWithRowMapper() throws SQLException { + MockControl psControl = MockControl.createControl(PreparedStatement.class); + final PreparedStatement ps = (PreparedStatement) psControl.getMock(); + + con.prepareStatement("some SQL"); + conControl.setReturnValue(ps, 1); + ps.setString(1, "test"); + psControl.setVoidCallable(1); + ps.executeQuery(); + psControl.setReturnValue(rs, 1); + if (debugEnabled) { + ps.getWarnings(); + psControl.setReturnValue(null, 1); + } + ps.close(); + psControl.setVoidCallable(1); + + conControl.replay(); + psControl.replay(); + + result = jdbcTemplate.query( + "some SQL", + new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) throws SQLException { + ps.setString(1, "test"); + } + }, new TestRowMapper()); + + psControl.verify(); + verify(); + } + + public void testQueryWithArgsAndRowMapper() throws SQLException { + MockControl psControl = MockControl.createControl(PreparedStatement.class); + final PreparedStatement ps = (PreparedStatement) psControl.getMock(); + + con.prepareStatement("some SQL"); + conControl.setReturnValue(ps, 1); + ps.setString(1, "test1"); + ps.setString(2, "test2"); + psControl.setVoidCallable(1); + ps.executeQuery(); + psControl.setReturnValue(rs, 1); + if (debugEnabled) { + ps.getWarnings(); + psControl.setReturnValue(null, 1); + } + ps.close(); + psControl.setVoidCallable(1); + + conControl.replay(); + psControl.replay(); + + result = jdbcTemplate.query( + "some SQL", + new Object[] {"test1", "test2"}, + new TestRowMapper()); + + psControl.verify(); + verify(); + } + + public void testQueryWithArgsAndTypesAndRowMapper() throws SQLException { + MockControl psControl = MockControl.createControl(PreparedStatement.class); + final PreparedStatement ps = (PreparedStatement) psControl.getMock(); + + con.prepareStatement("some SQL"); + conControl.setReturnValue(ps, 1); + ps.setString(1, "test1"); + ps.setString(2, "test2"); + psControl.setVoidCallable(1); + ps.executeQuery(); + psControl.setReturnValue(rs, 1); + if (debugEnabled) { + ps.getWarnings(); + psControl.setReturnValue(null, 1); + } + ps.close(); + psControl.setVoidCallable(1); + + conControl.replay(); + psControl.replay(); + + result = jdbcTemplate.query( + "some SQL", + new Object[] {"test1", "test2"}, + new int[] {Types.VARCHAR, Types.VARCHAR}, + new TestRowMapper()); + + psControl.verify(); + verify(); + } + + protected void verify() { + conControl.verify(); + rsControl.verify(); + + assertTrue(result != null); + assertEquals(2, result.size()); + TestBean tb1 = (TestBean) result.get(0); + TestBean tb2 = (TestBean) result.get(1); + assertEquals("tb1", tb1.getName()); + assertEquals(1, tb1.getAge()); + assertEquals("tb2", tb2.getName()); + assertEquals(2, tb2.getAge()); + } + + + private static class TestRowMapper implements RowMapper { + + public Object mapRow(ResultSet rs, int rowNum) throws SQLException { + return new TestBean(rs.getString(1), rs.getInt(2)); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/SimpleRowCountCallbackHandler.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/SimpleRowCountCallbackHandler.java new file mode 100644 index 00000000000..ae4d9737026 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/SimpleRowCountCallbackHandler.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Simple row count callback handler for testing purposes. + * Does not call any JDBC methods on the given ResultSet. + * + * @author Juergen Hoeller + * @since 2.0 + */ +public class SimpleRowCountCallbackHandler implements RowCallbackHandler { + + private int count; + + + public void processRow(ResultSet rs) throws SQLException { + count++; + } + + public int getCount() { + return count; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/StatementCreatorUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/StatementCreatorUtilsTests.java new file mode 100644 index 00000000000..17292869391 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/StatementCreatorUtilsTests.java @@ -0,0 +1,223 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; +import java.util.GregorianCalendar; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +/** + * @author Juergen Hoeller + * @since 31.08.2004 + */ +public class StatementCreatorUtilsTests extends TestCase { + + private MockControl psControl; + private PreparedStatement ps; + + protected void setUp() { + psControl = MockControl.createControl(PreparedStatement.class); + ps = (PreparedStatement) psControl.getMock(); + } + + protected void tearDown() { + psControl.verify(); + } + + public void testSetParameterValueWithNullAndType() throws SQLException { + ps.setNull(1, Types.VARCHAR); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.VARCHAR, null, null); + } + + public void testSetParameterValueWithNullAndTypeName() throws SQLException { + ps.setNull(1, Types.VARCHAR, "mytype"); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.VARCHAR, "mytype", null); + } + + public void testSetParameterValueWithNullAndUnknownType() throws SQLException { + ps.setNull(1, Types.NULL); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, SqlTypeValue.TYPE_UNKNOWN, null, null); + } + + public void testSetParameterValueWithNullAndUnknownTypeOnInformix() throws SQLException { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl metaDataControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData metaData = (DatabaseMetaData) metaDataControl.getMock(); + ps.getConnection(); + psControl.setReturnValue(con, 1); + con.getMetaData(); + conControl.setReturnValue(metaData, 1); + metaData.getDatabaseProductName(); + metaDataControl.setReturnValue("Informix Dynamic Server"); + metaData.getDriverName(); + metaDataControl.setReturnValue("Informix Driver"); + ps.setObject(1, null); + psControl.setVoidCallable(1); + psControl.replay(); + conControl.replay(); + metaDataControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, SqlTypeValue.TYPE_UNKNOWN, null, null); + conControl.verify(); + metaDataControl.verify(); + } + + public void testSetParameterValueWithNullAndUnknownTypeOnDerbyEmbedded() throws SQLException { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl metaDataControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData metaData = (DatabaseMetaData) metaDataControl.getMock(); + ps.getConnection(); + psControl.setReturnValue(con, 1); + con.getMetaData(); + conControl.setReturnValue(metaData, 1); + metaData.getDatabaseProductName(); + metaDataControl.setReturnValue("Apache Derby"); + metaData.getDriverName(); + metaDataControl.setReturnValue("Apache Derby Embedded Driver"); + ps.setNull(1, Types.VARCHAR); + psControl.setVoidCallable(1); + psControl.replay(); + conControl.replay(); + metaDataControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, SqlTypeValue.TYPE_UNKNOWN, null, null); + conControl.verify(); + metaDataControl.verify(); + } + + public void testSetParameterValueWithString() throws SQLException { + ps.setString(1, "test"); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.VARCHAR, null, "test"); + } + + public void testSetParameterValueWithStringAndSpecialType() throws SQLException { + ps.setObject(1, "test", Types.CHAR); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.CHAR, null, "test"); + } + + public void testSetParameterValueWithStringAndUnknownType() throws SQLException { + ps.setString(1, "test"); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, SqlTypeValue.TYPE_UNKNOWN, null, "test"); + } + + public void testSetParameterValueWithSqlDate() throws SQLException { + java.sql.Date date = new java.sql.Date(1000); + ps.setDate(1, date); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.DATE, null, date); + } + + public void testSetParameterValueWithDateAndUtilDate() throws SQLException { + java.util.Date date = new java.util.Date(1000); + ps.setDate(1, new java.sql.Date(1000)); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.DATE, null, date); + } + + public void testSetParameterValueWithDateAndCalendar() throws SQLException { + java.util.Calendar cal = new GregorianCalendar(); + ps.setDate(1, new java.sql.Date(cal.getTime().getTime()), cal); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.DATE, null, cal); + } + + public void testSetParameterValueWithSqlTime() throws SQLException { + java.sql.Time time = new java.sql.Time(1000); + ps.setTime(1, time); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.TIME, null, time); + } + + public void testSetParameterValueWithTimeAndUtilDate() throws SQLException { + java.util.Date date = new java.util.Date(1000); + ps.setTime(1, new java.sql.Time(1000)); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.TIME, null, date); + } + + public void testSetParameterValueWithTimeAndCalendar() throws SQLException { + java.util.Calendar cal = new GregorianCalendar(); + ps.setTime(1, new java.sql.Time(cal.getTime().getTime()), cal); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.TIME, null, cal); + } + + public void testSetParameterValueWithSqlTimestamp() throws SQLException { + java.sql.Timestamp timestamp = new java.sql.Timestamp(1000); + ps.setTimestamp(1, timestamp); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.TIMESTAMP, null, timestamp); + } + + public void testSetParameterValueWithTimestampAndUtilDate() throws SQLException { + java.util.Date date = new java.util.Date(1000); + ps.setTimestamp(1, new java.sql.Timestamp(1000)); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.TIMESTAMP, null, date); + } + + public void testSetParameterValueWithTimestampAndCalendar() throws SQLException { + java.util.Calendar cal = new GregorianCalendar(); + ps.setTimestamp(1, new java.sql.Timestamp(cal.getTime().getTime()), cal); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, Types.TIMESTAMP, null, cal); + } + + public void testSetParameterValueWithDateAndUnknownType() throws SQLException { + java.util.Date date = new java.util.Date(1000); + ps.setTimestamp(1, new java.sql.Timestamp(1000)); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, SqlTypeValue.TYPE_UNKNOWN, null, date); + } + + public void testSetParameterValueWithCalendarAndUnknownType() throws SQLException { + java.util.Calendar cal = new GregorianCalendar(); + ps.setTimestamp(1, new java.sql.Timestamp(cal.getTime().getTime()), cal); + psControl.setVoidCallable(1); + psControl.replay(); + StatementCreatorUtils.setParameterValue(ps, 1, SqlTypeValue.TYPE_UNKNOWN, null, cal); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSourceTests.java new file mode 100644 index 00000000000..d5644769793 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSourceTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.namedparam; + +import java.sql.Types; +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class BeanPropertySqlParameterSourceTests extends TestCase { + + public void testWithNullBeanPassedToCtor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new BeanPropertySqlParameterSource(null); + } + }.runTest(); + } + + public void testGetValueWhereTheUnderlyingBeanHasNoSuchProperty() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + BeanPropertySqlParameterSource source = new BeanPropertySqlParameterSource(new TestBean()); + source.getValue("thisPropertyDoesNotExist"); + } + }.runTest(); + } + + public void testSuccessfulPropertyAccess(){ + BeanPropertySqlParameterSource source = new BeanPropertySqlParameterSource(new TestBean("tb", 99)); + assertTrue(Arrays.asList(source.getReadablePropertyNames()).contains("name")); + assertTrue(Arrays.asList(source.getReadablePropertyNames()).contains("age")); + assertEquals("tb", source.getValue("name")); + assertEquals(new Integer(99), source.getValue("age")); + assertEquals(Types.VARCHAR, source.getSqlType("name")); + assertEquals(Types.INTEGER, source.getSqlType("age")); + } + + public void testSuccessfulPropertyAccessWithOverriddenSqlType(){ + BeanPropertySqlParameterSource source = new BeanPropertySqlParameterSource(new TestBean("tb", 99)); + source.registerSqlType("age", Types.NUMERIC); + assertEquals("tb", source.getValue("name")); + assertEquals(new Integer(99), source.getValue("age")); + assertEquals(Types.VARCHAR, source.getSqlType("name")); + assertEquals(Types.NUMERIC, source.getSqlType("age")); + } + + public void testHasValueWhereTheUnderlyingBeanHasNoSuchProperty() throws Exception { + BeanPropertySqlParameterSource source = new BeanPropertySqlParameterSource(new TestBean()); + assertFalse(source.hasValue("thisPropertyDoesNotExist")); + } + + public void testGetValueWhereTheUnderlyingBeanPropertyIsNotReadable() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + BeanPropertySqlParameterSource source = new BeanPropertySqlParameterSource(new NoReadableProperties()); + source.getValue("noOp"); + } + }.runTest(); + } + + public void testHasValueWhereTheUnderlyingBeanPropertyIsNotReadable() throws Exception { + BeanPropertySqlParameterSource source = new BeanPropertySqlParameterSource(new NoReadableProperties()); + assertFalse(source.hasValue("noOp")); + } + + + private static final class NoReadableProperties { + + public void setNoOp(String noOp) { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/MapSqlParameterSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/MapSqlParameterSourceTests.java new file mode 100644 index 00000000000..707c20447ef --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/MapSqlParameterSourceTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.namedparam; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; +import org.springframework.jdbc.core.SqlParameterValue; + +/** + * @author Rick Evans + */ +public final class MapSqlParameterSourceTests extends TestCase { + + public void testNullParameterValuesPassedToCtorIsOk() throws Exception { + new MapSqlParameterSource(null); + } + + public void testGetValueChokesIfParameterIsNotPresent() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MapSqlParameterSource source = new MapSqlParameterSource(); + source.getValue("pechorin was right!"); + } + }.runTest(); + } + + public void testSqlParameterValueRegistersSqlType() throws Exception { + MapSqlParameterSource msps = new MapSqlParameterSource("FOO", new SqlParameterValue(2, "Foo")); + assertEquals("Correct SQL Type not registered", 2, msps.getSqlType("FOO")); + MapSqlParameterSource msps2 = new MapSqlParameterSource(); + msps2.addValues(msps.getValues()); + assertEquals("Correct SQL Type not registered", 2, msps2.getSqlType("FOO")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java new file mode 100644 index 00000000000..b2b6f0f73d4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java @@ -0,0 +1,415 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.namedparam; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.Customer; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.PreparedStatementCallback; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.jdbc.core.RowCallbackHandler; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.SqlParameterValue; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class NamedParameterJdbcTemplateTests extends AbstractJdbcTests { + + private static final String SELECT_NAMED_PARAMETERS = + "select id, forename from custmr where id = :id and country = :country"; + private static final String SELECT_NAMED_PARAMETERS_PARSED = + "select id, forename from custmr where id = ? and country = ?"; + + private static final String UPDATE_NAMED_PARAMETERS = + "update seat_status set booking_id = null where performance_id = :perfId and price_band_id = :priceId"; + private static final String UPDATE_NAMED_PARAMETERS_PARSED = + "update seat_status set booking_id = null where performance_id = ? and price_band_id = ?"; + + private static final String[] COLUMN_NAMES = new String[] {"id", "forename"}; + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl ctrlPreparedStatement; + private PreparedStatement mockPreparedStatement; + private MockControl ctrlResultSet; + private ResultSet mockResultSet; + + protected void setUp() throws Exception { + super.setUp(); + ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (shouldVerify()) { + ctrlPreparedStatement.verify(); + ctrlResultSet.verify(); + } + } + + protected void replay() { + super.replay(); + ctrlPreparedStatement.replay(); + ctrlResultSet.replay(); + } + + + public void testNullDataSourceProvidedToCtor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new NamedParameterJdbcTemplate((DataSource) null); + } + }.runTest(); + } + + public void testNullJdbcTemplateProvidedToCtor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new NamedParameterJdbcTemplate((JdbcOperations) null); + } + }.runTest(); + } + + public void testExecute() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(1)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("perfId", new Integer(1)); + params.put("priceId", new Integer(1)); + assertEquals("result", jt.execute(UPDATE_NAMED_PARAMETERS, params, new PreparedStatementCallback() { + public Object doInPreparedStatement(PreparedStatement ps) throws SQLException { + assertEquals(mockPreparedStatement, ps); + ps.executeUpdate(); + return "result"; + } + })); + } + + public void testExecuteWithTypedParameters() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1), Types.DECIMAL); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(1), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("perfId", new SqlParameterValue(Types.DECIMAL, new Integer(1))); + params.put("priceId", new SqlParameterValue(Types.INTEGER, new Integer(1))); + assertEquals("result", jt.execute(UPDATE_NAMED_PARAMETERS, params, new PreparedStatementCallback() { + public Object doInPreparedStatement(PreparedStatement ps) throws SQLException { + assertEquals(mockPreparedStatement, ps); + ps.executeUpdate(); + return "result"; + } + })); + } + + public void testUpdate() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(1)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("perfId", new Integer(1)); + params.put("priceId", new Integer(1)); + int rowsAffected = jt.update(UPDATE_NAMED_PARAMETERS, params); + assertEquals(1, rowsAffected); + } + + public void testUpdateWithTypedParameters() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1), Types.DECIMAL); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(1), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("perfId", new SqlParameterValue(Types.DECIMAL, new Integer(1))); + params.put("priceId", new SqlParameterValue(Types.INTEGER, new Integer(1))); + int rowsAffected = jt.update(UPDATE_NAMED_PARAMETERS, params); + assertEquals(1, rowsAffected); + } + + public void testQueryWithResultSetExtractor() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.DECIMAL); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "UK"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("id", new SqlParameterValue(Types.DECIMAL, new Integer(1))); + params.put("country", "UK"); + Customer cust = (Customer) jt.query(SELECT_NAMED_PARAMETERS, params, new ResultSetExtractor() { + public Object extractData(ResultSet rs) throws SQLException, DataAccessException { + rs.next(); + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + }); + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); + } + + public void testQueryWithRowCallbackHandler() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.DECIMAL); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "UK"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("id", new SqlParameterValue(Types.DECIMAL, new Integer(1))); + params.put("country", "UK"); + final List customers = new LinkedList(); + jt.query(SELECT_NAMED_PARAMETERS, params, new RowCallbackHandler() { + public void processRow(ResultSet rs) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + customers.add(cust); + } + }); + assertEquals(1, customers.size()); + Customer cust = (Customer) customers.get(0); + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); + } + + public void testQueryWithRowMapper() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.DECIMAL); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "UK"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("id", new SqlParameterValue(Types.DECIMAL, new Integer(1))); + params.put("country", "UK"); + List customers = jt.query(SELECT_NAMED_PARAMETERS, params, new RowMapper() { + public Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + }); + assertEquals(1, customers.size()); + Customer cust = (Customer) customers.get(0); + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); + } + + public void testQueryForObjectWithRowMapper() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.DECIMAL); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "UK"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_NAMED_PARAMETERS_PARSED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(mockDataSource); + Map params = new HashMap(); + params.put("id", new SqlParameterValue(Types.DECIMAL, new Integer(1))); + params.put("country", "UK"); + Customer cust = (Customer) jt.queryForObject(SELECT_NAMED_PARAMETERS, params, new RowMapper() { + public Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + }); + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterQueryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterQueryTests.java new file mode 100644 index 00000000000..67dadc84a2a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterQueryTests.java @@ -0,0 +1,608 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.namedparam; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.easymock.MockControl; + +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.core.RowMapper; + +/** + * @author Thomas Risberg + */ +public class NamedParameterQueryTests extends AbstractJdbcTests { + + private MockControl ctrlPreparedStatement; + private PreparedStatement mockPreparedStatement; + private MockControl ctrlResultSet; + private ResultSet mockResultSet; + private MockControl ctrlResultSetMetaData; + private ResultSetMetaData mockResultSetMetaData; + + protected void setUp() throws Exception { + super.setUp(); + ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + } + + protected void replay() { + super.replay(); + ctrlPreparedStatement.replay(); + ctrlResultSet.replay(); + ctrlResultSetMetaData.replay(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (false && shouldVerify()) { + ctrlPreparedStatement.verify(); + ctrlResultSet.verify(); + ctrlResultSetMetaData.verify(); + } + } + + public void testQueryForListWithParamMap() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1, 2); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 2); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 2); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(12)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + List li = template.queryForList(sql, parms); + assertEquals("All rows returned", 2, li.size()); + assertEquals("First row is Integer", 11, ((Integer)((Map)li.get(0)).get("age")).intValue()); + assertEquals("Second row is Integer", 12, ((Integer)((Map)li.get(1)).get("age")).intValue()); + } + + public void testQueryForListWithParamMapAndEmptyResult() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + List li = template.queryForList(sql, parms); + assertEquals("All rows returned", 0, li.size()); + } + + public void testQueryForListWithParamMapAndSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + List li = template.queryForList(sql, parms); + assertEquals("All rows returned", 1, li.size()); + assertEquals("First row is Integer", 11, ((Integer)((Map)li.get(0)).get("age")).intValue()); + } + + public void testQueryForListWithParamMapAndIntegerElementAndSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(11); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + List li = template.queryForList(sql, parms, Integer.class); + assertEquals("All rows returned", 1, li.size()); + assertEquals("First row is Integer", 11, ((Integer) li.get(0)).intValue()); + } + + public void testQueryForMapWithParamMapAndSingleRowAndColumn() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID < :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID < ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("age", 1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + Map map = template.queryForMap(sql, parms); + assertEquals("Row is Integer", 11, ((Integer) map.get("age")).intValue()); + } + + public void testQueryForObjectWithParamMapAndRowMapper() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + Object o = template.queryForObject(sql, parms, new RowMapper() { + public Object mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Integer(rs.getInt(1)); + } + }); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForObjectWithMapAndInteger() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + Map parms = new HashMap(); + parms.put("id", new Integer(3)); + + Object o = template.queryForObject(sql, parms, Integer.class); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForObjectWithParamMapAndInteger() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + Object o = template.queryForObject(sql, parms, Integer.class); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForObjectWithParamMapAndList() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID IN (:ids)"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID IN (?, ?)"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(4)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("ids", Arrays.asList(new Object[] {new Integer(3), new Integer(4)})); + + Object o = template.queryForObject(sql, parms, Integer.class); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForObjectWithParamMapAndListOfExpressionLists() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE (ID, NAME) IN (:multiExpressionList)"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE (ID, NAME) IN ((?, ?), (?, ?))"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(22); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "Rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(3, new Integer(4)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(4, "Juergen"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + List l1 = new ArrayList(); + l1.add(new Object[] {new Integer(3), "Rod"}); + l1.add(new Object[] {new Integer(4), "Juergen"}); + parms.addValue("multiExpressionList", l1); + + Object o = template.queryForObject(sql, parms, Integer.class); + assertTrue("Correct result type", o instanceof Integer); + } + + public void testQueryForIntWithParamMap() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getDouble(1); + ctrlResultSet.setReturnValue(22.0d); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3)); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + + MapSqlParameterSource parms = new MapSqlParameterSource(); + parms.addValue("id", new Integer(3)); + + int i = template.queryForInt(sql, parms); + assertEquals("Return of an int", 22, i); + } + + public void testQueryForLongWithParamBean() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = :id"; + String sqlToUse = "SELECT AGE FROM CUSTMR WHERE ID = ?"; + + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getDouble(1); + ctrlResultSet.setReturnValue(87.0d); + mockResultSet.wasNull(); + ctrlResultSet.setReturnValue(false); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(3), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(sqlToUse); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(mockDataSource); + BeanPropertySqlParameterSource parms = new BeanPropertySqlParameterSource(new ParameterBean(3)); + + long l = template.queryForLong(sql, parms); + assertEquals("Return of a long", 87, l); + } + + + private static class ParameterBean { + + private int id; + + public ParameterBean(int id) { + this.id = id; + } + + public int getId() { + return id; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java new file mode 100644 index 00000000000..ccecc08a64e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java @@ -0,0 +1,189 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.namedparam; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.test.AssertThrows; + +/** + * @author Thomas Risberg + * @author Juergen Hoeller + * @author Rick Evans + */ +public class NamedParameterUtilsTests extends TestCase { + + public void testParseSql() { + String sql = "xxx :a yyyy :b :c :a zzzzz"; + ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); + assertEquals("xxx ? yyyy ? ? ? zzzzz", NamedParameterUtils.substituteNamedParameters(psql, null)); + assertEquals("a", psql.getParameterNames().get(0)); + assertEquals("c", psql.getParameterNames().get(2)); + assertEquals("a", psql.getParameterNames().get(3)); + assertEquals(4, psql.getTotalParameterCount()); + assertEquals(3, psql.getNamedParameterCount()); + + String sql2 = "xxx &a yyyy ? zzzzz"; + ParsedSql psql2 = NamedParameterUtils.parseSqlStatement(sql2); + assertEquals("xxx ? yyyy ? zzzzz", NamedParameterUtils.substituteNamedParameters(psql2, null)); + assertEquals("a", psql2.getParameterNames().get(0)); + assertEquals(2, psql2.getTotalParameterCount()); + assertEquals(1, psql2.getNamedParameterCount()); + + String sql3 = "xxx &a+:b" + '\t' + ":c%10 yyyy ? zzzzz"; + ParsedSql psql3 = NamedParameterUtils.parseSqlStatement(sql3); + assertEquals("a", psql3.getParameterNames().get(0)); + assertEquals("b", psql3.getParameterNames().get(1)); + assertEquals("c", psql3.getParameterNames().get(2)); + + } + + public void testSubstituteNamedParameters() { + MapSqlParameterSource namedParams = new MapSqlParameterSource(); + namedParams.addValue("a", "a").addValue("b", "b").addValue("c", "c"); + assertEquals("xxx ? ? ?", NamedParameterUtils.substituteNamedParameters("xxx :a :b :c", namedParams)); + assertEquals("xxx ? ? ? xx ? ?", NamedParameterUtils.substituteNamedParameters("xxx :a :b :c xx :a :a", namedParams)); + } + + public void testConvertParamMapToArray() { + Map paramMap = new HashMap(); + paramMap.put("a", "a"); + paramMap.put("b", "b"); + paramMap.put("c", "c"); + assertTrue(3 == NamedParameterUtils.buildValueArray("xxx :a :b :c", paramMap).length); + assertTrue(5 == NamedParameterUtils.buildValueArray("xxx :a :b :c xx :a :b", paramMap).length); + assertTrue(5 == NamedParameterUtils.buildValueArray("xxx :a :a :a xx :a :a", paramMap).length); + assertEquals("b", NamedParameterUtils.buildValueArray("xxx :a :b :c xx :a :b", paramMap)[4]); + try { + NamedParameterUtils.buildValueArray("xxx :a :b ?", paramMap); + fail("mixed named parameters and ? placeholders not detected"); + } + catch (InvalidDataAccessApiUsageException expected) { + } + } + + public void testConvertTypeMapToArray() { + MapSqlParameterSource namedParams = new MapSqlParameterSource(); + namedParams.addValue("a", "a", 1).addValue("b", "b", 2).addValue("c", "c", 3); + assertTrue(3 == NamedParameterUtils.buildSqlTypeArray(NamedParameterUtils.parseSqlStatement("xxx :a :b :c"), namedParams).length); + assertTrue(5 == NamedParameterUtils.buildSqlTypeArray(NamedParameterUtils.parseSqlStatement("xxx :a :b :c xx :a :b"), namedParams).length); + assertTrue(5 == NamedParameterUtils.buildSqlTypeArray(NamedParameterUtils.parseSqlStatement("xxx :a :a :a xx :a :a"), namedParams).length); + assertEquals(2, NamedParameterUtils.buildSqlTypeArray(NamedParameterUtils.parseSqlStatement("xxx :a :b :c xx :a :b"), namedParams)[4]); + } + + public void testBuildValueArrayWithMissingParameterValue() throws Exception { + new AssertThrows(InvalidDataAccessApiUsageException.class) { + public void test() throws Exception { + String sql = "select count(0) from foo where id = :id"; + NamedParameterUtils.buildValueArray(sql, new HashMap()); + } + }.runTest(); + } + + public void testSubstituteNamedParametersWithStringContainingQuotes() throws Exception { + String expectedSql = "select 'first name' from artists where id = ? and quote = 'exsqueeze me?'"; + String sql = "select 'first name' from artists where id = :id and quote = 'exsqueeze me?'"; + String newSql = NamedParameterUtils.substituteNamedParameters(sql, new MapSqlParameterSource()); + assertEquals(expectedSql, newSql); + } + + public void testParseSqlStatementWithStringContainingQuotes() throws Exception { + String expectedSql = "select 'first name' from artists where id = ? and quote = 'exsqueeze me?'"; + String sql = "select 'first name' from artists where id = :id and quote = 'exsqueeze me?'"; + ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); + assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null)); + } + + /* + * SPR-4789 + */ + public void testParseSqlContainingComments() { + String sql1 = "/*+ HINT */ xxx /* comment ? */ :a yyyy :b :c :a zzzzz -- :xx XX\n"; + ParsedSql psql1 = NamedParameterUtils.parseSqlStatement(sql1); + assertEquals("/*+ HINT */ xxx /* comment ? */ ? yyyy ? ? ? zzzzz -- :xx XX\n", + NamedParameterUtils.substituteNamedParameters(psql1, null)); + MapSqlParameterSource paramMap = new MapSqlParameterSource(); + paramMap.addValue("a", "a"); + paramMap.addValue("b", "b"); + paramMap.addValue("c", "c"); + Object[] params = NamedParameterUtils.buildValueArray(psql1, paramMap, null); + assertEquals(4, params.length); + assertEquals("a", params[0]); + assertEquals("b", params[1]); + assertEquals("c", params[2]); + assertEquals("a", params[3]); + + String sql2 = "/*+ HINT */ xxx /* comment ? */ :a yyyy :b :c :a zzzzz -- :xx XX"; + ParsedSql psql2 = NamedParameterUtils.parseSqlStatement(sql2); + assertEquals("/*+ HINT */ xxx /* comment ? */ ? yyyy ? ? ? zzzzz -- :xx XX", + NamedParameterUtils.substituteNamedParameters(psql2, null)); + + String sql3 = "/*+ HINT */ xxx /* comment ? */ :a yyyy :b :c :a zzzzz /* :xx XX*"; + ParsedSql psql3 = NamedParameterUtils.parseSqlStatement(sql3); + assertEquals("/*+ HINT */ xxx /* comment ? */ ? yyyy ? ? ? zzzzz /* :xx XX*", + NamedParameterUtils.substituteNamedParameters(psql3, null)); + + String sql4 = "/*+ HINT */ xxx /* comment :a ? */ :a yyyy :b :c :a zzzzz /* :xx XX*"; + ParsedSql psql4 = NamedParameterUtils.parseSqlStatement(sql4); + Map parameters = Collections.singletonMap("a", "0"); + assertEquals("/*+ HINT */ xxx /* comment :a ? */ ? yyyy ? ? ? zzzzz /* :xx XX*", + NamedParameterUtils.substituteNamedParameters(psql4, new MapSqlParameterSource(parameters))); + } + + /* + * SPR-4612 + */ + public void testParseSqlStatementWithPostgresCasting() throws Exception { + String expectedSql = "select 'first name' from artists where id = ? and birth_date=?::timestamp"; + String sql = "select 'first name' from artists where id = :id and birth_date=:birthDate::timestamp"; + ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); + assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null)); + } + + /* + * SPR-2544 + */ + public void testParseSqlStatementWithLogicalAnd() { + String expectedSql = "xxx & yyyy"; + ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(expectedSql); + assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null)); + } + + /* + * SPR-2544 + */ + public void testSubstituteNamedParametersWithLogicalAnd() throws Exception { + String expectedSql = "xxx & yyyy"; + String newSql = NamedParameterUtils.substituteNamedParameters(expectedSql, new MapSqlParameterSource()); + assertEquals(expectedSql, newSql); + } + + /* + * SPR-3173 + */ + public void testVariableAssignmentOperator() throws Exception { + String expectedSql = "x := 1"; + String newSql = NamedParameterUtils.substituteNamedParameters(expectedSql, new MapSqlParameterSource()); + assertEquals(expectedSql, newSql); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcBeanDefinitionReaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcBeanDefinitionReaderTests.java new file mode 100644 index 00000000000..16f620942cb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcBeanDefinitionReaderTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.support; + +import java.sql.ResultSet; +import java.sql.Statement; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * @author Rod Johnson + */ +public class JdbcBeanDefinitionReaderTests extends AbstractJdbcTests { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + + public void testValid() throws Exception { + String sql = "SELECT NAME AS NAME, PROPERTY AS PROPERTY, VALUE AS VALUE FROM T"; + + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + ctrlResultSet.expectAndReturn(mockResultSet.next(), true, 2); + ctrlResultSet.expectAndReturn(mockResultSet.next(), false); + + // first row + ctrlResultSet.expectAndReturn(mockResultSet.getString(1), "one"); + ctrlResultSet.expectAndReturn(mockResultSet.getString(2), "(class)"); + ctrlResultSet.expectAndReturn(mockResultSet.getString(3), "org.springframework.beans.TestBean"); + + // second row + ctrlResultSet.expectAndReturn(mockResultSet.getString(1), "one"); + ctrlResultSet.expectAndReturn(mockResultSet.getString(2), "age"); + ctrlResultSet.expectAndReturn(mockResultSet.getString(3), "53"); + + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + MockControl ctrlStatement = MockControl.createControl(Statement.class); + Statement mockStatement = (Statement) ctrlStatement.getMock(); + ctrlStatement.expectAndReturn(mockStatement.executeQuery(sql), mockResultSet); + if (debugEnabled) { + ctrlStatement.expectAndReturn(mockStatement.getWarnings(), null); + } + mockStatement.close(); + ctrlStatement.setVoidCallable(); + + mockConnection.createStatement(); + ctrlConnection.setReturnValue(mockStatement); + + ctrlResultSet.replay(); + ctrlStatement.replay(); + replay(); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + JdbcBeanDefinitionReader reader = new JdbcBeanDefinitionReader(bf); + reader.setDataSource(mockDataSource); + reader.loadBeanDefinitions(sql); + assertEquals("Incorrect number of bean definitions", 1, bf.getBeanDefinitionCount()); + TestBean tb = (TestBean) bf.getBean("one"); + assertEquals("Age in TestBean was wrong.", 53, tb.getAge()); + + ctrlResultSet.verify(); + ctrlStatement.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcDaoSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcDaoSupportTests.java new file mode 100644 index 00000000000..d9cb7118cc0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/JdbcDaoSupportTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.support; + +import java.util.ArrayList; +import java.util.List; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * @author Juergen Hoeller + * @since 30.07.2003 + */ +public class JdbcDaoSupportTests extends TestCase { + + public void testJdbcDaoSupportWithDataSource() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + final List test = new ArrayList(); + JdbcDaoSupport dao = new JdbcDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setDataSource(ds); + dao.afterPropertiesSet(); + assertEquals("Correct DataSource", ds, dao.getDataSource()); + assertEquals("Correct JdbcTemplate", ds, dao.getJdbcTemplate().getDataSource()); + assertEquals("initDao called", test.size(), 1); + } + + public void testJdbcDaoSupportWithJdbcTemplate() throws Exception { + JdbcTemplate template = new JdbcTemplate(); + final List test = new ArrayList(); + JdbcDaoSupport dao = new JdbcDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setJdbcTemplate(template); + dao.afterPropertiesSet(); + assertEquals("Correct JdbcTemplate", dao.getJdbcTemplate(), template); + assertEquals("initDao called", test.size(), 1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/LobSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/LobSupportTests.java new file mode 100644 index 00000000000..08f3a84f18f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/LobSupportTests.java @@ -0,0 +1,169 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.support; + +import java.io.IOException; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.jdbc.LobRetrievalFailureException; +import org.springframework.jdbc.support.lob.LobCreator; +import org.springframework.jdbc.support.lob.LobHandler; + +/** + * @author Alef Arendsen + */ +public class LobSupportTests extends TestCase { + + public void testCreatingPreparedStatementCallback() throws SQLException { + // - return value should match + // - lob creator should be closed + // - set return value should be called + // - execute update should be called + + MockControl lobHandlerControl = MockControl.createControl(LobHandler.class); + LobHandler handler = (LobHandler)lobHandlerControl.getMock(); + + MockControl lobCreatorControl = MockControl.createControl(LobCreator.class); + LobCreator creator = (LobCreator)lobCreatorControl.getMock(); + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement)psControl.getMock(); + + handler.getLobCreator(); + lobHandlerControl.setReturnValue(creator); + ps.executeUpdate(); + psControl.setReturnValue(3); + creator.close(); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + psControl.replay(); + + class SetValuesCalled { + boolean b = false; + } + + final SetValuesCalled svc = new SetValuesCalled(); + + AbstractLobCreatingPreparedStatementCallback psc = + new AbstractLobCreatingPreparedStatementCallback(handler) { + + protected void setValues(PreparedStatement ps, LobCreator lobCreator) + throws SQLException, DataAccessException { + svc.b = true; + } + }; + + assertEquals(new Integer(3), psc.doInPreparedStatement(ps)); + + lobHandlerControl.verify(); + lobCreatorControl.verify(); + psControl.verify(); + assertTrue(svc.b); + } + + public void testAbstractLobStreamingResultSetExtractorNoRows() throws SQLException { + MockControl rsetControl = MockControl.createControl(ResultSet.class); + ResultSet rset = (ResultSet)rsetControl.getMock(); + rset.next(); + rsetControl.setReturnValue(false); + rsetControl.replay(); + + AbstractLobStreamingResultSetExtractor lobRse = getResultSetExtractor(false); + try { + lobRse.extractData(rset); + fail("IncorrectResultSizeDataAccessException should have been thrown"); + } catch (IncorrectResultSizeDataAccessException e) { + // expected + } + } + + public void testAbstractLobStreamingResultSetExtractorOneRow() throws SQLException { + MockControl rsetControl = MockControl.createControl(ResultSet.class); + ResultSet rset = (ResultSet)rsetControl.getMock(); + rset.next(); + rsetControl.setReturnValue(true); + // see if it's called + rset.clearWarnings(); + rset.next(); + rsetControl.setReturnValue(false); + rsetControl.replay(); + + AbstractLobStreamingResultSetExtractor lobRse = getResultSetExtractor(false); + lobRse.extractData(rset); + rsetControl.verify(); + } + + public void testAbstractLobStreamingResultSetExtractorMultipleRows() throws SQLException { + MockControl rsetControl = MockControl.createControl(ResultSet.class); + ResultSet rset = (ResultSet)rsetControl.getMock(); + rset.next(); + rsetControl.setReturnValue(true); + // see if it's called + rset.clearWarnings(); + rset.next(); + rsetControl.setReturnValue(true); + rsetControl.replay(); + + AbstractLobStreamingResultSetExtractor lobRse = getResultSetExtractor(false); + try { + lobRse.extractData(rset); + fail("IncorrectResultSizeDataAccessException should have been thrown"); + } catch (IncorrectResultSizeDataAccessException e) { + // expected + } + rsetControl.verify(); + } + + public void testAbstractLobStreamingResultSetExtractorCorrectException() throws SQLException { + MockControl rsetControl = MockControl.createControl(ResultSet.class); + ResultSet rset = (ResultSet)rsetControl.getMock(); + rset.next(); + rsetControl.setReturnValue(true); + rsetControl.replay(); + + AbstractLobStreamingResultSetExtractor lobRse = getResultSetExtractor(true); + try { + lobRse.extractData(rset); + fail("LobRetrievalFailureException should have been thrown"); + } catch (LobRetrievalFailureException e) { + // expected + } + rsetControl.verify(); + } + + private AbstractLobStreamingResultSetExtractor getResultSetExtractor(final boolean ex) { + AbstractLobStreamingResultSetExtractor lobRse = new AbstractLobStreamingResultSetExtractor() { + protected void streamData(ResultSet rs) throws SQLException, IOException { + if (ex) { + throw new IOException(); + } + else { + rs.clearWarnings(); + } + } + }; + return lobRse; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/SqlLobValueTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/SqlLobValueTests.java new file mode 100644 index 00000000000..29a4a51fbc1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/support/SqlLobValueTests.java @@ -0,0 +1,274 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.jdbc.core.support; + +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; +import java.util.Date; + +import junit.framework.TestCase; +import org.easymock.ArgumentsMatcher; +import org.easymock.MockControl; + +import org.springframework.jdbc.support.lob.LobCreator; +import org.springframework.jdbc.support.lob.LobHandler; + +/** + * Test cases for the sql lob value: + * + * BLOB: + * 1. Types.BLOB: setBlobAsBytes (byte[]) + * 2. String: setBlobAsBytes (byte[]) + * 3. else: IllegalArgumentException + * + * CLOB: + * 4. String or NULL: setClobAsString (String) + * 5. InputStream: setClobAsAsciiStream (InputStream) + * 6. Reader: setClobAsCharacterStream (Reader) + * 7. else: IllegalArgumentException + * + * @author Alef Arendsen + */ +public class SqlLobValueTests extends TestCase { + + private MockControl psControl; + private PreparedStatement ps; + + private MockControl lobHandlerControl; + private LobHandler handler; + + private MockControl lobCreatorControl; + private LobCreator creator; + + public void setUp() { + // create preparedstatement + psControl = MockControl.createControl(PreparedStatement.class); + ps = (PreparedStatement) psControl.getMock(); + + // create handler controler + lobHandlerControl = MockControl.createControl(LobHandler.class); + handler = (LobHandler) lobHandlerControl.getMock(); + + // create creator control + lobCreatorControl = MockControl.createControl(LobCreator.class); + creator = (LobCreator) lobCreatorControl.getMock(); + + // set initial state + handler.getLobCreator(); + lobHandlerControl.setReturnValue(creator); + } + + private void replay() { + psControl.replay(); + lobHandlerControl.replay(); + lobCreatorControl.replay(); + } + + public void test1() throws SQLException { + byte[] testBytes = "Bla".getBytes(); + creator.setBlobAsBytes(ps, 1, testBytes); + replay(); + SqlLobValue lob = new SqlLobValue(testBytes, handler); + lob.setTypeValue(ps, 1, Types.BLOB, "test"); + lobHandlerControl.verify(); + lobCreatorControl.verify(); + } + + public void test2() throws SQLException { + String testString = "Bla"; + + creator.setBlobAsBytes(ps, 1, testString.getBytes()); + // set a matcher to match the byte array! + lobCreatorControl.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] arg0, Object[] arg1) { + byte[] one = (byte[]) arg0[2]; + byte[] two = (byte[]) arg1[2]; + return Arrays.equals(one, two); + } + public String toString(Object[] arg0) { + return "bla"; + } + }); + + replay(); + + SqlLobValue lob = new SqlLobValue(testString, handler); + lob.setTypeValue(ps, 1, Types.BLOB, "test"); + lobHandlerControl.verify(); + lobCreatorControl.verify(); + + } + + public void test3() + throws SQLException { + + Date testContent = new Date(); + + SqlLobValue lob = + new SqlLobValue(new InputStreamReader(new ByteArrayInputStream("Bla".getBytes())), 12); + try { + lob.setTypeValue(ps, 1, Types.BLOB, "test"); + fail("IllegalArgumentException should have been thrown"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void test4() throws SQLException { + String testContent = "Bla"; + creator.setClobAsString(ps, 1, testContent); + + replay(); + + SqlLobValue lob = new SqlLobValue(testContent, handler); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + lobHandlerControl.verify(); + lobCreatorControl.verify(); + } + + public void test5() throws SQLException { + byte[] testContent = "Bla".getBytes(); + ByteArrayInputStream bais = new ByteArrayInputStream(testContent); + creator.setClobAsAsciiStream(ps, 1, bais, 3); + lobCreatorControl.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] arg0, Object[] arg1) { + // for now, match always + return true; + } + public String toString(Object[] arg0) { + return null; + } + }); + + replay(); + + SqlLobValue lob = new SqlLobValue(new ByteArrayInputStream(testContent), 3, handler); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + lobHandlerControl.verify(); + lobCreatorControl.verify(); + } + + public void test6()throws SQLException { + byte[] testContent = "Bla".getBytes(); + ByteArrayInputStream bais = new ByteArrayInputStream(testContent); + InputStreamReader reader = new InputStreamReader(bais); + creator.setClobAsCharacterStream(ps, 1, reader, 3); + lobCreatorControl.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] arg0, Object[] arg1) { + // for now, match always + return true; + } + public String toString(Object[] arg0) { + return null; + } + }); + + replay(); + + SqlLobValue lob = new SqlLobValue(reader, 3, handler); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + lobHandlerControl.verify(); + lobCreatorControl.verify(); + + } + + public void test7() throws SQLException { + Date testContent = new Date(); + + SqlLobValue lob = new SqlLobValue("bla".getBytes()); + try { + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + fail("IllegalArgumentException should have been thrown"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testOtherConstructors() throws SQLException { + // a bit BS, but we need to test them, as long as they don't throw exceptions + + SqlLobValue lob = new SqlLobValue("bla"); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + + try { + lob = new SqlLobValue("bla".getBytes()); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + fail("IllegalArgumentException should have been thrown"); + } + catch (IllegalArgumentException e) { + // expected + } + + lob = new SqlLobValue(new ByteArrayInputStream("bla".getBytes()), 3); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + + lob = new SqlLobValue(new InputStreamReader( + new ByteArrayInputStream("bla".getBytes())), 3); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + + // same for BLOB + lob = new SqlLobValue("bla"); + lob.setTypeValue(ps, 1, Types.BLOB, "test"); + + lob = new SqlLobValue("bla".getBytes()); + lob.setTypeValue(ps, 1, Types.BLOB, "test"); + + lob = new SqlLobValue(new ByteArrayInputStream("bla".getBytes()), 3); + lob.setTypeValue(ps, 1, Types.BLOB, "test"); + + lob = new SqlLobValue(new InputStreamReader( + new ByteArrayInputStream("bla".getBytes())), 3); + + try { + lob.setTypeValue(ps, 1, Types.BLOB, "test"); + fail("IllegalArgumentException should have been thrown"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testCorrectCleanup() throws SQLException { + creator.setClobAsString(ps, 1, "Bla"); + creator.close(); + + replay(); + SqlLobValue lob = new SqlLobValue("Bla", handler); + lob.setTypeValue(ps, 1, Types.CLOB, "test"); + lob.cleanup(); + + lobCreatorControl.verify(); + } + + public void testOtherSqlType() throws SQLException { + replay(); + SqlLobValue lob = new SqlLobValue("Bla", handler); + try { + lob.setTypeValue(ps, 1, Types.SMALLINT, "test"); + fail("IllegalArgumentException should have been thrown"); + } + catch (IllegalArgumentException e) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java new file mode 100644 index 00000000000..89148bc0821 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.test; + +import java.util.Date; + +/** + * @author Thomas Risberg + */ +public abstract class AbstractPerson { + + private String name; + + private long age; + + private java.util.Date birth_date; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getAge() { + return age; + } + + public void setAge(long age) { + this.age = age; + } + + public Date getBirth_date() { + return birth_date; + } + + public void setBirth_date(Date birth_date) { + this.birth_date = birth_date; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ConcretePerson.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ConcretePerson.java new file mode 100644 index 00000000000..5d13c99c1b0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ConcretePerson.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.test; + +import java.math.BigDecimal; + +/** + * @author Thomas Risberg + */ +public class ConcretePerson extends AbstractPerson { + + private BigDecimal balance; + + + public BigDecimal getBalance() { + return balance; + } + + public void setBalance(BigDecimal balance) { + this.balance = balance; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ExtendedPerson.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ExtendedPerson.java new file mode 100644 index 00000000000..21c4f2eb6e2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/ExtendedPerson.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.test; + +/** + * @author Juergen Hoeller + */ +public class ExtendedPerson extends ConcretePerson { + + private Object someField; + + + public Object getSomeField() { + return someField; + } + + public void setSomeField(Object someField) { + this.someField = someField; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/Person.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/Person.java new file mode 100644 index 00000000000..9613b37e94b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/core/test/Person.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core.test; + +import java.math.BigDecimal; + +/** + * @author Thomas Risberg + */ +public class Person { + + private String name; + + private long age; + + private java.util.Date birth_date; + + private BigDecimal balance; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getAge() { + return age; + } + + public void setAge(long age) { + this.age = age; + } + + public java.util.Date getBirth_date() { + return birth_date; + } + + public void setBirth_date(java.util.Date birth_date) { + this.birth_date = birth_date; + } + + public BigDecimal getBalance() { + return balance; + } + + public void setBalance(BigDecimal balanace) { + this.balance = balanace; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceJtaTransactionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceJtaTransactionTests.java new file mode 100644 index 00000000000..3dcee9661cf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceJtaTransactionTests.java @@ -0,0 +1,901 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.jdbc.datasource.lookup.BeanFactoryDataSourceLookup; +import org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.jta.JtaTransactionManager; +import org.springframework.transaction.jta.JtaTransactionObject; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 17.10.2005 + */ +public class DataSourceJtaTransactionTests extends TestCase { + + public void testJtaTransactionCommit() throws Exception { + doTestJtaTransaction(false); + } + + public void testJtaTransactionRollback() throws Exception { + doTestJtaTransaction(true); + } + + private void doTestJtaTransaction(final boolean rollback) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.begin(); + utControl.setVoidCallable(1); + if (rollback) { + ut.rollback(); + } + else { + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.commit(); + } + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.close(); + conControl.setVoidCallable(1); + conControl.replay(); + dsControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + + Connection c = DataSourceUtils.getConnection(ds); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + DataSourceUtils.releaseConnection(c, ds); + + c = DataSourceUtils.getConnection(ds); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + DataSourceUtils.releaseConnection(c, ds); + + if (rollback) { + status.setRollbackOnly(); + } + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + dsControl.verify(); + conControl.verify(); + utControl.verify(); + } + + public void testJtaTransactionCommitWithPropagationRequiresNew() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(false, false, false, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithAccessAfterResume() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(false, false, true, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithOpenOuterConnection() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(false, true, false, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithOpenOuterConnectionAccessed() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(false, true, true, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithTransactionAwareDataSource() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(false, false, true, true); + } + + public void testJtaTransactionRollbackWithPropagationRequiresNew() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(true, false, false, false); + } + + public void testJtaTransactionRollbackWithPropagationRequiresNewWithAccessAfterResume() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(true, false, true, false); + } + + public void testJtaTransactionRollbackWithPropagationRequiresNewWithOpenOuterConnection() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(true, true, false, false); + } + + public void testJtaTransactionRollbackWithPropagationRequiresNewWithOpenOuterConnectionAccessed() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(true, true, true, false); + } + + public void testJtaTransactionRollbackWithPropagationRequiresNewWithTransactionAwareDataSource() throws Exception { + doTestJtaTransactionWithPropagationRequiresNew(true, false, true, true); + } + + private void doTestJtaTransactionWithPropagationRequiresNew( + final boolean rollback, final boolean openOuterConnection, final boolean accessAfterResume, + final boolean useTransactionAwareDataSource) throws Exception { + + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 16); + tm.suspend(); + tmControl.setReturnValue(tx, 5); + ut.begin(); + utControl.setVoidCallable(5); + ut.commit(); + utControl.setVoidCallable(5); + tm.resume(tx); + tmControl.setVoidCallable(5); + if (rollback) { + ut.rollback(); + } + else { + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.commit(); + } + utControl.setVoidCallable(1); + utControl.replay(); + tmControl.replay(); + + final MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + final MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.isReadOnly(); + conControl.setReturnValue(true, 1); + if (!openOuterConnection) { + con.close(); + conControl.setVoidCallable(1); + } + conControl.replay(); + dsControl.replay(); + + final DataSource dsToUse = useTransactionAwareDataSource ? + new TransactionAwareDataSourceProxy(ds) : ds; + + JtaTransactionManager ptm = new JtaTransactionManager(ut, tm); + final TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + + Connection c = DataSourceUtils.getConnection(dsToUse); + try { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + c.isReadOnly(); + DataSourceUtils.releaseConnection(c, dsToUse); + + c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + if (!openOuterConnection) { + DataSourceUtils.releaseConnection(c, dsToUse); + } + } + catch (SQLException ex) { + } + + for (int i = 0; i < 5; i++) { + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + + try { + dsControl.verify(); + conControl.verify(); + dsControl.reset(); + conControl.reset(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.isReadOnly(); + conControl.setReturnValue(true, 1); + con.close(); + conControl.setVoidCallable(1); + dsControl.replay(); + conControl.replay(); + + Connection c = DataSourceUtils.getConnection(dsToUse); + c.isReadOnly(); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + DataSourceUtils.releaseConnection(c, dsToUse); + + c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + DataSourceUtils.releaseConnection(c, dsToUse); + } + catch (SQLException ex) { + } + } + }); + + } + + if (rollback) { + status.setRollbackOnly(); + } + + if (accessAfterResume) { + try { + if (!openOuterConnection) { + dsControl.verify(); + dsControl.reset(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + dsControl.replay(); + } + conControl.verify(); + conControl.reset(); + con.isReadOnly(); + conControl.setReturnValue(true, 1); + con.close(); + conControl.setVoidCallable(1); + conControl.replay(); + + if (!openOuterConnection) { + c = DataSourceUtils.getConnection(dsToUse); + } + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + c.isReadOnly(); + DataSourceUtils.releaseConnection(c, dsToUse); + + c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + DataSourceUtils.releaseConnection(c, dsToUse); + } + catch (SQLException ex) { + } + } + + else { + if (openOuterConnection) { + try { + conControl.verify(); + conControl.reset(); + con.close(); + conControl.setVoidCallable(1); + conControl.replay(); + } + catch (SQLException ex) { + } + DataSourceUtils.releaseConnection(c, dsToUse); + } + } + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + dsControl.verify(); + conControl.verify(); + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionCommitWithPropagationRequiredWithinSupports() throws Exception { + doTestJtaTransactionCommitWithNewTransactionWithinEmptyTransaction(false, false); + } + + public void testJtaTransactionCommitWithPropagationRequiredWithinNotSupported() throws Exception { + doTestJtaTransactionCommitWithNewTransactionWithinEmptyTransaction(false, true); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithinSupports() throws Exception { + doTestJtaTransactionCommitWithNewTransactionWithinEmptyTransaction(true, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithinNotSupported() throws Exception { + doTestJtaTransactionCommitWithNewTransactionWithinEmptyTransaction(true, true); + } + + private void doTestJtaTransactionCommitWithNewTransactionWithinEmptyTransaction( + final boolean requiresNew, boolean notSupported) throws Exception { + + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + if (notSupported) { + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.suspend(); + tmControl.setReturnValue(tx, 1); + } + else { + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + } + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + utControl.setVoidCallable(1); + if (notSupported) { + tm.resume(tx); + tmControl.setVoidCallable(1); + } + utControl.replay(); + tmControl.replay(); + txControl.replay(); + + final MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + final MockControl con1Control = MockControl.createControl(Connection.class); + final Connection con1 = (Connection) con1Control.getMock(); + final MockControl con2Control = MockControl.createControl(Connection.class); + final Connection con2 = (Connection) con2Control.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con1, 1); + ds.getConnection(); + dsControl.setReturnValue(con2, 1); + con2.close(); + con2Control.setVoidCallable(1); + con1.close(); + con1Control.setVoidCallable(1); + dsControl.replay(); + con1Control.replay(); + con2Control.replay(); + + final JtaTransactionManager ptm = new JtaTransactionManager(ut, tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(notSupported ? + TransactionDefinition.PROPAGATION_NOT_SUPPORTED : TransactionDefinition.PROPAGATION_SUPPORTS); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertSame(con1, DataSourceUtils.getConnection(ds)); + assertSame(con1, DataSourceUtils.getConnection(ds)); + + TransactionTemplate tt2 = new TransactionTemplate(ptm); + tt2.setPropagationBehavior(requiresNew ? + TransactionDefinition.PROPAGATION_REQUIRES_NEW : TransactionDefinition.PROPAGATION_REQUIRED); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertSame(con2, DataSourceUtils.getConnection(ds)); + assertSame(con2, DataSourceUtils.getConnection(ds)); + } + }); + + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertSame(con1, DataSourceUtils.getConnection(ds)); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + tmControl.verify(); + txControl.verify(); + dsControl.verify(); + con1Control.verify(); + con2Control.verify(); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewAndSuspendException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(true, false, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithOpenOuterConnectionAndSuspendException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(true, true, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithTransactionAwareDataSourceAndSuspendException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(true, false, true); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithOpenOuterConnectionAndTransactionAwareDataSourceAndSuspendException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(true, true, true); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewAndBeginException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(false, false, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithOpenOuterConnectionAndBeginException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(false, true, false); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithOpenOuterConnectionAndTransactionAwareDataSourceAndBeginException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(false, true, true); + } + + public void testJtaTransactionCommitWithPropagationRequiresNewWithTransactionAwareDataSourceAndBeginException() throws Exception { + doTestJtaTransactionWithPropagationRequiresNewAndBeginException(false, false, true); + } + + private void doTestJtaTransactionWithPropagationRequiresNewAndBeginException(boolean suspendException, + final boolean openOuterConnection, final boolean useTransactionAwareDataSource) throws Exception { + + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + if (suspendException) { + tm.suspend(); + tmControl.setThrowable(new SystemException(), 1); + } + else { + tm.suspend(); + tmControl.setReturnValue(tx, 1); + ut.begin(); + utControl.setThrowable(new SystemException(), 1); + tm.resume(tx); + tmControl.setVoidCallable(1); + } + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + tmControl.replay(); + + final MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + final MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.isReadOnly(); + conControl.setReturnValue(true, 1); + if (!openOuterConnection || useTransactionAwareDataSource) { + con.close(); + conControl.setVoidCallable(1); + } + conControl.replay(); + dsControl.replay(); + + final DataSource dsToUse = useTransactionAwareDataSource ? + new TransactionAwareDataSourceProxy(ds) : ds; + if (dsToUse instanceof TransactionAwareDataSourceProxy) { + ((TransactionAwareDataSourceProxy) dsToUse).setReobtainTransactionalConnections(true); + } + + JtaTransactionManager ptm = new JtaTransactionManager(ut, tm); + final TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + + Connection c = DataSourceUtils.getConnection(dsToUse); + try { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + c.isReadOnly(); + DataSourceUtils.releaseConnection(c, dsToUse); + + c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + if (!openOuterConnection) { + DataSourceUtils.releaseConnection(c, dsToUse); + } + } + catch (SQLException ex) { + } + + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + + try { + dsControl.verify(); + conControl.verify(); + dsControl.reset(); + conControl.reset(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.close(); + conControl.setVoidCallable(1); + dsControl.replay(); + conControl.replay(); + + Connection c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + DataSourceUtils.releaseConnection(c, dsToUse); + + c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + DataSourceUtils.releaseConnection(c, dsToUse); + } + catch (SQLException ex) { + } + } + }); + } + finally { + if (openOuterConnection) { + try { + dsControl.verify(); + dsControl.reset(); + conControl.verify(); + conControl.reset(); + + if (useTransactionAwareDataSource) { + ds.getConnection(); + dsControl.setReturnValue(con, 1); + } + con.isReadOnly(); + conControl.setReturnValue(true, 1); + con.close(); + conControl.setVoidCallable(1); + dsControl.replay(); + conControl.replay(); + + c.isReadOnly(); + DataSourceUtils.releaseConnection(c, dsToUse); + } + catch (SQLException ex) { + } + } + } + } + }); + + fail("Should have thrown TransactionException"); + } + catch (TransactionException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + dsControl.verify(); + conControl.verify(); + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionWithConnectionHolderStillBound() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut) { + protected void doRegisterAfterCompletionWithJtaTransaction( + JtaTransactionObject txObject, final List synchronizations) { + Thread async = new Thread() { + public void run() { + invokeAfterCompletion(synchronizations, TransactionSynchronization.STATUS_COMMITTED); + } + }; + async.start(); + try { + async.join(); + } + catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + }; + TransactionTemplate tt = new TransactionTemplate(ptm); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + for (int i = 0; i < 3; i++) { + utControl.reset(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + utControl.replay(); + + dsControl.reset(); + conControl.reset(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.close(); + conControl.setVoidCallable(1); + dsControl.replay(); + conControl.replay(); + + final boolean releaseCon = (i != 1); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is existing transaction", !status.isNewTransaction()); + + Connection c = DataSourceUtils.getConnection(ds); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + DataSourceUtils.releaseConnection(c, ds); + + c = DataSourceUtils.getConnection(ds); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + if (releaseCon) { + DataSourceUtils.releaseConnection(c, ds); + } + } + }); + + if (!releaseCon) { + assertTrue("Still has connection holder", TransactionSynchronizationManager.hasResource(ds)); + } + else { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + } + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + conControl.verify(); + dsControl.verify(); + utControl.verify(); + } + } + + public void testJtaTransactionWithIsolationLevelDataSourceAdapter() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl ds1Control = MockControl.createControl(DataSource.class); + final DataSource ds1 = (DataSource) ds1Control.getMock(); + MockControl con1Control = MockControl.createControl(Connection.class); + final Connection con1 = (Connection) con1Control.getMock(); + ds1.getConnection(); + ds1Control.setReturnValue(con1, 1); + con1.close(); + con1Control.setVoidCallable(1); + ds1.getConnection(); + ds1Control.setReturnValue(con1, 1); + con1.setReadOnly(true); + con1Control.setVoidCallable(1); + con1.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); + con1Control.setVoidCallable(1); + con1.close(); + con1Control.setVoidCallable(1); + con1Control.replay(); + ds1Control.replay(); + + final IsolationLevelDataSourceAdapter dsToUse = new IsolationLevelDataSourceAdapter(); + dsToUse.setTargetDataSource(ds1); + dsToUse.afterPropertiesSet(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + ptm.setAllowCustomIsolationLevels(true); + + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + Connection c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + assertSame(con1, c); + DataSourceUtils.releaseConnection(c, dsToUse); + } + }); + + tt.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); + tt.setReadOnly(true); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + Connection c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + assertSame(con1, c); + DataSourceUtils.releaseConnection(c, dsToUse); + } + }); + + ds1Control.verify(); + con1Control.verify(); + utControl.verify(); + } + + public void testJtaTransactionWithIsolationLevelDataSourceRouter() throws Exception { + doTestJtaTransactionWithIsolationLevelDataSourceRouter(false); + } + + public void testJtaTransactionWithIsolationLevelDataSourceRouterWithDataSourceLookup() throws Exception { + doTestJtaTransactionWithIsolationLevelDataSourceRouter(true); + } + + private void doTestJtaTransactionWithIsolationLevelDataSourceRouter(boolean dataSourceLookup) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl ds1Control = MockControl.createControl(DataSource.class); + final DataSource ds1 = (DataSource) ds1Control.getMock(); + MockControl con1Control = MockControl.createControl(Connection.class); + final Connection con1 = (Connection) con1Control.getMock(); + ds1.getConnection(); + ds1Control.setReturnValue(con1, 1); + con1.close(); + con1Control.setVoidCallable(1); + con1Control.replay(); + ds1Control.replay(); + + MockControl ds2Control = MockControl.createControl(DataSource.class); + final DataSource ds2 = (DataSource) ds2Control.getMock(); + MockControl con2Control = MockControl.createControl(Connection.class); + final Connection con2 = (Connection) con2Control.getMock(); + ds2.getConnection(); + ds2Control.setReturnValue(con2, 1); + con2.close(); + con2Control.setVoidCallable(1); + con2Control.replay(); + ds2Control.replay(); + + final IsolationLevelDataSourceRouter dsToUse = new IsolationLevelDataSourceRouter(); + Map targetDataSources = new HashMap(); + if (dataSourceLookup) { + targetDataSources.put("ISOLATION_REPEATABLE_READ", "ds2"); + dsToUse.setDefaultTargetDataSource("ds1"); + StaticListableBeanFactory beanFactory = new StaticListableBeanFactory(); + beanFactory.addBean("ds1", ds1); + beanFactory.addBean("ds2", ds2); + dsToUse.setDataSourceLookup(new BeanFactoryDataSourceLookup(beanFactory)); + } + else { + targetDataSources.put("ISOLATION_REPEATABLE_READ", ds2); + dsToUse.setDefaultTargetDataSource(ds1); + } + dsToUse.setTargetDataSources(targetDataSources); + dsToUse.afterPropertiesSet(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + ptm.setAllowCustomIsolationLevels(true); + + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + Connection c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + assertSame(con1, c); + DataSourceUtils.releaseConnection(c, dsToUse); + } + }); + + tt.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + Connection c = DataSourceUtils.getConnection(dsToUse); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + assertSame(con2, c); + DataSourceUtils.releaseConnection(c, dsToUse); + } + }); + + ds1Control.verify(); + con1Control.verify(); + ds2Control.verify(); + con2Control.verify(); + utControl.verify(); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionIsolationLevel()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceTransactionManagerTests.java new file mode 100644 index 00000000000..703e6930d08 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DataSourceTransactionManagerTests.java @@ -0,0 +1,1990 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Savepoint; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.jdbc.UncategorizedSQLException; +import org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor; +import org.springframework.transaction.CannotCreateTransactionException; +import org.springframework.transaction.IllegalTransactionStateException; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.TransactionSystemException; +import org.springframework.transaction.TransactionTimedOutException; +import org.springframework.transaction.UnexpectedRollbackException; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 04.07.2003 + */ +public class DataSourceTransactionManagerTests extends TestCase { + + public void testTransactionCommitWithAutoCommitTrue() throws Exception { + doTestTransactionCommitRestoringAutoCommit(true, false, false); + } + + public void testTransactionCommitWithAutoCommitFalse() throws Exception { + doTestTransactionCommitRestoringAutoCommit(false, false, false); + } + + public void testTransactionCommitWithAutoCommitTrueAndLazyConnection() throws Exception { + doTestTransactionCommitRestoringAutoCommit(true, true, false); + } + + public void testTransactionCommitWithAutoCommitFalseAndLazyConnection() throws Exception { + doTestTransactionCommitRestoringAutoCommit(false, true, false); + } + + public void testTransactionCommitWithAutoCommitTrueAndLazyConnectionAndStatementCreated() throws Exception { + doTestTransactionCommitRestoringAutoCommit(true, true, true); + } + + public void testTransactionCommitWithAutoCommitFalseAndLazyConnectionAndStatementCreated() throws Exception { + doTestTransactionCommitRestoringAutoCommit(false, true, true); + } + + private void doTestTransactionCommitRestoringAutoCommit( + boolean autoCommit, boolean lazyConnection, final boolean createStatement) + throws Exception { + + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + + if (lazyConnection) { + ds.getConnection(); + dsControl.setReturnValue(con, 1); + if (createStatement) { + con.getMetaData(); + conControl.setReturnValue(null, 1); + } + con.getAutoCommit(); + conControl.setReturnValue(autoCommit, 1); + con.getTransactionIsolation(); + conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED, 1); + con.close(); + conControl.setVoidCallable(1); + } + + if (!lazyConnection || createStatement) { + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setReturnValue(autoCommit, 1); + if (autoCommit) { + // Must disable autocommit + con.setAutoCommit(false); + conControl.setVoidCallable(1); + } + if (createStatement) { + con.createStatement(); + conControl.setReturnValue(null, 1); + } + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + if (autoCommit) { + // must restore autoCommit + con.setAutoCommit(true); + conControl.setVoidCallable(1); + } + con.close(); + conControl.setVoidCallable(1); + } + + conControl.replay(); + dsControl.replay(); + + final DataSource dsToUse = (lazyConnection ? new LazyConnectionDataSourceProxy(ds) : ds); + PlatformTransactionManager tm = new DataSourceTransactionManager(dsToUse); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + Connection tCon = DataSourceUtils.getConnection(dsToUse); + try { + if (createStatement) { + tCon.createStatement(); + assertEquals(con, new SimpleNativeJdbcExtractor().getNativeConnection(tCon)); + } + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + conControl.verify(); + dsControl.verify(); + } + + public void testTransactionRollbackWithAutoCommitTrue() throws Exception { + doTestTransactionRollbackRestoringAutoCommit(true, false, false); + } + + public void testTransactionRollbackWithAutoCommitFalse() throws Exception { + doTestTransactionRollbackRestoringAutoCommit(false, false, false); + } + + public void testTransactionRollbackWithAutoCommitTrueAndLazyConnection() throws Exception { + doTestTransactionRollbackRestoringAutoCommit(true, true, false); + } + + public void testTransactionRollbackWithAutoCommitFalseAndLazyConnection() throws Exception { + doTestTransactionRollbackRestoringAutoCommit(false, true, false); + } + + public void testTransactionRollbackWithAutoCommitTrueAndLazyConnectionAndCreateStatement() throws Exception { + doTestTransactionRollbackRestoringAutoCommit(true, true, true); + } + + public void testTransactionRollbackWithAutoCommitFalseAndLazyConnectionAndCreateStatement() throws Exception { + doTestTransactionRollbackRestoringAutoCommit(false, true, true); + } + + private void doTestTransactionRollbackRestoringAutoCommit( + boolean autoCommit, boolean lazyConnection, final boolean createStatement) throws Exception { + + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + + if (lazyConnection) { + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setReturnValue(autoCommit, 1); + con.getTransactionIsolation(); + conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED, 1); + con.close(); + conControl.setVoidCallable(1); + } + + if (!lazyConnection || createStatement) { + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setReturnValue(autoCommit, 1); + if (autoCommit) { + // Must disable autocommit + con.setAutoCommit(false); + conControl.setVoidCallable(1); + } + if (createStatement) { + con.createStatement(); + conControl.setReturnValue(null, 1); + } + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + if (autoCommit) { + // Must restore autocommit + con.setAutoCommit(true); + conControl.setVoidCallable(1); + } + con.close(); + conControl.setVoidCallable(1); + } + + conControl.replay(); + dsControl.replay(); + + final DataSource dsToUse = (lazyConnection ? new LazyConnectionDataSourceProxy(ds) : ds); + PlatformTransactionManager tm = new DataSourceTransactionManager(dsToUse); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + final RuntimeException ex = new RuntimeException("Application exception"); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(dsToUse)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + Connection con = DataSourceUtils.getConnection(dsToUse); + if (createStatement) { + try { + con.createStatement(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + } + throw ex; + } + }); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException ex2) { + // expected + assertTrue("Correct exception thrown", ex2.equals(ex)); + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + conControl.verify(); + dsControl.verify(); + } + + public void testTransactionRollbackOnly() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + conControl.replay(); + dsControl.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + tm.setTransactionSynchronization(DataSourceTransactionManager.SYNCHRONIZATION_NEVER); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + ConnectionHolder conHolder = new ConnectionHolder(con); + conHolder.setTransactionActive(true); + TransactionSynchronizationManager.bindResource(ds, conHolder); + final RuntimeException ex = new RuntimeException("Application exception"); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is existing transaction", !status.isNewTransaction()); + throw ex; + } + }); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException ex2) { + // expected + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertEquals("Correct exception thrown", ex, ex2); + } + finally { + TransactionSynchronizationManager.unbindResource(ds); + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testParticipatingTransactionWithRollbackOnly() throws Exception { + doTestParticipatingTransactionWithRollbackOnly(false); + } + + public void testParticipatingTransactionWithRollbackOnlyAndFailEarly() throws Exception { + doTestParticipatingTransactionWithRollbackOnly(true); + } + + private void doTestParticipatingTransactionWithRollbackOnly(boolean failEarly) throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + if (failEarly) { + tm.setFailEarlyOnGlobalRollbackOnly(true); + } + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + TestTransactionSynchronization synch = + new TestTransactionSynchronization(ds, TransactionSynchronization.STATUS_ROLLED_BACK); + TransactionSynchronizationManager.registerSynchronization(synch); + + boolean outerTransactionBoundaryReached = false; + try { + assertTrue("Is new transaction", ts.isNewTransaction()); + + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is existing transaction", !status.isNewTransaction()); + assertFalse("Is not rollback-only", status.isRollbackOnly()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is existing transaction", !status.isNewTransaction()); + status.setRollbackOnly(); + } + }); + assertTrue("Is existing transaction", !status.isNewTransaction()); + assertTrue("Is rollback-only", status.isRollbackOnly()); + } + }); + + outerTransactionBoundaryReached = true; + tm.commit(ts); + + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + if (!outerTransactionBoundaryReached) { + tm.rollback(ts); + } + if (failEarly) { + assertFalse(outerTransactionBoundaryReached); + } + else { + assertTrue(outerTransactionBoundaryReached); + } + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertFalse(synch.beforeCommitCalled); + assertTrue(synch.beforeCompletionCalled); + assertFalse(synch.afterCommitCalled); + assertTrue(synch.afterCompletionCalled); + conControl.verify(); + dsControl.verify(); + } + + public void testParticipatingTransactionWithIncompatibleIsolationLevel() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + tm.setValidateExistingTransaction(true); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + final TransactionTemplate tt = new TransactionTemplate(tm); + final TransactionTemplate tt2 = new TransactionTemplate(tm); + tt2.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertFalse("Is not rollback-only", status.isRollbackOnly()); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + status.setRollbackOnly(); + } + }); + assertTrue("Is rollback-only", status.isRollbackOnly()); + } + }); + + fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testParticipatingTransactionWithIncompatibleReadOnly() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + tm.setValidateExistingTransaction(true); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setReadOnly(true); + final TransactionTemplate tt2 = new TransactionTemplate(tm); + tt2.setReadOnly(false); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertFalse("Is not rollback-only", status.isRollbackOnly()); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + status.setRollbackOnly(); + } + }); + assertTrue("Is rollback-only", status.isRollbackOnly()); + } + }); + + fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testParticipatingTransactionWithTransactionStartedFromSynch() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 2); + con.commit(); + conControl.setVoidCallable(2); + con.isReadOnly(); + conControl.setReturnValue(false, 2); + con.close(); + conControl.setVoidCallable(2); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 2); + conControl.replay(); + dsControl.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + final TestTransactionSynchronization synch = + new TestTransactionSynchronization(ds, TransactionSynchronization.STATUS_COMMITTED) { + public void afterCompletion(int status) { + super.afterCompletion(status); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + } + }); + } + }; + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + TransactionSynchronizationManager.registerSynchronization(synch); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue(synch.beforeCommitCalled); + assertTrue(synch.beforeCompletionCalled); + assertTrue(synch.afterCommitCalled); + assertTrue(synch.afterCompletionCalled); + conControl.verify(); + dsControl.verify(); + } + + public void testParticipatingTransactionWithRollbackOnlyAndInnerSynch() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + tm.setTransactionSynchronization(DataSourceTransactionManager.SYNCHRONIZATION_NEVER); + DataSourceTransactionManager tm2 = new DataSourceTransactionManager(ds); + // tm has no synch enabled (used at outer level), tm2 has synch enabled (inner level) + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + final TestTransactionSynchronization synch = + new TestTransactionSynchronization(ds, TransactionSynchronization.STATUS_UNKNOWN); + + try { + assertTrue("Is new transaction", ts.isNewTransaction()); + + final TransactionTemplate tt = new TransactionTemplate(tm2); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is existing transaction", !status.isNewTransaction()); + assertFalse("Is not rollback-only", status.isRollbackOnly()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is existing transaction", !status.isNewTransaction()); + status.setRollbackOnly(); + } + }); + assertTrue("Is existing transaction", !status.isNewTransaction()); + assertTrue("Is rollback-only", status.isRollbackOnly()); + TransactionSynchronizationManager.registerSynchronization(synch); + } + }); + + tm.commit(ts); + + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertFalse(synch.beforeCommitCalled); + assertTrue(synch.beforeCompletionCalled); + assertFalse(synch.afterCommitCalled); + assertTrue(synch.afterCompletionCalled); + conControl.verify(); + dsControl.verify(); + } + + public void testPropagationRequiresNewWithExistingTransaction() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 2); + con.rollback(); + conControl.setVoidCallable(1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 2); + con.close(); + conControl.setVoidCallable(2); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 2); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + status.setRollbackOnly(); + } + }); + assertTrue("Is new transaction", status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testPropagationRequiresNewWithExistingTransactionAndUnrelatedDataSource() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + MockControl con2Control = MockControl.createControl(Connection.class); + Connection con2 = (Connection) con2Control.getMock(); + con2.getAutoCommit(); + con2Control.setReturnValue(false, 1); + con2.rollback(); + con2Control.setVoidCallable(1); + con2.isReadOnly(); + con2Control.setReturnValue(false, 1); + con2.close(); + con2Control.setVoidCallable(1); + + MockControl ds2Control = MockControl.createControl(DataSource.class); + final DataSource ds2 = (DataSource) ds2Control.getMock(); + ds2.getConnection(); + ds2Control.setReturnValue(con2, 1); + con2Control.replay(); + ds2Control.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + PlatformTransactionManager tm2 = new DataSourceTransactionManager(ds2); + final TransactionTemplate tt2 = new TransactionTemplate(tm2); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds2)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + status.setRollbackOnly(); + } + }); + assertTrue("Is new transaction", status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds2)); + conControl.verify(); + dsControl.verify(); + con2Control.verify(); + ds2Control.verify(); + } + + public void testPropagationRequiresNewWithExistingTransactionAndUnrelatedFailingDataSource() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + MockControl ds2Control = MockControl.createControl(DataSource.class); + final DataSource ds2 = (DataSource) ds2Control.getMock(); + SQLException failure = new SQLException(); + ds2.getConnection(); + ds2Control.setThrowable(failure); + ds2Control.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + DataSourceTransactionManager tm2 = new DataSourceTransactionManager(ds2); + tm2.setTransactionSynchronization(DataSourceTransactionManager.SYNCHRONIZATION_NEVER); + final TransactionTemplate tt2 = new TransactionTemplate(tm2); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds2)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + status.setRollbackOnly(); + } + }); + } + }); + fail("Should have thrown CannotCreateTransactionException"); + } + catch (CannotCreateTransactionException ex) { + assertSame(failure, ex.getCause()); + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds2)); + conControl.verify(); + dsControl.verify(); + ds2Control.verify(); + } + + public void testPropagationNotSupportedWithExistingTransaction() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Isn't new transaction", !status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + status.setRollbackOnly(); + } + }); + assertTrue("Is new transaction", status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testPropagationNeverWithExistingTransaction() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + fail("Should have thrown IllegalTransactionStateException"); + } + }); + fail("Should have thrown IllegalTransactionStateException"); + } + }); + } + catch (IllegalTransactionStateException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testPropagationSupportsAndRequiresNew() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + + dsControl.replay(); + conControl.replay(); + + final PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + TransactionTemplate tt2 = new TransactionTemplate(tm); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + assertSame(con, DataSourceUtils.getConnection(ds)); + assertSame(con, DataSourceUtils.getConnection(ds)); + } + }); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + conControl.verify(); + } + + public void testPropagationSupportsAndRequiresNewWithEarlyAccess() throws Exception { + MockControl con1Control = MockControl.createControl(Connection.class); + final Connection con1 = (Connection) con1Control.getMock(); + con1.close(); + con1Control.setVoidCallable(1); + + MockControl con2Control = MockControl.createControl(Connection.class); + final Connection con2 = (Connection) con2Control.getMock(); + con2.getAutoCommit(); + con2Control.setReturnValue(false, 1); + con2.commit(); + con2Control.setVoidCallable(1); + con2.isReadOnly(); + con2Control.setReturnValue(false, 1); + con2.close(); + con2Control.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con1, 1); + ds.getConnection(); + dsControl.setReturnValue(con2, 1); + + dsControl.replay(); + con1Control.replay(); + con2Control.replay(); + + final PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertSame(con1, DataSourceUtils.getConnection(ds)); + assertSame(con1, DataSourceUtils.getConnection(ds)); + TransactionTemplate tt2 = new TransactionTemplate(tm); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Is new transaction", status.isNewTransaction()); + assertSame(con2, DataSourceUtils.getConnection(ds)); + assertSame(con2, DataSourceUtils.getConnection(ds)); + } + }); + assertSame(con1, DataSourceUtils.getConnection(ds)); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + con1Control.verify(); + con2Control.verify(); + } + + public void testTransactionWithIsolationAndReadOnly() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getTransactionIsolation(); + conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED, 1); + con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); + conControl.setVoidCallable(1); + con.setReadOnly(true); + conControl.setVoidCallable(1); + con.getAutoCommit(); + conControl.setReturnValue(true, 1); + con.setAutoCommit(false); + conControl.setVoidCallable(1); + con.commit(); + conControl.setVoidCallable(1); + con.setAutoCommit(true); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setReadOnly(true); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + // something transactional + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testTransactionWithLongTimeout() throws Exception { + doTestTransactionWithTimeout(10); + } + + public void testTransactionWithShortTimeout() throws Exception { + doTestTransactionWithTimeout(1); + } + + private void doTestTransactionWithTimeout(int timeout) throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setReturnValue(true, 1); + con.setAutoCommit(false); + conControl.setVoidCallable(1); + con.prepareStatement("some SQL statement"); + conControl.setReturnValue(ps, 1); + if (timeout > 1) { + ps.setQueryTimeout(timeout - 1); + psControl.setVoidCallable(1); + con.commit(); + } + else { + con.rollback(); + } + conControl.setVoidCallable(1); + con.setAutoCommit(true); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + psControl.replay(); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setTimeout(timeout); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + try { + Thread.sleep(1500); + } + catch (InterruptedException ex) { + } + try { + Connection con = DataSourceUtils.getConnection(ds); + PreparedStatement ps = con.prepareStatement("some SQL statement"); + DataSourceUtils.applyTransactionTimeout(ps, ds); + } + catch (SQLException ex) { + throw new DataAccessResourceFailureException("", ex); + } + } + }); + if (timeout <= 1) { + fail("Should have thrown TransactionTimedOutException"); + } + } + catch (TransactionTimedOutException ex) { + if (timeout <= 1) { + // expected + } + else { + throw ex; + } + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + psControl.verify(); + } + + public void testTransactionAwareDataSourceProxy() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getMetaData(); + conControl.setReturnValue(null, 1); + con.getAutoCommit(); + conControl.setReturnValue(true, 1); + con.setAutoCommit(false); + conControl.setVoidCallable(1); + con.commit(); + conControl.setVoidCallable(1); + con.setAutoCommit(true); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertEquals(con, DataSourceUtils.getConnection(ds)); + TransactionAwareDataSourceProxy dsProxy = new TransactionAwareDataSourceProxy(ds); + try { + assertEquals(con, ((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()); + assertEquals(con, new SimpleNativeJdbcExtractor().getNativeConnection(dsProxy.getConnection())); + // should be ignored + dsProxy.getConnection().close(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testTransactionAwareDataSourceProxyWithSuspension() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 2); + con.getMetaData(); + conControl.setReturnValue(null, 2); + con.getAutoCommit(); + conControl.setReturnValue(true, 2); + con.setAutoCommit(false); + conControl.setVoidCallable(2); + con.commit(); + conControl.setVoidCallable(2); + con.setAutoCommit(true); + conControl.setVoidCallable(2); + con.isReadOnly(); + conControl.setReturnValue(false, 2); + con.close(); + conControl.setVoidCallable(2); + + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertEquals(con, DataSourceUtils.getConnection(ds)); + final TransactionAwareDataSourceProxy dsProxy = new TransactionAwareDataSourceProxy(ds); + try { + assertEquals(con, ((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()); + assertEquals(con, new SimpleNativeJdbcExtractor().getNativeConnection(dsProxy.getConnection())); + // should be ignored + dsProxy.getConnection().close(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertEquals(con, DataSourceUtils.getConnection(ds)); + try { + assertEquals(con, ((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()); + assertEquals(con, new SimpleNativeJdbcExtractor().getNativeConnection(dsProxy.getConnection())); + // should be ignored + dsProxy.getConnection().close(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + } + }); + + try { + assertEquals(con, ((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()); + // should be ignored + dsProxy.getConnection().close(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testTransactionAwareDataSourceProxyWithSuspensionAndReobtaining() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 2); + con.getMetaData(); + conControl.setReturnValue(null, 2); + con.getAutoCommit(); + conControl.setReturnValue(true, 2); + con.setAutoCommit(false); + conControl.setVoidCallable(2); + con.commit(); + conControl.setVoidCallable(2); + con.setAutoCommit(true); + conControl.setVoidCallable(2); + con.isReadOnly(); + conControl.setReturnValue(false, 2); + con.close(); + conControl.setVoidCallable(2); + + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertEquals(con, DataSourceUtils.getConnection(ds)); + final TransactionAwareDataSourceProxy dsProxy = new TransactionAwareDataSourceProxy(ds); + dsProxy.setReobtainTransactionalConnections(true); + try { + assertEquals(con, ((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()); + assertEquals(con, new SimpleNativeJdbcExtractor().getNativeConnection(dsProxy.getConnection())); + // should be ignored + dsProxy.getConnection().close(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertEquals(con, DataSourceUtils.getConnection(ds)); + try { + assertEquals(con, ((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()); + assertEquals(con, new SimpleNativeJdbcExtractor().getNativeConnection(dsProxy.getConnection())); + // should be ignored + dsProxy.getConnection().close(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + } + }); + + try { + assertEquals(con, ((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()); + // should be ignored + dsProxy.getConnection().close(); + } + catch (SQLException ex) { + throw new UncategorizedSQLException("", "", ex); + } + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + /** + * Test behavior if the first operation on a connection (getAutoCommit) throws SQLException. + */ + public void testTransactionWithExceptionOnBegin() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setThrowable(new SQLException("Cannot begin")); + con.close(); + conControl.setVoidCallable(); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown CannotCreateTransactionException"); + } + catch (CannotCreateTransactionException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + } + + public void testTransactionWithExceptionOnCommit() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + // No need to restore it + conControl.setReturnValue(false, 1); + con.commit(); + conControl.setThrowable(new SQLException("Cannot commit"), 1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + } + + public void testTransactionWithExceptionOnCommitAndRollbackOnCommitFailure() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + // No need to change or restore + conControl.setReturnValue(false); + con.commit(); + conControl.setThrowable(new SQLException("Cannot commit"), 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + conControl.replay(); + dsControl.replay(); + + DataSourceTransactionManager tm = new DataSourceTransactionManager(ds); + tm.setRollbackOnCommitFailure(true); + TransactionTemplate tt = new TransactionTemplate(tm); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + } + + public void testTransactionWithExceptionOnRollback() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setReturnValue(true, 1); + // Must restore + con.setAutoCommit(false); + conControl.setVoidCallable(1); + + con.rollback(); + conControl.setThrowable(new SQLException("Cannot rollback"), 1); + con.setAutoCommit(true); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + status.setRollbackOnly(); + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + } + + public void testTransactionWithPropagationSupports() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + } + + public void testTransactionWithPropagationNotSupported() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + } + + public void testTransactionWithPropagationNever() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + } + + public void testExistingTransactionWithPropagationNested() throws Exception { + doTestExistingTransactionWithPropagationNested(1); + } + + public void testExistingTransactionWithPropagationNestedTwice() throws Exception { + doTestExistingTransactionWithPropagationNested(2); + } + + private void doTestExistingTransactionWithPropagationNested(final int count) throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); + MockControl spControl = MockControl.createControl(Savepoint.class); + Savepoint sp = (Savepoint) spControl.getMock(); + + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + md.supportsSavepoints(); + mdControl.setReturnValue(true, 1); + con.getMetaData(); + conControl.setReturnValue(md, 1); + for (int i = 1; i <= count; i++) { + con.setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + i); + conControl.setReturnValue(sp, 1); + con.releaseSavepoint(sp); + conControl.setVoidCallable(1); + } + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + + spControl.replay(); + mdControl.replay(); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + assertTrue("Isn't nested transaction", !status.hasSavepoint()); + for (int i = 0; i < count; i++) { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Isn't new transaction", !status.isNewTransaction()); + assertTrue("Is nested transaction", status.hasSavepoint()); + } + }); + } + assertTrue("Is new transaction", status.isNewTransaction()); + assertTrue("Isn't nested transaction", !status.hasSavepoint()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + spControl.verify(); + mdControl.verify(); + conControl.verify(); + dsControl.verify(); + } + + public void testExistingTransactionWithPropagationNestedAndRollback() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); + MockControl spControl = MockControl.createControl(Savepoint.class); + Savepoint sp = (Savepoint) spControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + md.supportsSavepoints(); + mdControl.setReturnValue(true, 1); + con.getMetaData(); + conControl.setReturnValue(md, 1); + con.setSavepoint("SAVEPOINT_1"); + conControl.setReturnValue(sp, 1); + con.rollback(sp); + conControl.setVoidCallable(1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + spControl.replay(); + mdControl.replay(); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + assertTrue("Isn't nested transaction", !status.hasSavepoint()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Isn't new transaction", !status.isNewTransaction()); + assertTrue("Is nested transaction", status.hasSavepoint()); + status.setRollbackOnly(); + } + }); + assertTrue("Is new transaction", status.isNewTransaction()); + assertTrue("Isn't nested transaction", !status.hasSavepoint()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + spControl.verify(); + mdControl.verify(); + conControl.verify(); + dsControl.verify(); + } + + public void testExistingTransactionWithManualSavepoint() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); + MockControl spControl = MockControl.createControl(Savepoint.class); + Savepoint sp = (Savepoint) spControl.getMock(); + + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + md.supportsSavepoints(); + mdControl.setReturnValue(true, 1); + con.getMetaData(); + conControl.setReturnValue(md, 1); + con.setSavepoint("SAVEPOINT_1"); + conControl.setReturnValue(sp, 1); + con.releaseSavepoint(sp); + conControl.setVoidCallable(1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + + spControl.replay(); + mdControl.replay(); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + Object savepoint = status.createSavepoint(); + status.releaseSavepoint(savepoint); + assertTrue("Is new transaction", status.isNewTransaction()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + spControl.verify(); + mdControl.verify(); + conControl.verify(); + dsControl.verify(); + } + + public void testExistingTransactionWithManualSavepointAndRollback() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); + MockControl spControl = MockControl.createControl(Savepoint.class); + Savepoint sp = (Savepoint) spControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 1); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + md.supportsSavepoints(); + mdControl.setReturnValue(true, 1); + con.getMetaData(); + conControl.setReturnValue(md, 1); + con.setSavepoint("SAVEPOINT_1"); + conControl.setReturnValue(sp, 1); + con.rollback(sp); + conControl.setVoidCallable(1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + spControl.replay(); + mdControl.replay(); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + Object savepoint = status.createSavepoint(); + status.rollbackToSavepoint(savepoint); + assertTrue("Is new transaction", status.isNewTransaction()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + spControl.verify(); + mdControl.verify(); + conControl.verify(); + dsControl.verify(); + } + + public void testTransactionWithPropagationNested() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.commit(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + public void testTransactionWithPropagationNestedAndRollback() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + con.getAutoCommit(); + conControl.setReturnValue(false, 1); + con.rollback(); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + con.close(); + conControl.setVoidCallable(1); + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con, 1); + conControl.replay(); + dsControl.replay(); + + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { + assertTrue("Is new transaction", status.isNewTransaction()); + status.setRollbackOnly(); + } + }); + + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + conControl.verify(); + dsControl.verify(); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + + + private static class TestTransactionSynchronization implements TransactionSynchronization { + + private DataSource dataSource; + private int status; + + public boolean beforeCommitCalled; + public boolean beforeCompletionCalled; + public boolean afterCommitCalled; + public boolean afterCompletionCalled; + + public TestTransactionSynchronization(DataSource dataSource, int status) { + this.dataSource = dataSource; + this.status = status; + } + + public void suspend() { + } + + public void resume() { + } + + public void beforeCommit(boolean readOnly) { + if (this.status != TransactionSynchronization.STATUS_COMMITTED) { + fail("Should never be called"); + } + assertFalse(this.beforeCommitCalled); + this.beforeCommitCalled = true; + } + + public void beforeCompletion() { + assertFalse(this.beforeCompletionCalled); + this.beforeCompletionCalled = true; + } + + public void afterCommit() { + if (this.status != TransactionSynchronization.STATUS_COMMITTED) { + fail("Should never be called"); + } + assertFalse(this.afterCommitCalled); + this.afterCommitCalled = true; + } + + public void afterCompletion(int status) { + assertFalse(this.afterCompletionCalled); + this.afterCompletionCalled = true; + assertTrue(status == this.status); + assertTrue(TransactionSynchronizationManager.hasResource(this.dataSource)); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DriverManagerDataSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DriverManagerDataSourceTests.java new file mode 100644 index 00000000000..8696edf257d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/DriverManagerDataSourceTests.java @@ -0,0 +1,160 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource; + +import java.sql.Connection; +import java.util.Properties; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +/** + * @author Rod Johnson + */ +public class DriverManagerDataSourceTests extends TestCase { + + public void testStandardUsage() throws Exception { + final String jdbcUrl = "url"; + final String uname = "uname"; + final String pwd = "pwd"; + + MockControl ctrlConnection = + MockControl.createControl(Connection.class); + final Connection mockConnection = (Connection) ctrlConnection.getMock(); + ctrlConnection.replay(); + + class TestDriverManagerDataSource extends DriverManagerDataSource { + protected Connection getConnectionFromDriverManager(String url, Properties props) { + assertEquals(jdbcUrl, url); + assertEquals(uname, props.getProperty("user")); + assertEquals(pwd, props.getProperty("password")); + return mockConnection; + } + } + + DriverManagerDataSource ds = new TestDriverManagerDataSource(); + //ds.setDriverClassName("foobar"); + ds.setUrl(jdbcUrl); + ds.setUsername(uname); + ds.setPassword(pwd); + + Connection actualCon = ds.getConnection(); + assertTrue(actualCon == mockConnection); + + assertTrue(ds.getUrl().equals(jdbcUrl)); + assertTrue(ds.getPassword().equals(pwd)); + assertTrue(ds.getUsername().equals(uname)); + + ctrlConnection.verify(); + } + + public void testUsageWithConnectionProperties() throws Exception { + final String jdbcUrl = "url"; + + final Properties connProps = new Properties(); + connProps.setProperty("myProp", "myValue"); + connProps.setProperty("yourProp", "yourValue"); + connProps.setProperty("user", "uname"); + connProps.setProperty("password", "pwd"); + + MockControl ctrlConnection = + MockControl.createControl(Connection.class); + final Connection mockConnection = (Connection) ctrlConnection.getMock(); + ctrlConnection.replay(); + + class TestDriverManagerDataSource extends DriverManagerDataSource { + protected Connection getConnectionFromDriverManager(String url, Properties props) { + assertEquals(jdbcUrl, url); + assertEquals("uname", props.getProperty("user")); + assertEquals("pwd", props.getProperty("password")); + assertEquals("myValue", props.getProperty("myProp")); + assertEquals("yourValue", props.getProperty("yourProp")); + return mockConnection; + } + } + + DriverManagerDataSource ds = new TestDriverManagerDataSource(); + //ds.setDriverClassName("foobar"); + ds.setUrl(jdbcUrl); + ds.setConnectionProperties(connProps); + + Connection actualCon = ds.getConnection(); + assertTrue(actualCon == mockConnection); + + assertTrue(ds.getUrl().equals(jdbcUrl)); + + ctrlConnection.verify(); + } + + public void testUsageWithConnectionPropertiesAndUserCredentials() throws Exception { + final String jdbcUrl = "url"; + final String uname = "uname"; + final String pwd = "pwd"; + + final Properties connProps = new Properties(); + connProps.setProperty("myProp", "myValue"); + connProps.setProperty("yourProp", "yourValue"); + connProps.setProperty("user", "uname2"); + connProps.setProperty("password", "pwd2"); + + MockControl ctrlConnection = + MockControl.createControl(Connection.class); + final Connection mockConnection = (Connection) ctrlConnection.getMock(); + ctrlConnection.replay(); + + class TestDriverManagerDataSource extends DriverManagerDataSource { + protected Connection getConnectionFromDriverManager(String url, Properties props) { + assertEquals(jdbcUrl, url); + assertEquals(uname, props.getProperty("user")); + assertEquals(pwd, props.getProperty("password")); + assertEquals("myValue", props.getProperty("myProp")); + assertEquals("yourValue", props.getProperty("yourProp")); + return mockConnection; + } + } + + DriverManagerDataSource ds = new TestDriverManagerDataSource(); + //ds.setDriverClassName("foobar"); + ds.setUrl(jdbcUrl); + ds.setUsername(uname); + ds.setPassword(pwd); + ds.setConnectionProperties(connProps); + + Connection actualCon = ds.getConnection(); + assertTrue(actualCon == mockConnection); + + assertTrue(ds.getUrl().equals(jdbcUrl)); + assertTrue(ds.getPassword().equals(pwd)); + assertTrue(ds.getUsername().equals(uname)); + + ctrlConnection.verify(); + } + + public void testInvalidClassName() throws Exception { + String bogusClassName = "foobar"; + DriverManagerDataSource ds = new DriverManagerDataSource(); + try { + ds.setDriverClassName(bogusClassName); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // OK + assertTrue(ex.getCause() instanceof ClassNotFoundException); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapterTests.java new file mode 100644 index 00000000000..d020c2113cc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapterTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +/** + * @author Juergen Hoeller + * @since 28.05.2004 + */ +public class UserCredentialsDataSourceAdapterTests extends TestCase { + + public void testStaticCredentials() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + ds.getConnection("user", "pw"); + dsControl.setReturnValue(con); + dsControl.replay(); + conControl.replay(); + + UserCredentialsDataSourceAdapter adapter = new UserCredentialsDataSourceAdapter(); + adapter.setTargetDataSource(ds); + adapter.setUsername("user"); + adapter.setPassword("pw"); + assertEquals(con, adapter.getConnection()); + } + + public void testNoCredentials() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + ds.getConnection(); + dsControl.setReturnValue(con); + dsControl.replay(); + conControl.replay(); + + UserCredentialsDataSourceAdapter adapter = new UserCredentialsDataSourceAdapter(); + adapter.setTargetDataSource(ds); + assertEquals(con, adapter.getConnection()); + } + + public void testThreadBoundCredentials() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + ds.getConnection("user", "pw"); + dsControl.setReturnValue(con); + dsControl.replay(); + conControl.replay(); + + UserCredentialsDataSourceAdapter adapter = new UserCredentialsDataSourceAdapter(); + adapter.setTargetDataSource(ds); + + adapter.setCredentialsForCurrentThread("user", "pw"); + try { + assertEquals(con, adapter.getConnection()); + } + finally { + adapter.removeCredentialsFromCurrentThread(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookupTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookupTests.java new file mode 100644 index 00000000000..30b78b33e54 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookupTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource.lookup; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanNotOfRequiredTypeException; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class BeanFactoryDataSourceLookupTests extends TestCase { + + private static final String DATASOURCE_BEAN_NAME = "dataSource"; + + + public void testLookupSunnyDay() throws Exception { + MockControl mockBeanFactory = MockControl.createControl(BeanFactory.class); + BeanFactory beanFactory = (BeanFactory) mockBeanFactory.getMock(); + + beanFactory.getBean(DATASOURCE_BEAN_NAME, DataSource.class); + StubDataSource expectedDataSource = new StubDataSource(); + mockBeanFactory.setReturnValue(expectedDataSource); + + mockBeanFactory.replay(); + + BeanFactoryDataSourceLookup lookup = new BeanFactoryDataSourceLookup(); + lookup.setBeanFactory(beanFactory); + DataSource dataSource = lookup.getDataSource(DATASOURCE_BEAN_NAME); + assertNotNull("A DataSourceLookup implementation must *never* return null from getDataSource(): this one obviously (and incorrectly) is", dataSource); + assertSame(expectedDataSource, dataSource); + + mockBeanFactory.verify(); + } + + public void testLookupWhereBeanFactoryYieldsNonDataSourceType() throws Exception { + MockControl mockBeanFactory = MockControl.createControl(BeanFactory.class); + final BeanFactory beanFactory = (BeanFactory) mockBeanFactory.getMock(); + + beanFactory.getBean(DATASOURCE_BEAN_NAME, DataSource.class); + mockBeanFactory.setThrowable(new BeanNotOfRequiredTypeException(DATASOURCE_BEAN_NAME, DataSource.class, String.class)); + + mockBeanFactory.replay(); + + new AssertThrows(DataSourceLookupFailureException.class) { + public void test() throws Exception { + BeanFactoryDataSourceLookup lookup = new BeanFactoryDataSourceLookup(beanFactory); + lookup.getDataSource(DATASOURCE_BEAN_NAME); + } + }.runTest(); + + mockBeanFactory.verify(); + } + + public void testLookupWhereBeanFactoryHasNotBeenSupplied() throws Exception { + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + BeanFactoryDataSourceLookup lookup = new BeanFactoryDataSourceLookup(); + lookup.getDataSource(DATASOURCE_BEAN_NAME); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/JndiDataSourceLookupTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/JndiDataSourceLookupTests.java new file mode 100644 index 00000000000..eebfac250b9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/JndiDataSourceLookupTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource.lookup; + +import javax.naming.NamingException; +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + */ +public final class JndiDataSourceLookupTests extends TestCase { + + private static final String DATA_SOURCE_NAME = "Love is like a stove, burns you when it's hot"; + + + public void testSunnyDay() throws Exception { + final DataSource expectedDataSource = new StubDataSource(); + JndiDataSourceLookup lookup = new JndiDataSourceLookup() { + protected Object lookup(String jndiName, Class requiredType) { + assertEquals(DATA_SOURCE_NAME, jndiName); + return expectedDataSource; + } + }; + DataSource dataSource = lookup.getDataSource(DATA_SOURCE_NAME); + assertNotNull("A DataSourceLookup implementation must *never* return null from getDataSource(): this one obviously (and incorrectly) is", dataSource); + assertSame(expectedDataSource, dataSource); + } + + public void testNoDataSourceAtJndiLocation() throws Exception { + new AssertThrows(DataSourceLookupFailureException.class) { + public void test() throws Exception { + JndiDataSourceLookup lookup = new JndiDataSourceLookup() { + protected Object lookup(String jndiName, Class requiredType) throws NamingException { + assertEquals(DATA_SOURCE_NAME, jndiName); + throw new NamingException(); + } + }; + lookup.getDataSource(DATA_SOURCE_NAME); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/MapDataSourceLookupTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/MapDataSourceLookupTests.java new file mode 100644 index 00000000000..284c380a315 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/MapDataSourceLookupTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource.lookup; + +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + */ +public final class MapDataSourceLookupTests extends TestCase { + + private static final String DATA_SOURCE_NAME = "dataSource"; + + + public void testGetDataSourcesReturnsUnmodifiableMap() throws Exception { + new AssertThrows(UnsupportedOperationException.class, "The Map returned from getDataSources() *must* be unmodifiable") { + public void test() throws Exception { + MapDataSourceLookup lookup = new MapDataSourceLookup(new HashMap()); + Map dataSources = lookup.getDataSources(); + dataSources.put("", ""); + } + }.runTest(); + } + + public void testLookupSunnyDay() throws Exception { + Map dataSources = new HashMap(); + StubDataSource expectedDataSource = new StubDataSource(); + dataSources.put(DATA_SOURCE_NAME, expectedDataSource); + MapDataSourceLookup lookup = new MapDataSourceLookup(); + lookup.setDataSources(dataSources); + DataSource dataSource = lookup.getDataSource(DATA_SOURCE_NAME); + assertNotNull("A DataSourceLookup implementation must *never* return null from getDataSource(): this one obviously (and incorrectly) is", dataSource); + assertSame(expectedDataSource, dataSource); + } + + public void testSettingDataSourceMapToNullIsAnIdempotentOperation() throws Exception { + Map dataSources = new HashMap(); + StubDataSource expectedDataSource = new StubDataSource(); + dataSources.put(DATA_SOURCE_NAME, expectedDataSource); + MapDataSourceLookup lookup = new MapDataSourceLookup(); + lookup.setDataSources(dataSources); + lookup.setDataSources(null); // must be idempotent (i.e. the following lookup must still work); + DataSource dataSource = lookup.getDataSource(DATA_SOURCE_NAME); + assertNotNull("A DataSourceLookup implementation must *never* return null from getDataSource(): this one obviously (and incorrectly) is", dataSource); + assertSame(expectedDataSource, dataSource); + } + + public void testAddingDataSourcePermitsOverride() throws Exception { + Map dataSources = new HashMap(); + StubDataSource overridenDataSource = new StubDataSource(); + StubDataSource expectedDataSource = new StubDataSource(); + dataSources.put(DATA_SOURCE_NAME, overridenDataSource); + MapDataSourceLookup lookup = new MapDataSourceLookup(); + lookup.setDataSources(dataSources); + lookup.addDataSource(DATA_SOURCE_NAME, expectedDataSource); // must override existing entry + DataSource dataSource = lookup.getDataSource(DATA_SOURCE_NAME); + assertNotNull("A DataSourceLookup implementation must *never* return null from getDataSource(): this one obviously (and incorrectly) is", dataSource); + assertSame(expectedDataSource, dataSource); + } + + public void testGetDataSourceWhereSuppliedMapHasNonDataSourceTypeUnderSpecifiedKey() throws Exception { + new AssertThrows(DataSourceLookupFailureException.class) { + public void test() throws Exception { + Map dataSources = new HashMap(); + dataSources.put(DATA_SOURCE_NAME, new Object()); + MapDataSourceLookup lookup = new MapDataSourceLookup(); + lookup.setDataSources(dataSources); + lookup.getDataSource(DATA_SOURCE_NAME); + } + }.runTest(); + } + + public void testGetDataSourceWhereSuppliedMapHasNoEntryForSpecifiedKey() throws Exception { + new AssertThrows(DataSourceLookupFailureException.class) { + public void test() throws Exception { + MapDataSourceLookup lookup = new MapDataSourceLookup(); + lookup.getDataSource(DATA_SOURCE_NAME); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/StubDataSource.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/StubDataSource.java new file mode 100644 index 00000000000..22904830666 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/datasource/lookup/StubDataSource.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource.lookup; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.springframework.jdbc.datasource.AbstractDataSource; + +/** + * Stub, do-nothing DataSource implementation. + * + *

All methods throw {@link UnsupportedOperationException}. + * + * @author Rick Evans + */ +class StubDataSource extends AbstractDataSource { + + public Connection getConnection() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Connection getConnection(String username, String password) throws SQLException { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/BatchSqlUpdateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/BatchSqlUpdateTests.java new file mode 100644 index 00000000000..b635c3a0cbe --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/BatchSqlUpdateTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jdbc.object; + +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.Types; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * @author Juergen Hoeller + * @since 22.02.2005 + */ +public class BatchSqlUpdateTests extends AbstractJdbcTests { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + + public void testBatchUpdateWithExplicitFlush() throws Exception { + doTestBatchUpdate(false); + } + + public void testBatchUpdateWithFlushThroughBatchSize() throws Exception { + doTestBatchUpdate(true); + } + + private void doTestBatchUpdate(boolean flushThroughBatchSize) throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + final int[] ids = new int[] { 100, 200 }; + final int[] rowsAffected = new int[] { 1, 2 }; + + MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + mockPreparedStatement.getConnection(); + ctrlPreparedStatement.setReturnValue(mockConnection); + mockPreparedStatement.setObject(1, new Integer(ids[0]), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(1, new Integer(ids[1]), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.addBatch(); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeBatch(); + ctrlPreparedStatement.setReturnValue(rowsAffected); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock(); + mockDatabaseMetaData.supportsBatchUpdates(); + ctrlDatabaseMetaData.setReturnValue(true); + + mockConnection.prepareStatement(sql); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(mockDatabaseMetaData, 1); + + ctrlPreparedStatement.replay(); + ctrlDatabaseMetaData.replay(); + replay(); + + BatchSqlUpdate update = new BatchSqlUpdate(mockDataSource, sql); + update.declareParameter(new SqlParameter(Types.INTEGER)); + if (flushThroughBatchSize) { + update.setBatchSize(2); + } + + update.update(ids[0]); + update.update(ids[1]); + + if (flushThroughBatchSize) { + assertEquals(0, update.getQueueCount()); + assertEquals(2, update.getRowsAffected().length); + } + else { + assertEquals(2, update.getQueueCount()); + assertEquals(0, update.getRowsAffected().length); + } + + int[] actualRowsAffected = update.flush(); + assertEquals(0, update.getQueueCount()); + + if (flushThroughBatchSize) { + assertTrue("flush did not execute updates", actualRowsAffected.length == 0); + } + else { + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + } + + actualRowsAffected = update.getRowsAffected(); + assertTrue("executed 2 updates", actualRowsAffected.length == 2); + assertEquals(rowsAffected[0], actualRowsAffected[0]); + assertEquals(rowsAffected[1], actualRowsAffected[1]); + + update.reset(); + assertEquals(0, update.getRowsAffected().length); + + ctrlPreparedStatement.verify(); + ctrlDatabaseMetaData.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/RdbmsOperationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/RdbmsOperationTests.java new file mode 100644 index 00000000000..e94bcc37293 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/RdbmsOperationTests.java @@ -0,0 +1,220 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +import java.sql.Types; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; + +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.SqlInOutParameter; +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +/** + * @author Trevor Cook + * @author Juergen Hoeller + */ +public class RdbmsOperationTests extends TestCase { + + public void testEmptySql() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + try { + operation.compile(); + fail("Shouldn't allow compiling without sql statement"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testSetTypeAfterCompile() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setDataSource(new DriverManagerDataSource()); + operation.setSql("select * from mytable"); + operation.compile(); + try { + operation.setTypes(new int[] {Types.INTEGER }); + fail("Shouldn't allow setting parameters after compile"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testDeclareParameterAfterCompile() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setDataSource(new DriverManagerDataSource()); + operation.setSql("select * from mytable"); + operation.compile(); + try { + operation.declareParameter(new SqlParameter(Types.INTEGER)); + fail("Shouldn't allow setting parameters after compile"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testTooFewParameters() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setSql("select * from mytable"); + operation.setTypes(new int[] { Types.INTEGER }); + try { + operation.validateParameters((Object[]) null); + fail("Shouldn't validate without enough parameters"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testTooFewMapParameters() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setSql("select * from mytable"); + operation.setTypes(new int[] { Types.INTEGER }); + try { + operation.validateNamedParameters((Map) null); + fail("Shouldn't validate without enough parameters"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testOperationConfiguredViaJdbcTemplateMustGetDataSource() throws Exception { + try { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setSql("foo"); + operation.compile(); + fail("Can't compile without providing a DataSource for the JdbcTemplate"); + } + catch (InvalidDataAccessApiUsageException ex) { + // Check for helpful error message. Omit leading character + // so as not to be fussy about case + assertTrue(ex.getMessage().indexOf("ataSource") != -1); + } + } + + public void testTooManyParameters() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setSql("select * from mytable"); + try { + operation.validateParameters(new Object[] {new Integer(1), new Integer(2)}); + fail("Shouldn't validate with too many parameters"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testUnspecifiedMapParameters() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setSql("select * from mytable"); + try { + Map params = new HashMap(); + params.put("col1", "value"); + operation.validateNamedParameters(params); + fail("Shouldn't validate with unspecified parameters"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testCompileTwice() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setDataSource(new DriverManagerDataSource()); + operation.setSql("select * from mytable"); + operation.setTypes(null); + operation.compile(); + operation.compile(); + } + + public void testEmptyDataSource() { + SqlOperation operation = new SqlOperation() { + }; + operation.setSql("select * from mytable"); + try { + operation.compile(); + fail("Shouldn't allow compiling without data source"); + } + catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testParameterPropagation() { + SqlOperation operation = new SqlOperation() { + }; + DataSource ds = new DriverManagerDataSource(); + operation.setDataSource(ds); + operation.setFetchSize(10); + operation.setMaxRows(20); + JdbcTemplate jt = operation.getJdbcTemplate(); + assertEquals(ds, jt.getDataSource()); + assertEquals(10, jt.getFetchSize()); + assertEquals(20, jt.getMaxRows()); + } + + public void testValidateInOutParameter() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + operation.setDataSource(new DriverManagerDataSource()); + operation.setSql("DUMMY_PROC"); + operation.declareParameter(new SqlOutParameter("DUMMY_OUT_PARAM", Types.VARCHAR)); + operation.declareParameter(new SqlInOutParameter("DUMMY_IN_OUT_PARAM", Types.VARCHAR)); + operation.validateParameters(new Object[] {"DUMMY_VALUE1", "DUMMY_VALUE2"}); + } + + public void testParametersSetWithList() { + TestRdbmsOperation operation = new TestRdbmsOperation(); + DataSource ds = new DriverManagerDataSource(); + operation.setDataSource(ds); + operation.setSql("select * from mytable where one = ? and two = ?"); + List l = new ArrayList(); + l.add(new SqlParameter("one", Types.NUMERIC)); + l.add(new SqlParameter("two", Types.VARCHAR)); + operation.setParameters(new SqlParameter[] { + new SqlParameter("one", Types.NUMERIC), + new SqlParameter("two", Types.NUMERIC)}); + operation.afterPropertiesSet(); + try { + operation.validateParameters(new Object[] {new Integer(1), new String("2")}); + assertEquals(2, operation.getDeclaredParameters().size()); + // OK + } + catch (InvalidDataAccessApiUsageException idaauex) { + fail("Should have validated with parameters set using List: " + idaauex.getMessage()); + } + } + + + private static class TestRdbmsOperation extends RdbmsOperation { + + protected void compileInternal() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlFunctionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlFunctionTests.java new file mode 100644 index 00000000000..0def0f4f925 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlFunctionTests.java @@ -0,0 +1,339 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Types; + +import org.apache.commons.logging.LogFactory; +import org.easymock.MockControl; + +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * @author Trevor Cook + */ +public class SqlFunctionTests extends AbstractJdbcTests { + + private static final String FUNCTION = "select count(id) from mytable"; + private static final String FUNCTION_INT = + "select count(id) from mytable where myparam = ?"; + private static final String FUNCTION_MIXED = + "select count(id) from mytable where myparam = ? and mystring = ?"; + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl ctrlPreparedStatement; + private PreparedStatement mockPreparedStatement; + private MockControl ctrlResultSet; + private ResultSet mockResultSet; + private MockControl ctrlResultSetMetaData; + private ResultSetMetaData mockResultSetMetaData; + + + protected void setUp() throws Exception { + super.setUp(); + + ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (shouldVerify()) { + ctrlPreparedStatement.verify(); + ctrlResultSet.verify(); + ctrlResultSetMetaData.verify(); + } + } + + protected void replay() { + super.replay(); + ctrlPreparedStatement.replay(); + ctrlResultSet.replay(); + ctrlResultSetMetaData.replay(); + } + + + public void testFunction() throws SQLException { + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(14)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(FUNCTION); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + SqlFunction function = new SqlFunction(); + function.setDataSource(mockDataSource); + function.setSql(FUNCTION); + function.compile(); + + int count = function.run(); + assertTrue("Function returned value 14", count == 14); + } + + public void testTooManyRows() throws SQLException { + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1, 2); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 2); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(14), 1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(15), 1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(FUNCTION); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + SqlFunction function = new SqlFunction(mockDataSource, FUNCTION); + function.compile(); + + try { + int count = function.run(); + fail("Shouldn't continue when too many rows returned"); + } + catch (IncorrectResultSizeDataAccessException idaauex) { + // OK + } + } + + public void testFunctionInt() throws SQLException { + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(14)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(FUNCTION_INT); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + SqlFunction function = new SqlFunction(mockDataSource, FUNCTION_INT); + function.setTypes(new int[] { Types.INTEGER }); + function.compile(); + + int count = function.run(1); + assertTrue("Function returned value 14", count == 14); + } + + public void testFunctionMixed() throws SQLException { + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(14)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(FUNCTION_MIXED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + SqlFunction function = new SqlFunction( + mockDataSource, FUNCTION_MIXED, new int[] { Types.INTEGER, Types.VARCHAR }); + function.compile(); + + int count = function.run(new Object[] { new Integer(1), "rod" }); + assertTrue("Function returned value 14", count == 14); + } + + public void testFunctionWithStringResult() throws SQLException { + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue("14"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(FUNCTION_MIXED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + SqlFunction function = new SqlFunction( mockDataSource, FUNCTION_MIXED); + function.setTypes(new int[] { Types.INTEGER, Types.VARCHAR }); + function.compile(); + + String result = (String) function.runGeneric(new Object[] { new Integer(1), "rod" }); + assertTrue("Function returned value 14", "14".equals(result)); + } + + public void testFunctionWithStringConvertedResult() throws SQLException { + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData, 1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue("14"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(FUNCTION_MIXED); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + SqlFunction function = new SqlFunction( mockDataSource, FUNCTION_MIXED); + function.setTypes(new int[] { Types.INTEGER, Types.VARCHAR }); + function.setResultType(String.class); + function.compile(); + + String result = (String) function.runGeneric(new Object[] { new Integer(1), "rod" }); + assertTrue("Function returned value 14", "14".equals(result)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlQueryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlQueryTests.java new file mode 100644 index 00000000000..ba33117361f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlQueryTests.java @@ -0,0 +1,1160 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.Customer; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.SqlParameter; + +/** + * @author Trevor Cook + * @author Thomas Risberg + * @author Juergen Hoeller + */ +public class SqlQueryTests extends AbstractJdbcTests { + + private static final String SELECT_ID = "select id from custmr"; + private static final String SELECT_ID_WHERE = + "select id from custmr where forename = ? and id = ?"; + private static final String SELECT_FORENAME = "select forename from custmr"; + private static final String SELECT_FORENAME_EMPTY = + "select forename from custmr WHERE 1 = 2"; + private static final String SELECT_ID_FORENAME_WHERE = + "select id, forename from prefix:custmr where forename = ?"; + private static final String SELECT_ID_FORENAME_NAMED_PARAMETERS = + "select id, forename from custmr where id = :id and country = :country"; + private static final String SELECT_ID_FORENAME_NAMED_PARAMETERS_PARSED = + "select id, forename from custmr where id = ? and country = ?"; + private static final String SELECT_ID_FORENAME_WHERE_ID_IN_LIST_1 = + "select id, forename from custmr where id in (?, ?)"; + private static final String SELECT_ID_FORENAME_WHERE_ID_IN_LIST_2 = + "select id, forename from custmr where id in (:ids)"; + private static final String SELECT_ID_FORENAME_WHERE_ID_REUSED_1 = + "select id, forename from custmr where id = ? or id = ?)"; + private static final String SELECT_ID_FORENAME_WHERE_ID_REUSED_2 = + "select id, forename from custmr where id = :id1 or id = :id1)"; + private static final String SELECT_ID_FORENAME_WHERE_ID = + "select id, forename from custmr where id <= ?"; + + private static final String[] COLUMN_NAMES = new String[] {"id", "forename"}; + private static final int[] COLUMN_TYPES = new int[] {Types.INTEGER, Types.VARCHAR}; + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl ctrlPreparedStatement; + private PreparedStatement mockPreparedStatement; + private MockControl ctrlResultSet; + private ResultSet mockResultSet; + + + protected void setUp() throws Exception { + super.setUp(); + ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (shouldVerify()) { + ctrlPreparedStatement.verify(); + ctrlResultSet.verify(); + } + } + + protected void replay() { + super.replay(); + ctrlPreparedStatement.replay(); + ctrlResultSet.replay(); + } + + + public void testQueryWithoutParams() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt(1); + ctrlResultSet.setReturnValue(1); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_ID); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + SqlQuery query = new MappingSqlQueryWithParameters() { + protected Object mapRow(ResultSet rs, int rownum, Object[] params, Map context) throws SQLException { + assertTrue("params were null", params == null); + assertTrue("context was null", context == null); + return new Integer(rs.getInt(1)); + } + }; + + query.setDataSource(mockDataSource); + query.setSql(SELECT_ID); + query.compile(); + List list = query.execute(); + assertTrue("Found customers", list.size() != 0); + for (Iterator itr = list.iterator(); itr.hasNext();) { + Integer id = (Integer) itr.next(); + assertTrue( + "Customer id was assigned correctly", + id.intValue() == 1); + } + } + + public void testQueryWithoutEnoughParams() { + replay(); + + MappingSqlQuery query = new MappingSqlQuery() { + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + return new Integer(rs.getInt(1)); + } + + }; + query.setDataSource(mockDataSource); + query.setSql(SELECT_ID_WHERE); + query.declareParameter( + new SqlParameter(COLUMN_NAMES[0], COLUMN_TYPES[0])); + query.declareParameter( + new SqlParameter(COLUMN_NAMES[1], COLUMN_TYPES[1])); + query.compile(); + + try { + List list = query.execute(); + fail("Shouldn't succeed in running query without enough params"); + } + catch (InvalidDataAccessApiUsageException ex) { + // OK + } + } + + public void testQueryWithMissingMapParams() { + replay(); + + MappingSqlQuery query = new MappingSqlQuery() { + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + return new Integer(rs.getInt(1)); + } + }; + query.setDataSource(mockDataSource); + query.setSql(SELECT_ID_WHERE); + query.declareParameter( + new SqlParameter(COLUMN_NAMES[0], COLUMN_TYPES[0])); + query.declareParameter( + new SqlParameter(COLUMN_NAMES[1], COLUMN_TYPES[1])); + query.compile(); + + try { + Map params = new HashMap(); + params.put(COLUMN_NAMES[0], "Value"); + List list = query.executeByNamedParam(params); + fail("Shouldn't succeed in running query with missing params"); + } + catch (InvalidDataAccessApiUsageException ex) { + // OK + } + } + + public void testStringQueryWithResults() throws Exception { + String[] dbResults = new String[] { "alpha", "beta", "charlie" }; + + MockControl[] ctrlCountResultSetMetaData = new MockControl[3]; + ResultSetMetaData[] mockCountResultSetMetaData = new ResultSetMetaData[3]; + MockControl[] ctrlCountResultSet = new MockControl[3]; + ResultSet[] mockCountResultSet = new ResultSet[3]; + MockControl[] ctrlCountPreparedStatement = new MockControl[3]; + PreparedStatement[] mockCountPreparedStatement = new PreparedStatement[3]; + + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue(dbResults[0]); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue(dbResults[1]); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(1); + ctrlResultSet.setReturnValue(dbResults[2]); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_FORENAME); + ctrlConnection.setReturnValue(mockPreparedStatement); + + for (int i = 0; i < dbResults.length; i++) { + ctrlCountResultSetMetaData[i] = MockControl.createControl(ResultSetMetaData.class); + mockCountResultSetMetaData[i] = (ResultSetMetaData) ctrlCountResultSetMetaData[i].getMock(); + mockCountResultSetMetaData[i].getColumnCount(); + ctrlCountResultSetMetaData[i].setReturnValue(1); + + ctrlCountResultSet[i] = MockControl.createControl(ResultSet.class); + mockCountResultSet[i] = (ResultSet) ctrlCountResultSet[i].getMock(); + mockCountResultSet[i].getMetaData(); + ctrlCountResultSet[i].setReturnValue(mockCountResultSetMetaData[i]); + mockCountResultSet[i].next(); + ctrlCountResultSet[i].setReturnValue(true); + mockCountResultSet[i].getInt(1); + ctrlCountResultSet[i].setReturnValue(1); + mockCountResultSet[i].wasNull(); + ctrlCountResultSet[i].setReturnValue(false); + mockCountResultSet[i].next(); + ctrlCountResultSet[i].setReturnValue(false); + mockCountResultSet[i].close(); + ctrlCountResultSet[i].setVoidCallable(); + + ctrlCountPreparedStatement[i] = MockControl.createControl(PreparedStatement.class); + mockCountPreparedStatement[i] = (PreparedStatement) ctrlCountPreparedStatement[i].getMock(); + mockCountPreparedStatement[i].executeQuery(); + ctrlCountPreparedStatement[i].setReturnValue(mockCountResultSet[i]); + if (debugEnabled) { + mockCountPreparedStatement[i].getWarnings(); + ctrlCountPreparedStatement[i].setReturnValue(null); + } + mockCountPreparedStatement[i].close(); + ctrlCountPreparedStatement[i].setVoidCallable(); + + mockConnection.prepareStatement( + "SELECT COUNT(FORENAME) FROM CUSTMR WHERE FORENAME='" + dbResults[i] + "'"); + ctrlConnection.setReturnValue(mockCountPreparedStatement[i]); + + ctrlCountResultSetMetaData[i].replay(); + ctrlCountResultSet[i].replay(); + ctrlCountPreparedStatement[i].replay(); + } + + replay(); + + StringQuery query = new StringQuery(mockDataSource, SELECT_FORENAME); + query.setRowsExpected(3); + String[] results = query.run(); + assertTrue("Array is non null", results != null); + assertTrue("Found results", results.length > 0); + assertTrue( + "Found expected number of results", + query.getRowsExpected() == 3); + + JdbcTemplate helper = new JdbcTemplate(mockDataSource); + for (int i = 0; i < results.length; i++) { + // BREAKS ON ' in name + int dbCount = helper.queryForInt( + "SELECT COUNT(FORENAME) FROM CUSTMR WHERE FORENAME='" + results[i] + "'", (Object[]) null); + assertTrue("found in db", dbCount == 1); + } + + for (int i = 0; i < dbResults.length; i++) { + ctrlCountResultSetMetaData[i].verify(); + ctrlCountResultSet[i].verify(); + ctrlCountPreparedStatement[i].verify(); + } + } + + public void testStringQueryWithoutResults() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_FORENAME_EMPTY); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + StringQuery query = new StringQuery(mockDataSource, SELECT_FORENAME_EMPTY); + String[] results = query.run(); + assertTrue("Array is non null", results != null); + assertTrue("Found 0 results", results.length == 0); + } + + public void testFindCustomerIntInt() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_ID_WHERE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_WHERE); + declareParameter(new SqlParameter(Types.NUMERIC)); + declareParameter(new SqlParameter(Types.NUMERIC)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public Customer findCustomer(int id, int otherNum) { + return (Customer) findObject(id, otherNum); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + Customer cust = query.findCustomer(1, 1); + + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue( + "Customer forename was assigned correctly", + cust.getForename().equals("rod")); + } + + public void testFindCustomerString() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setString(1, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_ID_FORENAME_WHERE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE); + declareParameter(new SqlParameter(Types.VARCHAR)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public Customer findCustomer(String id) { + return (Customer) findObject(id); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + Customer cust = query.findCustomer("rod"); + + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); + } + + public void testFindCustomerMixed() throws SQLException { + MockControl ctrlResultSet2; + ResultSet mockResultSet2; + MockControl ctrlPreparedStatement2; + PreparedStatement mockPreparedStatement2; + + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.INTEGER); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + ctrlResultSet2 = MockControl.createControl(ResultSet.class); + mockResultSet2 = (ResultSet) ctrlResultSet2.getMock(); + mockResultSet2.next(); + ctrlResultSet2.setReturnValue(false); + mockResultSet2.close(); + ctrlResultSet2.setVoidCallable(); + + ctrlPreparedStatement2 = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement2 = (PreparedStatement) ctrlPreparedStatement2.getMock(); + mockPreparedStatement2.setObject(1, new Integer(1), Types.INTEGER); + ctrlPreparedStatement2.setVoidCallable(); + mockPreparedStatement2.setString(2, "Roger"); + ctrlPreparedStatement2.setVoidCallable(); + mockPreparedStatement2.executeQuery(); + ctrlPreparedStatement2.setReturnValue(mockResultSet2); + if (debugEnabled) { + mockPreparedStatement2.getWarnings(); + ctrlPreparedStatement2.setReturnValue(null); + } + mockPreparedStatement2.close(); + ctrlPreparedStatement2.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_ID_WHERE); + ctrlConnection.setReturnValue(mockPreparedStatement); + mockConnection.prepareStatement(SELECT_ID_WHERE); + ctrlConnection.setReturnValue(mockPreparedStatement2); + + ctrlResultSet2.replay(); + ctrlPreparedStatement2.replay(); + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_WHERE); + declareParameter( + new SqlParameter(COLUMN_NAMES[0], COLUMN_TYPES[0])); + declareParameter( + new SqlParameter(COLUMN_NAMES[1], COLUMN_TYPES[1])); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public Customer findCustomer(int id, String name) { + return (Customer) findObject( + new Object[] { new Integer(id), name }); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + + Customer cust1 = query.findCustomer(1, "rod"); + assertTrue("Found customer", cust1 != null); + assertTrue("Customer id was assigned correctly", cust1.getId() == 1); + + Customer cust2 = query.findCustomer(1, "Roger"); + assertTrue("No customer found", cust2 == null); + } + + public void testFindTooManyCustomers() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(2); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setString(1, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_ID_FORENAME_WHERE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE); + declareParameter(new SqlParameter(Types.VARCHAR)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public Customer findCustomer(String id) { + return (Customer) findObject(id); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + try { + Customer cust = query.findCustomer("rod"); + fail("Should fail if more than one row found"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // OK + } + } + + public void testListCustomersIntInt() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(2); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("dave"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_ID_WHERE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_WHERE); + declareParameter(new SqlParameter(Types.NUMERIC)); + declareParameter(new SqlParameter(Types.NUMERIC)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + List list = query.execute(1, 1); + assertTrue("2 results in list", list.size() == 2); + for (Iterator itr = list.iterator(); itr.hasNext();) { + Customer cust = (Customer) itr.next(); + } + } + + public void testListCustomersString() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(2); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("dave"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setString(1, "one"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(SELECT_ID_FORENAME_WHERE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE); + declareParameter(new SqlParameter(Types.VARCHAR)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + List list = query.execute("one"); + assertTrue("2 results in list", list.size() == 2); + for (Iterator itr = list.iterator(); itr.hasNext();) { + Customer cust = (Customer) itr.next(); + } + } + + public void testFancyCustomerQuery() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement( + SELECT_ID_FORENAME_WHERE, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE); + setResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + declareParameter(new SqlParameter(Types.NUMERIC)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public Customer findCustomer(int id) { + return (Customer) findObject(id); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + Customer cust = query.findCustomer(1); + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); + } + + public void testUnnamedParameterDeclarationWithNamedParameterQuery() throws SQLException { + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE); + setResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + declareParameter(new SqlParameter(Types.NUMERIC)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public Customer findCustomer(int id) { + Map params = new HashMap(); + params.put("id", new Integer(id)); + return (Customer) executeByNamedParam(params).get(0); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + try { + Customer cust = query.findCustomer(1); + fail("Query should not succeed since parameter declaration did not specify parameter name"); + } + catch (InvalidDataAccessApiUsageException ex) { + // OK - it worked + } + } + + public void testNamedParameterCustomerQueryWithUnnamedDeclarations() throws SQLException { + doTestNamedParameterCustomerQuery(false); + } + + public void testNamedParameterCustomerQueryWithNamedDeclarations() throws SQLException { + doTestNamedParameterCustomerQuery(true); + } + + private void doTestNamedParameterCustomerQuery(final boolean namedDeclarations) throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setString(2, "UK"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement( + SELECT_ID_FORENAME_NAMED_PARAMETERS_PARSED, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_NAMED_PARAMETERS); + setResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + if (namedDeclarations) { + declareParameter(new SqlParameter("country", Types.VARCHAR)); + declareParameter(new SqlParameter("id", Types.NUMERIC)); + } + else { + declareParameter(new SqlParameter(Types.NUMERIC)); + declareParameter(new SqlParameter(Types.VARCHAR)); + } + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public Customer findCustomer(int id, String country) { + Map params = new HashMap(); + params.put("id", new Integer(id)); + params.put("country", country); + return (Customer) executeByNamedParam(params).get(0); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + Customer cust = query.findCustomer(1, "UK"); + assertTrue("Customer id was assigned correctly", cust.getId() == 1); + assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); + } + + public void testNamedParameterInListQuery() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(2); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("juergen"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(2), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement( + SELECT_ID_FORENAME_WHERE_ID_IN_LIST_1, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE_ID_IN_LIST_2); + setResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + declareParameter(new SqlParameter("ids", Types.NUMERIC)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public List findCustomers(List ids) { + Map params = new HashMap(); + params.put("ids", ids); + return (List) executeByNamedParam(params); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + List ids = new ArrayList(); + ids.add(new Integer(1)); + ids.add(new Integer(2)); + List cust = query.findCustomers(ids); + + assertEquals("We got two customers back", cust.size(), 2); + assertEquals("First customer id was assigned correctly", ((Customer)cust.get(0)).getId(), 1); + assertEquals("First customer forename was assigned correctly", ((Customer)cust.get(0)).getForename(), "rod"); + assertEquals("Second customer id was assigned correctly", ((Customer)cust.get(1)).getId(), 2); + assertEquals("Second customer forename was assigned correctly", ((Customer)cust.get(1)).getForename(), "juergen"); + } + + public void testNamedParameterQueryReusingParameter() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("rod"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(2); + mockResultSet.getString("forename"); + ctrlResultSet.setReturnValue("juergen"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.setObject(2, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement( + SELECT_ID_FORENAME_WHERE_ID_REUSED_1, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE_ID_REUSED_2); + setResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + declareParameter(new SqlParameter("id1", Types.NUMERIC)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public List findCustomers(Integer id) { + Map params = new HashMap(); + params.put("id1", id); + return (List) executeByNamedParam(params); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + List cust = query.findCustomers(new Integer(1)); + + assertEquals("We got two customers back", cust.size(), 2); + assertEquals("First customer id was assigned correctly", ((Customer)cust.get(0)).getId(), 1); + assertEquals("First customer forename was assigned correctly", ((Customer)cust.get(0)).getForename(), "rod"); + assertEquals("Second customer id was assigned correctly", ((Customer)cust.get(1)).getId(), 2); + assertEquals("Second customer forename was assigned correctly", ((Customer)cust.get(1)).getForename(), "juergen"); + } + + public void testNamedParameterUsingInvalidQuestionMarkPlaceHolders() throws SQLException { + + mockConnection.prepareStatement( + SELECT_ID_FORENAME_WHERE_ID_REUSED_1, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerQuery extends MappingSqlQuery { + + public CustomerQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE_ID_REUSED_1); + setResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + declareParameter(new SqlParameter("id1", Types.NUMERIC)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; + } + + public List findCustomers(Integer id1) { + Map params = new HashMap(); + params.put("id1", id1); + return (List) executeByNamedParam(params); + } + } + + CustomerQuery query = new CustomerQuery(mockDataSource); + try { + List cust = query.findCustomers(new Integer(1)); + fail("Should have caused an InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException e){ + } + + } + + public void testUpdateCustomers() throws SQLException { + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(1); + mockResultSet.updateString(2, "Rod"); + ctrlResultSet.setVoidCallable(); + mockResultSet.updateRow(); + ctrlResultSet.setVoidCallable(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getInt("id"); + ctrlResultSet.setReturnValue(2); + mockResultSet.updateString(2, "Thomas"); + ctrlResultSet.setVoidCallable(); + mockResultSet.updateRow(); + ctrlResultSet.setVoidCallable(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setObject(1, new Integer(2), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeQuery(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement( + SELECT_ID_FORENAME_WHERE_ID, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class CustomerUpdateQuery extends UpdatableSqlQuery { + + public CustomerUpdateQuery(DataSource ds) { + super(ds, SELECT_ID_FORENAME_WHERE_ID); + declareParameter(new SqlParameter(Types.NUMERIC)); + compile(); + } + + protected Object updateRow(ResultSet rs, int rownum, Map context) throws SQLException { + rs.updateString(2, "" + context.get(new Integer(rs.getInt(COLUMN_NAMES[0])))); + return null; + } + } + CustomerUpdateQuery query = new CustomerUpdateQuery(mockDataSource); + Map values = new HashMap(2); + values.put(new Integer(1), "Rod"); + values.put(new Integer(2), "Thomas"); + List customers = query.execute(2, values); + } + + + private static class StringQuery extends MappingSqlQuery { + + public StringQuery(DataSource ds, String sql) { + super(ds, sql); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) throws SQLException { + return rs.getString(1); + } + + public String[] run() { + List list = execute(); + String[] results = (String[]) list.toArray(new String[list.size()]); + return results; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlUpdateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlUpdateTests.java new file mode 100644 index 00000000000..9493b5fbbf8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/SqlUpdateTests.java @@ -0,0 +1,585 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.Map; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.core.JdkVersion; +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; + +/** + * @author Trevor Cook + * @author Thomas Risberg + * @author Juergen Hoeller + */ +public class SqlUpdateTests extends AbstractJdbcTests { + + private static final String UPDATE = + "update seat_status set booking_id = null"; + private static final String UPDATE_INT = + "update seat_status set booking_id = null where performance_id = ?"; + private static final String UPDATE_INT_INT = + "update seat_status set booking_id = null where performance_id = ? and price_band_id = ?"; + private static final String UPDATE_NAMED_PARAMETERS = + "update seat_status set booking_id = null where performance_id = :perfId and price_band_id = :priceId"; + private static final String UPDATE_STRING = + "update seat_status set booking_id = null where name = ?"; + private static final String UPDATE_OBJECTS = + "update seat_status set booking_id = null where performance_id = ? and price_band_id = ? and name = ? and confirmed = ?"; + private static final String INSERT_GENERATE_KEYS = + "insert into show (name) values(?)"; + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl ctrlPreparedStatement; + private PreparedStatement mockPreparedStatement; + private MockControl ctrlResultSet; + private ResultSet mockResultSet; + private MockControl ctrlResultSetMetaData; + private ResultSetMetaData mockResultSetMetaData; + + + protected void setUp() throws Exception { + super.setUp(); + ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class); + mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (shouldVerify()) { + ctrlPreparedStatement.verify(); + } + } + + protected void replay() { + super.replay(); + ctrlPreparedStatement.replay(); + } + + + public void testUpdate() throws SQLException { + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + Updater pc = new Updater(); + int rowsAffected = pc.run(); + assertEquals(1, rowsAffected); + } + + public void testUpdateInt() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_INT); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + IntUpdater pc = new IntUpdater(); + int rowsAffected = pc.run(1); + assertEquals(1, rowsAffected); + } + + public void testUpdateIntInt() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + mockPreparedStatement.setObject(2, new Integer(1), Types.NUMERIC); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_INT_INT); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + IntIntUpdater pc = new IntIntUpdater(); + int rowsAffected = pc.run(1, 1); + assertEquals(1, rowsAffected); + } + + public void testNamedParameterUpdateWithUnnamedDeclarations() throws SQLException { + doTestNamedParameterUpdate(false); + } + + public void testNamedParameterUpdateWithNamedDeclarations() throws SQLException { + doTestNamedParameterUpdate(true); + } + + private void doTestNamedParameterUpdate(final boolean namedDeclarations) throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + mockPreparedStatement.setObject(2, new Integer(1), Types.DECIMAL); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_INT_INT); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + class NamedParameterUpdater extends SqlUpdate { + + public NamedParameterUpdater() { + setSql(UPDATE_NAMED_PARAMETERS); + setDataSource(mockDataSource); + if (namedDeclarations) { + declareParameter(new SqlParameter("priceId", Types.DECIMAL)); + declareParameter(new SqlParameter("perfId", Types.NUMERIC)); + } + else { + declareParameter(new SqlParameter(Types.NUMERIC)); + declareParameter(new SqlParameter(Types.DECIMAL)); + } + compile(); + } + + public int run(int performanceId, int type) { + Map params = new HashMap(); + params.put("perfId", new Integer(performanceId)); + params.put("priceId", new Integer(type)); + return updateByNamedParam(params); + } + } + + NamedParameterUpdater pc = new NamedParameterUpdater(); + int rowsAffected = pc.run(1, 1); + assertEquals(1, rowsAffected); + } + + public void testUpdateString() throws SQLException { + mockPreparedStatement.setString(1, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_STRING); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + StringUpdater pc = new StringUpdater(); + int rowsAffected = pc.run("rod"); + assertEquals(1, rowsAffected); + } + + public void testUpdateMixed() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + mockPreparedStatement.setObject(2, new Integer(1), Types.NUMERIC, 2); + mockPreparedStatement.setString(3, "rod"); + mockPreparedStatement.setObject(4, Boolean.TRUE, Types.BOOLEAN); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_OBJECTS); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + MixedUpdater pc = new MixedUpdater(); + int rowsAffected = pc.run(1, 1, "rod", true); + assertEquals(1, rowsAffected); + } + + public void testUpdateAndGeneratedKeys() throws SQLException { + ctrlResultSetMetaData = MockControl.createControl(ResultSetMetaData.class); + mockResultSetMetaData = (ResultSetMetaData) ctrlResultSetMetaData.getMock(); + mockResultSetMetaData.getColumnCount(); + ctrlResultSetMetaData.setReturnValue(1); + mockResultSetMetaData.getColumnLabel(1); + ctrlResultSetMetaData.setReturnValue("1", 2); + + ctrlResultSet = MockControl.createControl(ResultSet.class); + mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.getMetaData(); + ctrlResultSet.setReturnValue(mockResultSetMetaData); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getObject(1); + ctrlResultSet.setReturnValue(new Integer(11)); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockPreparedStatement.setString(1, "rod"); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + mockPreparedStatement.getGeneratedKeys(); + ctrlPreparedStatement.setReturnValue(mockResultSet); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(INSERT_GENERATE_KEYS, PreparedStatement.RETURN_GENERATED_KEYS); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + ctrlResultSet.replay(); + ctrlResultSetMetaData.replay(); + + GeneratedKeysUpdater pc = new GeneratedKeysUpdater(); + KeyHolder generatedKeyHolder = new GeneratedKeyHolder(); + int rowsAffected = pc.run("rod", generatedKeyHolder); + assertEquals(1, rowsAffected); + assertEquals(1, generatedKeyHolder.getKeyList().size()); + assertEquals(11, generatedKeyHolder.getKey().intValue()); + } + + public void testUpdateConstructor() throws SQLException { + mockPreparedStatement.setObject(1, new Integer(1), Types.NUMERIC); + mockPreparedStatement.setObject(2, new Integer(1), Types.NUMERIC); + mockPreparedStatement.setString(3, "rod"); + mockPreparedStatement.setObject(4, Boolean.TRUE, Types.BOOLEAN); + ctrlPreparedStatement.setVoidCallable(); + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(1); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE_OBJECTS); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + ConstructorUpdater pc = new ConstructorUpdater(); + int rowsAffected = pc.run(1, 1, "rod", true); + assertEquals(1, rowsAffected); + } + + public void testUnderMaxRows() throws SQLException { + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(3); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + MaxRowsUpdater pc = new MaxRowsUpdater(); + int rowsAffected = pc.run(); + assertEquals(3, rowsAffected); + } + + public void testMaxRows() throws SQLException { + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(5); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + MaxRowsUpdater pc = new MaxRowsUpdater(); + int rowsAffected = pc.run(); + assertEquals(5, rowsAffected); + } + + public void testOverMaxRows() throws SQLException { + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(8); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + MaxRowsUpdater pc = new MaxRowsUpdater(); + try { + int rowsAffected = pc.run(); + fail("Shouldn't continue when too many rows affected"); + } + catch (JdbcUpdateAffectedIncorrectNumberOfRowsException juaicrex) { + // OK + } + } + + public void testRequiredRows() throws SQLException { + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(3); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + RequiredRowsUpdater pc = new RequiredRowsUpdater(); + int rowsAffected = pc.run(); + assertEquals(3, rowsAffected); + } + + public void testNotRequiredRows() throws SQLException { + mockPreparedStatement.executeUpdate(); + ctrlPreparedStatement.setReturnValue(2); + if (debugEnabled) { + mockPreparedStatement.getWarnings(); + ctrlPreparedStatement.setReturnValue(null); + } + mockPreparedStatement.close(); + ctrlPreparedStatement.setVoidCallable(); + + mockConnection.prepareStatement(UPDATE); + ctrlConnection.setReturnValue(mockPreparedStatement); + + replay(); + + RequiredRowsUpdater pc = new RequiredRowsUpdater(); + try { + int rowsAffected = pc.run(); + fail("Shouldn't continue when too many rows affected"); + } + catch (JdbcUpdateAffectedIncorrectNumberOfRowsException juaicrex) { + // OK + } + } + + + private class Updater extends SqlUpdate { + + public Updater() { + setSql(UPDATE); + setDataSource(mockDataSource); + compile(); + } + + public int run() { + return update(); + } + } + + + private class IntUpdater extends SqlUpdate { + + public IntUpdater() { + setSql(UPDATE_INT); + setDataSource(mockDataSource); + declareParameter(new SqlParameter(Types.NUMERIC)); + compile(); + } + + public int run(int performanceId) { + return update(performanceId); + } + } + + + private class IntIntUpdater extends SqlUpdate { + + public IntIntUpdater() { + setSql(UPDATE_INT_INT); + setDataSource(mockDataSource); + declareParameter(new SqlParameter(Types.NUMERIC)); + declareParameter(new SqlParameter(Types.NUMERIC)); + compile(); + } + + public int run(int performanceId, int type) { + return update(performanceId, type); + } + } + + + private class StringUpdater extends SqlUpdate { + + public StringUpdater() { + setSql(UPDATE_STRING); + setDataSource(mockDataSource); + declareParameter(new SqlParameter(Types.VARCHAR)); + compile(); + } + + public int run(String name) { + return update(name); + } + } + + + private class MixedUpdater extends SqlUpdate { + + public MixedUpdater() { + setSql(UPDATE_OBJECTS); + setDataSource(mockDataSource); + declareParameter(new SqlParameter(Types.NUMERIC)); + declareParameter(new SqlParameter(Types.NUMERIC, 2)); + declareParameter(new SqlParameter(Types.VARCHAR)); + declareParameter(new SqlParameter(Types.BOOLEAN)); + compile(); + } + + public int run(int performanceId, int type, String name, boolean confirmed) { + Object[] params = + new Object[] {new Integer(performanceId), new Integer(type), name, + new Boolean(confirmed)}; + return update(params); + } + } + + + private class GeneratedKeysUpdater extends SqlUpdate { + + public GeneratedKeysUpdater() { + setSql(INSERT_GENERATE_KEYS); + setDataSource(mockDataSource); + declareParameter(new SqlParameter(Types.VARCHAR)); + setReturnGeneratedKeys(true); + compile(); + } + + public int run(String name, KeyHolder generatedKeyHolder) { + Object[] params = new Object[] {name}; + return update(params, generatedKeyHolder); + } + } + + + private class ConstructorUpdater extends SqlUpdate { + + public ConstructorUpdater() { + super(mockDataSource, UPDATE_OBJECTS, + new int[] {Types.NUMERIC, Types.NUMERIC, Types.VARCHAR, Types.BOOLEAN }); + compile(); + } + + public int run(int performanceId, int type, String name, boolean confirmed) { + Object[] params = + new Object[] { + new Integer(performanceId), new Integer(type), name, new Boolean(confirmed)}; + return update(params); + } + } + + + private class MaxRowsUpdater extends SqlUpdate { + + public MaxRowsUpdater() { + setSql(UPDATE); + setDataSource(mockDataSource); + setMaxRowsAffected(5); + compile(); + } + + public int run() { + return update(); + } + } + + + private class RequiredRowsUpdater extends SqlUpdate { + + public RequiredRowsUpdater() { + setSql(UPDATE); + setDataSource(mockDataSource); + setRequiredRowsAffected(3); + compile(); + } + + public int run() { + return update(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/StoredProcedureTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/StoredProcedureTests.java new file mode 100644 index 00000000000..29d4a751876 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/object/StoredProcedureTests.java @@ -0,0 +1,1005 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.sql.ResultSetMetaData; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.math.BigDecimal; + +import javax.sql.DataSource; + +import org.easymock.MockControl; +import org.apache.commons.logging.LogFactory; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.core.CallableStatementCreator; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ParameterMapper; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.SimpleRowCountCallbackHandler; +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.SqlReturnResultSet; +import org.springframework.jdbc.core.support.AbstractSqlTypeValue; +import org.springframework.jdbc.datasource.ConnectionHolder; +import org.springframework.jdbc.support.SQLExceptionTranslator; +import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Thomas Risberg + * @author Trevor Cook + * @author Rod Johnson + */ +public class StoredProcedureTests extends AbstractJdbcTests { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private MockControl ctrlCallable; + private CallableStatement mockCallable; + + protected void setUp() throws Exception { + super.setUp(); + + ctrlCallable = MockControl.createControl(CallableStatement.class); + mockCallable = (CallableStatement) ctrlCallable.getMock(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (shouldVerify()) { + ctrlCallable.verify(); + } + } + + protected void replay() { + super.replay(); + ctrlCallable.replay(); + } + + public void testNoSuchStoredProcedure() throws Exception { + SQLException sex = + new SQLException( + "Syntax error or access violation exception", + "42000"); + mockCallable.execute(); + ctrlCallable.setThrowable(sex); + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call " + NoSuchStoredProcedure.SQL + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + NoSuchStoredProcedure sproc = new NoSuchStoredProcedure(mockDataSource); + try { + sproc.execute(); + fail("Shouldn't succeed in running stored procedure which doesn't exist"); + } catch (BadSqlGrammarException ex) { + // OK + } + } + + private void testAddInvoice(final int amount, final int custid) + throws Exception { + AddInvoice adder = new AddInvoice(mockDataSource); + int id = adder.execute(amount, custid); + assertEquals(4, id); + } + + public void testAddInvoices() throws Exception { + mockCallable.setObject(1, new Integer(1106), Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(2, new Integer(3), Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.registerOutParameter(3, Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(3); + ctrlCallable.setReturnValue(new Integer(4)); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + AddInvoice.SQL + "(?, ?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + testAddInvoice(1106, 3); + } + + public void testAddInvoicesWithinTransaction() throws Exception { + mockCallable.setObject(1, new Integer(1106), Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.setObject(2, new Integer(3), Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.registerOutParameter(3, Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(3); + ctrlCallable.setReturnValue(new Integer(4)); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + AddInvoice.SQL + "(?, ?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + TransactionSynchronizationManager.bindResource( + mockDataSource, + new ConnectionHolder(mockConnection)); + + try { + testAddInvoice(1106, 3); + } + finally { + TransactionSynchronizationManager.unbindResource(mockDataSource); + } + } + + + /** + * Confirm no connection was used to get metadata. + * Does not use superclass replay mechanism. + * @throws Exception + */ + public void testStoredProcedureConfiguredViaJdbcTemplateWithCustomExceptionTranslator() throws Exception { + mockCallable.setObject(1, new Integer(11), Types.INTEGER); + ctrlCallable.setVoidCallable(1); + mockCallable.registerOutParameter(2, Types.INTEGER); + ctrlCallable.setVoidCallable(1); + mockCallable.execute(); + ctrlCallable.setReturnValue(false, 1); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(2); + ctrlCallable.setReturnValue(new Integer(5), 1); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(1); + // Must call this here as we're not using setUp()/tearDown() mechanism + ctrlCallable.replay(); + + ctrlConnection = MockControl.createControl(Connection.class); + mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.prepareCall("{call " + StoredProcedureConfiguredViaJdbcTemplate.SQL + "(?, ?)}"); + ctrlConnection.setReturnValue(mockCallable, 1); + mockConnection.close(); + ctrlConnection.setVoidCallable(1); + ctrlConnection.replay(); + + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource localDs = (DataSource) dsControl.getMock(); + localDs.getConnection(); + dsControl.setReturnValue(mockConnection, 1); + dsControl.replay(); + + class TestJdbcTemplate extends JdbcTemplate { + int calls; + public Map call(CallableStatementCreator csc, List declaredParameters) throws DataAccessException { + calls++; + return super.call(csc, declaredParameters); + } + + } + TestJdbcTemplate t = new TestJdbcTemplate(); + t.setDataSource(localDs); + // Will fail without the following, because we're not able to get a connection from the + // DataSource here if we need to to create an ExceptionTranslator + t.setExceptionTranslator(new SQLStateSQLExceptionTranslator()); + StoredProcedureConfiguredViaJdbcTemplate sp = new StoredProcedureConfiguredViaJdbcTemplate(t); + + assertEquals(sp.execute(11), 5); + assertEquals(1, t.calls); + + dsControl.verify(); + ctrlCallable.verify(); + ctrlConnection.verify(); + } + + /** + * Confirm our JdbcTemplate is used + * @throws Exception + */ + public void testStoredProcedureConfiguredViaJdbcTemplate() throws Exception { + mockCallable.setObject(1, new Integer(1106), Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.registerOutParameter(2, Types.INTEGER); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(2); + ctrlCallable.setReturnValue(new Integer(4)); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + StoredProcedureConfiguredViaJdbcTemplate.SQL + "(?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + JdbcTemplate t = new JdbcTemplate(); + t.setDataSource(mockDataSource); + StoredProcedureConfiguredViaJdbcTemplate sp = new StoredProcedureConfiguredViaJdbcTemplate(t); + + assertEquals(sp.execute(1106), 4); + } + + public void testNullArg() throws Exception { + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + + mockCallable.setNull(1, Types.VARCHAR); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + NullArg.SQL + "(?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + ctrlResultSet.replay(); + + NullArg na = new NullArg(mockDataSource); + na.execute((String) null); + } + + public void testUnnamedParameter() throws Exception { + replay(); + try { + UnnamedParameterStoredProcedure unp = + new UnnamedParameterStoredProcedure(mockDataSource); + fail("Shouldn't succeed in creating stored procedure with unnamed parameter"); + } catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testMissingParameter() throws Exception { + replay(); + + try { + MissingParameterStoredProcedure mp = + new MissingParameterStoredProcedure(mockDataSource); + mp.execute(); + fail("Shouldn't succeed in running stored procedure with missing required parameter"); + } catch (InvalidDataAccessApiUsageException idaauex) { + // OK + } + } + + public void testStoredProcedureExceptionTranslator() throws Exception { + SQLException sex = + new SQLException( + "Syntax error or access violation exception", + "42000"); + mockCallable.execute(); + ctrlCallable.setThrowable(sex); + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call " + StoredProcedureExceptionTranslator.SQL + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + StoredProcedureExceptionTranslator sproc = + new StoredProcedureExceptionTranslator(mockDataSource); + try { + sproc.execute(); + fail("Custom exception should be thrown"); + } catch (CustomDataException ex) { + // OK + } + } + + public void testStoredProcedureWithResultSet() throws Exception { + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockCallable.execute(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getResultSet(); + ctrlCallable.setReturnValue(mockResultSet); + mockCallable.getMoreResults(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + StoredProcedureWithResultSet.SQL + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + ctrlResultSet.replay(); + + StoredProcedureWithResultSet sproc = new StoredProcedureWithResultSet(mockDataSource); + sproc.execute(); + + ctrlResultSet.verify(); + assertEquals(2, sproc.getCount()); + } + + public void testStoredProcedureWithResultSetMapped() throws Exception { + MockControl ctrlResultSet = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet = (ResultSet) ctrlResultSet.getMock(); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(2); + ctrlResultSet.setReturnValue("Foo"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(true); + mockResultSet.getString(2); + ctrlResultSet.setReturnValue("Bar"); + mockResultSet.next(); + ctrlResultSet.setReturnValue(false); + mockResultSet.close(); + ctrlResultSet.setVoidCallable(); + + mockCallable.execute(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getResultSet(); + ctrlCallable.setReturnValue(mockResultSet); + mockCallable.getMoreResults(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + ctrlResultSet.replay(); + + StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(mockDataSource); + Map res = sproc.execute(); + + ctrlResultSet.verify(); + + List rs = (List) res.get("rs"); + assertEquals(2, rs.size()); + assertEquals("Foo", rs.get(0)); + assertEquals("Bar", rs.get(1)); + + } + + public void testStoredProcedureWithUndeclaredResults() throws Exception { + MockControl ctrlResultSet1 = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet1 = (ResultSet) ctrlResultSet1.getMock(); + mockResultSet1.next(); + ctrlResultSet1.setReturnValue(true); + mockResultSet1.getString(2); + ctrlResultSet1.setReturnValue("Foo"); + mockResultSet1.next(); + ctrlResultSet1.setReturnValue(true); + mockResultSet1.getString(2); + ctrlResultSet1.setReturnValue("Bar"); + mockResultSet1.next(); + ctrlResultSet1.setReturnValue(false); + mockResultSet1.close(); + ctrlResultSet1.setVoidCallable(); + + MockControl ctrlMetaData = MockControl.createControl(ResultSetMetaData.class); + ResultSetMetaData mockMetaData = (ResultSetMetaData) ctrlMetaData.getMock(); + mockMetaData.getColumnCount(); + ctrlMetaData.setReturnValue(2); + mockMetaData.getColumnLabel(1); + ctrlMetaData.setReturnValue("spam"); + mockMetaData.getColumnLabel(2); + ctrlMetaData.setReturnValue("eggs"); + + MockControl ctrlResultSet2 = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet2 = (ResultSet) ctrlResultSet2.getMock(); + mockResultSet2.getMetaData(); + ctrlResultSet2.setReturnValue(mockMetaData); + mockResultSet2.next(); + ctrlResultSet2.setReturnValue(true); + mockResultSet2.getObject(1); + ctrlResultSet2.setReturnValue("Spam"); + mockResultSet2.getObject(2); + ctrlResultSet2.setReturnValue("Eggs"); + mockResultSet2.next(); + ctrlResultSet2.setReturnValue(false); + mockResultSet2.close(); + ctrlResultSet2.setVoidCallable(); + + mockCallable.execute(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getResultSet(); + ctrlCallable.setReturnValue(mockResultSet1); + mockCallable.getMoreResults(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getResultSet(); + ctrlCallable.setReturnValue(mockResultSet2); + mockCallable.getMoreResults(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(0); + mockCallable.getMoreResults(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + ctrlResultSet1.replay(); + ctrlMetaData.replay(); + ctrlResultSet2.replay(); + + StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(mockDataSource); + Map res = sproc.execute(); + + ctrlResultSet1.verify(); + ctrlResultSet2.verify(); + + assertEquals("incorrect number of returns", 3, res.size()); + + List rs1 = (List) res.get("rs"); + assertEquals(2, rs1.size()); + assertEquals("Foo", rs1.get(0)); + assertEquals("Bar", rs1.get(1)); + + List rs2 = (List) res.get("#result-set-2"); + assertEquals(1, rs2.size()); + Object o2 = rs2.get(0); + assertTrue("wron type returned for result set 2", o2 instanceof Map); + Map m2 = (Map) o2; + assertEquals("Spam", m2.get("spam")); + assertEquals("Eggs", m2.get("eggs")); + + Number n = (Number) res.get("#update-count-1"); + assertEquals("wrong update count", 0, n.intValue()); + } + + public void testStoredProcedureSkippingResultsProcessing() throws Exception { + mockCallable.execute(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + JdbcTemplate jdbcTemplate = new JdbcTemplate(mockDataSource); + jdbcTemplate.setSkipResultsProcessing(true); + StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(jdbcTemplate); + Map res = sproc.execute(); + + assertEquals("incorrect number of returns", 0, res.size()); + } + + public void testStoredProcedureSkippingUndeclaredResults() throws Exception { + MockControl ctrlResultSet1 = MockControl.createControl(ResultSet.class); + ResultSet mockResultSet1 = (ResultSet) ctrlResultSet1.getMock(); + mockResultSet1.next(); + ctrlResultSet1.setReturnValue(true); + mockResultSet1.getString(2); + ctrlResultSet1.setReturnValue("Foo"); + mockResultSet1.next(); + ctrlResultSet1.setReturnValue(true); + mockResultSet1.getString(2); + ctrlResultSet1.setReturnValue("Bar"); + mockResultSet1.next(); + ctrlResultSet1.setReturnValue(false); + mockResultSet1.close(); + ctrlResultSet1.setVoidCallable(); + + mockCallable.execute(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getResultSet(); + ctrlCallable.setReturnValue(mockResultSet1); + mockCallable.getMoreResults(); + ctrlCallable.setReturnValue(true); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getMoreResults(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + ctrlResultSet1.replay(); + + JdbcTemplate jdbcTemplate = new JdbcTemplate(mockDataSource); + jdbcTemplate.setSkipUndeclaredResults(true); + StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(jdbcTemplate); + Map res = sproc.execute(); + + ctrlResultSet1.verify(); + + assertEquals("incorrect number of returns", 1, res.size()); + + List rs1 = (List) res.get("rs"); + assertEquals(2, rs1.size()); + assertEquals("Foo", rs1.get(0)); + assertEquals("Bar", rs1.get(1)); + } + + public void testParameterMapper() throws Exception { + mockCallable.setString(1, "EasyMock for interface java.sql.Connection"); + ctrlCallable.setVoidCallable(); + mockCallable.registerOutParameter(2, Types.VARCHAR); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(2); + ctrlCallable.setReturnValue("OK"); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call " + ParameterMapperStoredProcedure.SQL + "(?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + ParameterMapperStoredProcedure pmsp = new ParameterMapperStoredProcedure(mockDataSource); + Map out = pmsp.executeTest(); + assertEquals("OK", out.get("out")); + } + + public void testSqlTypeValue() throws Exception { + int[] testVal = new int[] {1, 2}; + mockCallable.getConnection(); + ctrlCallable.setDefaultReturnValue(mockConnection); + mockCallable.setObject(1, testVal, Types.ARRAY); + ctrlCallable.setVoidCallable(); + mockCallable.registerOutParameter(2, Types.VARCHAR); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(2); + ctrlCallable.setReturnValue("OK"); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call " + SqlTypeValueStoredProcedure.SQL + "(?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + SqlTypeValueStoredProcedure stvsp = new SqlTypeValueStoredProcedure(mockDataSource); + Map out = stvsp.executeTest(testVal); + assertEquals("OK", out.get("out")); + } + + public void testNumericWithScale() throws Exception { + mockCallable.getConnection(); + ctrlCallable.setDefaultReturnValue(mockConnection); + mockCallable.registerOutParameter(1, Types.DECIMAL, 4); + ctrlCallable.setVoidCallable(); + mockCallable.execute(); + ctrlCallable.setReturnValue(false); + mockCallable.getUpdateCount(); + ctrlCallable.setReturnValue(-1); + mockCallable.getObject(1); + ctrlCallable.setReturnValue(new BigDecimal("12345.6789")); + if (debugEnabled) { + mockCallable.getWarnings(); + ctrlCallable.setReturnValue(null); + } + mockCallable.close(); + ctrlCallable.setVoidCallable(); + + mockConnection.prepareCall( + "{call " + NumericWithScaleStoredProcedure.SQL + "(?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + NumericWithScaleStoredProcedure nwssp = new NumericWithScaleStoredProcedure(mockDataSource); + Map out = nwssp.executeTest(); + assertEquals(new BigDecimal("12345.6789"), out.get("out")); + } + + + private static class StoredProcedureConfiguredViaJdbcTemplate extends StoredProcedure { + + public static final String SQL = "configured_via_jt"; + + public StoredProcedureConfiguredViaJdbcTemplate(JdbcTemplate t) { + setJdbcTemplate(t); + setSql(SQL); + declareParameter(new SqlParameter("intIn", Types.INTEGER)); + declareParameter(new SqlOutParameter("intOut", Types.INTEGER)); + compile(); + } + + public int execute(int intIn) { + Map in = new HashMap(); + in.put("intIn", new Integer(intIn)); + Map out = execute(in); + Number intOut = (Number) out.get("intOut"); + return intOut.intValue(); + } + } + + + private static class AddInvoice extends StoredProcedure { + + public static final String SQL = "add_invoice"; + + public AddInvoice(DataSource ds) { + setDataSource(ds); + setSql(SQL); + declareParameter(new SqlParameter("amount", Types.INTEGER)); + declareParameter(new SqlParameter("custid", Types.INTEGER)); + declareParameter(new SqlOutParameter("newid", Types.INTEGER)); + compile(); + } + + public int execute(int amount, int custid) { + Map in = new HashMap(); + in.put("amount", new Integer(amount)); + in.put("custid", new Integer(custid)); + Map out = execute(in); + Number id = (Number) out.get("newid"); + return id.intValue(); + } + } + + + private static class NullArg extends StoredProcedure { + + public static final String SQL = "takes_null"; + + public NullArg(DataSource ds) { + setDataSource(ds); + setSql(SQL); + declareParameter(new SqlParameter("ptest", Types.VARCHAR)); + compile(); + } + + public void execute(String s) { + Map in = new HashMap(); + in.put("ptest", s); + Map out = execute(in); + } + } + + + private static class NoSuchStoredProcedure extends StoredProcedure { + + public static final String SQL = "no_sproc_with_this_name"; + + public NoSuchStoredProcedure(DataSource ds) { + setDataSource(ds); + setSql(SQL); + compile(); + } + + public void execute() { + execute(new HashMap()); + } + } + + + private static class UnnamedParameterStoredProcedure extends StoredProcedure { + + public UnnamedParameterStoredProcedure(DataSource ds) { + super(ds, "unnamed_parameter_sp"); + declareParameter(new SqlParameter(Types.INTEGER)); + compile(); + } + + public void execute(int id) { + Map in = new HashMap(); + in.put("id", new Integer(id)); + Map out = execute(in); + } + } + + + private static class MissingParameterStoredProcedure extends StoredProcedure { + + public MissingParameterStoredProcedure(DataSource ds) { + setDataSource(ds); + setSql("takes_string"); + declareParameter(new SqlParameter("mystring", Types.VARCHAR)); + compile(); + } + + public void execute() { + execute(new HashMap()); + } + } + + + private static class StoredProcedureWithResultSet extends StoredProcedure { + + public static final String SQL = "sproc_with_result_set"; + + private final SimpleRowCountCallbackHandler handler = new SimpleRowCountCallbackHandler(); + + public StoredProcedureWithResultSet(DataSource ds) { + setDataSource(ds); + setSql(SQL); + declareParameter(new SqlReturnResultSet("rs", this.handler)); + compile(); + } + + public void execute() { + execute(new HashMap()); + } + + public int getCount() { + return this.handler.getCount(); + } + } + + + private static class StoredProcedureWithResultSetMapped extends StoredProcedure { + + public static final String SQL = "sproc_with_result_set"; + + public StoredProcedureWithResultSetMapped(DataSource ds) { + setDataSource(ds); + setSql(SQL); + declareParameter( + new SqlReturnResultSet("rs", new RowMapperImpl())); + compile(); + } + + public StoredProcedureWithResultSetMapped(JdbcTemplate jt) { + setJdbcTemplate(jt); + setSql(SQL); + declareParameter( + new SqlReturnResultSet("rs", new RowMapperImpl())); + compile(); + } + + public Map execute() { + Map out = execute(new HashMap()); + return out; + } + + private static class RowMapperImpl implements RowMapper { + public Object mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getString(2); + } + } + } + + + private static class ParameterMapperStoredProcedure extends StoredProcedure { + + public static final String SQL = "parameter_mapper_sp"; + + public ParameterMapperStoredProcedure(DataSource ds) { + setDataSource(ds); + setSql(SQL); + declareParameter(new SqlParameter("in", Types.VARCHAR)); + declareParameter(new SqlOutParameter("out", Types.VARCHAR)); + compile(); + } + + public Map executeTest() { + Map out = null; + out = execute(new TestParameterMapper()); + return out; + } + + private static class TestParameterMapper implements ParameterMapper { + + private TestParameterMapper() { + } + + public Map createMap(Connection conn) throws SQLException { + Map inParms = new HashMap(); + String testValue = conn.toString(); + inParms.put("in", testValue); + return inParms; + } + } + } + + + private static class SqlTypeValueStoredProcedure extends StoredProcedure { + + public static final String SQL = "sql_type_value_sp"; + + public SqlTypeValueStoredProcedure(DataSource ds) { + setDataSource(ds); + setSql(SQL); + declareParameter(new SqlParameter("in", Types.ARRAY, "NUMBERS")); + declareParameter(new SqlOutParameter("out", Types.VARCHAR)); + compile(); + } + + public Map executeTest(final int[] inValue) { + Map in = new HashMap(1); + in.put("in", new AbstractSqlTypeValue() { + public Object createTypeValue(Connection con, int type, String typeName) { + //assertEquals(Connection.class, con.getClass()); + //assertEquals(Types.ARRAY, type); + //assertEquals("NUMBER", typeName); + return inValue; + } + }); + Map out = null; + out = execute(in); + return out; + } + } + + private static class NumericWithScaleStoredProcedure extends StoredProcedure { + + public static final String SQL = "numeric_with_scale_sp"; + + public NumericWithScaleStoredProcedure(DataSource ds) { + setDataSource(ds); + setSql(SQL); + declareParameter(new SqlOutParameter("out", Types.DECIMAL, 4)); + compile(); + } + + public Map executeTest() { + Map in = new HashMap(1); + Map out = null; + out = execute(in); + return out; + } + } + + + private static class StoredProcedureExceptionTranslator extends StoredProcedure { + + public static final String SQL = "no_sproc_with_this_name"; + + public StoredProcedureExceptionTranslator(DataSource ds) { + setDataSource(ds); + setSql(SQL); + getJdbcTemplate().setExceptionTranslator(new SQLExceptionTranslator() { + public DataAccessException translate( + String task, + String sql, + SQLException sqlex) { + return new CustomDataException(sql, sqlex); + } + + }); + compile(); + } + + public void execute() { + execute(new HashMap()); + } + } + + + private static class CustomDataException extends DataAccessException { + + public CustomDataException(String s) { + super(s); + } + + public CustomDataException(String s, Throwable ex) { + super(s, ex); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/CustomErrorCodeException.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/CustomErrorCodeException.java new file mode 100644 index 00000000000..579a91cbb64 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/CustomErrorCodeException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import org.springframework.dao.DataAccessException; + +/** + * @author Thomas Risberg + */ +public class CustomErrorCodeException extends DataAccessException { + + public CustomErrorCodeException(String msg) { + super(msg); + } + + public CustomErrorCodeException(String msg, Throwable ex) { + super(msg, ex); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java new file mode 100644 index 00000000000..7c63fd5c5c0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java @@ -0,0 +1,253 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer; +import org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer; +import org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrementer; +import org.springframework.jdbc.support.incrementer.PostgreSQLSequenceMaxValueIncrementer; + +/** + * @author Juergen Hoeller + * @since 27.02.2004 + */ +public class DataFieldMaxValueIncrementerTests extends TestCase { + + public void testHsqlMaxValueIncrementer() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl stmtControl = MockControl.createControl(Statement.class); + Statement stmt = (Statement) stmtControl.getMock(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 2); + con.createStatement(); + conControl.setReturnValue(stmt, 2); + stmt.executeUpdate("insert into myseq values(null)"); + stmtControl.setReturnValue(1, 6); + stmt.executeQuery("select max(identity()) from myseq"); + stmtControl.setReturnValue(rs, 6); + rs.next(); + rsControl.setReturnValue(true, 6); + for (long i = 0; i < 6; i++) { + rs.getLong(1); + rsControl.setReturnValue(i); + } + rs.close(); + rsControl.setVoidCallable(6); + stmt.executeUpdate("delete from myseq where seq < 2"); + stmtControl.setReturnValue(1); + stmt.executeUpdate("delete from myseq where seq < 5"); + stmtControl.setReturnValue(1); + stmt.close(); + stmtControl.setVoidCallable(2); + con.close(); + conControl.setVoidCallable(2); + + dsControl.replay(); + conControl.replay(); + stmtControl.replay(); + rsControl.replay(); + + HsqlMaxValueIncrementer incrementer = new HsqlMaxValueIncrementer(); + incrementer.setDataSource(ds); + incrementer.setIncrementerName("myseq"); + incrementer.setColumnName("seq"); + incrementer.setCacheSize(3); + incrementer.setPaddingLength(3); + incrementer.afterPropertiesSet(); + + assertEquals(0, incrementer.nextIntValue()); + assertEquals(1, incrementer.nextLongValue()); + assertEquals("002", incrementer.nextStringValue()); + assertEquals(3, incrementer.nextIntValue()); + assertEquals(4, incrementer.nextLongValue()); + + dsControl.verify(); + conControl.verify(); + stmtControl.verify(); + rsControl.verify(); + } + + public void testMySQLMaxValueIncrementer() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl stmtControl = MockControl.createControl(Statement.class); + Statement stmt = (Statement) stmtControl.getMock(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 2); + con.createStatement(); + conControl.setReturnValue(stmt, 2); + stmt.executeUpdate("update myseq set seq = last_insert_id(seq + 2)"); + stmtControl.setReturnValue(1, 2); + stmt.executeQuery("select last_insert_id()"); + stmtControl.setReturnValue(rs, 2); + rs.next(); + rsControl.setReturnValue(true, 2); + rs.getLong(1); + rsControl.setReturnValue(2); + rs.getLong(1); + rsControl.setReturnValue(4); + rs.close(); + rsControl.setVoidCallable(2); + stmt.close(); + stmtControl.setVoidCallable(2); + con.close(); + conControl.setVoidCallable(2); + + dsControl.replay(); + conControl.replay(); + stmtControl.replay(); + rsControl.replay(); + + MySQLMaxValueIncrementer incrementer = new MySQLMaxValueIncrementer(); + incrementer.setDataSource(ds); + incrementer.setIncrementerName("myseq"); + incrementer.setColumnName("seq"); + incrementer.setCacheSize(2); + incrementer.setPaddingLength(1); + incrementer.afterPropertiesSet(); + + assertEquals(1, incrementer.nextIntValue()); + assertEquals(2, incrementer.nextLongValue()); + assertEquals("3", incrementer.nextStringValue()); + assertEquals(4, incrementer.nextLongValue()); + + dsControl.verify(); + conControl.verify(); + stmtControl.verify(); + rsControl.verify(); + } + + public void testPostgreSQLSequenceMaxValueIncrementer() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl stmtControl = MockControl.createControl(Statement.class); + Statement stmt = (Statement) stmtControl.getMock(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 2); + con.createStatement(); + conControl.setReturnValue(stmt, 2); + stmt.executeQuery("select nextval('myseq')"); + stmtControl.setReturnValue(rs, 2); + rs.next(); + rsControl.setReturnValue(true, 2); + rs.getLong(1); + rsControl.setReturnValue(10); + rs.getLong(1); + rsControl.setReturnValue(12); + rs.close(); + rsControl.setVoidCallable(2); + stmt.close(); + stmtControl.setVoidCallable(2); + con.close(); + conControl.setVoidCallable(2); + + dsControl.replay(); + conControl.replay(); + stmtControl.replay(); + rsControl.replay(); + + PostgreSQLSequenceMaxValueIncrementer incrementer = new PostgreSQLSequenceMaxValueIncrementer(); + incrementer.setDataSource(ds); + incrementer.setIncrementerName("myseq"); + incrementer.setPaddingLength(5); + incrementer.afterPropertiesSet(); + + assertEquals("00010", incrementer.nextStringValue()); + assertEquals(12, incrementer.nextIntValue()); + + dsControl.verify(); + conControl.verify(); + stmtControl.verify(); + rsControl.verify(); + } + + public void testOracleSequenceMaxValueIncrementer() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl stmtControl = MockControl.createControl(Statement.class); + Statement stmt = (Statement) stmtControl.getMock(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + + ds.getConnection(); + dsControl.setReturnValue(con, 2); + con.createStatement(); + conControl.setReturnValue(stmt, 2); + stmt.executeQuery("select myseq.nextval from dual"); + stmtControl.setReturnValue(rs, 2); + rs.next(); + rsControl.setReturnValue(true, 2); + rs.getLong(1); + rsControl.setReturnValue(10); + rs.getLong(1); + rsControl.setReturnValue(12); + rs.close(); + rsControl.setVoidCallable(2); + stmt.close(); + stmtControl.setVoidCallable(2); + con.close(); + conControl.setVoidCallable(2); + + dsControl.replay(); + conControl.replay(); + stmtControl.replay(); + rsControl.replay(); + + OracleSequenceMaxValueIncrementer incrementer = new OracleSequenceMaxValueIncrementer(); + incrementer.setDataSource(ds); + incrementer.setIncrementerName("myseq"); + incrementer.setPaddingLength(2); + incrementer.afterPropertiesSet(); + + assertEquals(10, incrementer.nextLongValue()); + assertEquals("12", incrementer.nextStringValue()); + + dsControl.verify(); + conControl.verify(); + stmtControl.verify(); + rsControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DefaultLobHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DefaultLobHandlerTests.java new file mode 100644 index 00000000000..933d8089a57 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/DefaultLobHandlerTests.java @@ -0,0 +1,161 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.ResultSet; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jdbc.support.lob.DefaultLobHandler; +import org.springframework.jdbc.support.lob.LobCreator; +import org.springframework.jdbc.support.lob.LobHandler; + +/** + * @author Juergen Hoeller + * @since 17.12.2003 + */ +public class DefaultLobHandlerTests extends TestCase { + + public void testGetBlobAsBytes() throws SQLException { + LobHandler lobHandler = new DefaultLobHandler(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + rs.getBytes(1); + rsControl.setReturnValue(null); + rsControl.replay(); + lobHandler.getBlobAsBytes(rs, 1); + rsControl.verify(); + } + + public void testGetBlobAsBinaryStream() throws SQLException { + LobHandler lobHandler = new DefaultLobHandler(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + rs.getBinaryStream(1); + rsControl.setReturnValue(null); + rsControl.replay(); + lobHandler.getBlobAsBinaryStream(rs, 1); + rsControl.verify(); + } + + public void testGetClobAsString() throws SQLException { + LobHandler lobHandler = new DefaultLobHandler(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + rs.getString(1); + rsControl.setReturnValue(null); + rsControl.replay(); + lobHandler.getClobAsString(rs, 1); + rsControl.verify(); + } + + public void testGetClobAsAsciiStream() throws SQLException { + LobHandler lobHandler = new DefaultLobHandler(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + rs.getAsciiStream(1); + rsControl.setReturnValue(null); + rsControl.replay(); + lobHandler.getClobAsAsciiStream(rs, 1); + rsControl.verify(); + } + + public void testGetClobAsCharacterStream() throws SQLException { + LobHandler lobHandler = new DefaultLobHandler(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + rs.getCharacterStream(1); + rsControl.setReturnValue(null); + rsControl.replay(); + lobHandler.getClobAsCharacterStream(rs, 1); + rsControl.verify(); + } + + public void testSetBlobAsBytes() throws SQLException { + LobCreator lobCreator = (new DefaultLobHandler()).getLobCreator(); + byte[] content = "testContent".getBytes(); + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + ps.setBytes(1, content); + psControl.replay(); + + lobCreator.setBlobAsBytes(ps, 1, content); + psControl.verify(); + } + + public void testSetBlobAsBinaryStream() throws SQLException, IOException { + LobCreator lobCreator = (new DefaultLobHandler()).getLobCreator(); + InputStream bis = new ByteArrayInputStream("testContent".getBytes()); + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + ps.setBinaryStream(1, bis, 11); + psControl.replay(); + + lobCreator.setBlobAsBinaryStream(ps, 1, bis, 11); + psControl.verify(); + } + + public void testSetClobAsString() throws SQLException, IOException { + LobCreator lobCreator = (new DefaultLobHandler()).getLobCreator(); + String content = "testContent"; + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + ps.setString(1, content); + psControl.replay(); + + lobCreator.setClobAsString(ps, 1, content); + psControl.verify(); + } + + public void testSetClobAsAsciiStream() throws SQLException, IOException { + LobCreator lobCreator = (new DefaultLobHandler()).getLobCreator(); + InputStream bis = new ByteArrayInputStream("testContent".getBytes()); + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + ps.setAsciiStream(1, bis, 11); + psControl.replay(); + + lobCreator.setClobAsAsciiStream(ps, 1, bis, 11); + psControl.verify(); + } + + public void testSetClobAsCharacterStream() throws SQLException, IOException { + LobCreator lobCreator = (new DefaultLobHandler()).getLobCreator(); + Reader str = new StringReader("testContent"); + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + ps.setCharacterStream(1, str, 11); + psControl.replay(); + + lobCreator.setClobAsCharacterStream(ps, 1, str, 11); + psControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/JdbcUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/JdbcUtilsTests.java new file mode 100644 index 00000000000..637032c6953 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/JdbcUtilsTests.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import junit.framework.TestCase; + +/** + * Unit tests for JdbcUtils. + * + * @author Thomas Risberg + */ +public class JdbcUtilsTests extends TestCase { + + public void testCommonDatabaseName() { + assertEquals("Wrong db name", "Oracle", JdbcUtils.commonDatabaseName("Oracle")); + assertEquals("Wrong db name", "DB2", JdbcUtils.commonDatabaseName("DB2-for-Spring")); + assertEquals("Wrong db name", "Sybase", JdbcUtils.commonDatabaseName("Sybase SQL Server")); + assertEquals("Wrong db name", "Sybase", JdbcUtils.commonDatabaseName("Adaptive Server Enterprise")); + assertEquals("Wrong db name", "MySQL", JdbcUtils.commonDatabaseName("MySQL")); + } + + public void testConvertUnderscoreNameToPropertyName() { + assertEquals("Wrong property name", "myName", JdbcUtils.convertUnderscoreNameToPropertyName("MY_NAME")); + assertEquals("Wrong property name", "yourName", JdbcUtils.convertUnderscoreNameToPropertyName("yOUR_nAME")); + assertEquals("Wrong property name", "AName", JdbcUtils.convertUnderscoreNameToPropertyName("a_name")); + assertEquals("Wrong property name", "someoneElsesName", JdbcUtils.convertUnderscoreNameToPropertyName("someone_elses_name")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/KeyHolderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/KeyHolderTests.java new file mode 100644 index 00000000000..058ce7c3048 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/KeyHolderTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import org.springframework.dao.DataRetrievalFailureException; +import org.springframework.dao.InvalidDataAccessApiUsageException; + +import junit.framework.TestCase; + +/** + * Tests for the KeyHolder and GeneratedKeyHolder + * and it appears that JdbcUtils doesn't work exactly as documented. + * + * @author trisberg + * @since Jul 18, 2004 + */ +public class KeyHolderTests extends TestCase { + private KeyHolder kh; + + public void setUp() { + kh = new GeneratedKeyHolder(); + } + + public void testSingleKey(){ + LinkedList l = new LinkedList(); + HashMap m = new HashMap(1); + m.put("key", new Integer(1)); + l.add(m); + kh.getKeyList().addAll(l); + assertEquals("single key should be returned", 1, kh.getKey().intValue()); + } + + public void testSingleKeyNonNumeric(){ + LinkedList l = new LinkedList(); + HashMap m = new HashMap(1); + m.put("key", "1"); + l.add(m); + kh.getKeyList().addAll(l); + try { + kh.getKey().intValue(); + } + catch (DataRetrievalFailureException e) { + assertTrue(e.getMessage().startsWith("The generated key is not of a supported numeric type.")); + } + } + + public void testNoKeyReturnedInMap(){ + LinkedList l = new LinkedList(); + HashMap m = new HashMap(); + l.add(m); + kh.getKeyList().addAll(l); + try { + kh.getKey(); + } + catch (DataRetrievalFailureException e) { + assertTrue(e.getMessage().startsWith("Unable to retrieve the generated key.")); + } + } + + public void testMultipleKeys(){ + LinkedList l = new LinkedList(); + HashMap m = new HashMap(1); + m.put("key", new Integer(1)); + m.put("seq", new Integer(2)); + l.add(m); + kh.getKeyList().addAll(l); + Map keyMap = kh.getKeys(); + assertEquals("two keys should be in the map", 2, keyMap.size()); + try { + kh.getKey(); + } + catch (InvalidDataAccessApiUsageException e) { + assertTrue(e.getMessage().startsWith("The getKey method should only be used when a single key is returned.")); + } + } + + public void testMultipleKeyRows(){ + LinkedList l = new LinkedList(); + HashMap m = new HashMap(1); + m.put("key", new Integer(1)); + m.put("seq", new Integer(2)); + l.add(m); + l.add(m); + kh.getKeyList().addAll(l); + + assertEquals("two rows should be in the list", 2, kh.getKeyList().size()); + try { + kh.getKeys(); + } + catch (InvalidDataAccessApiUsageException e) { + assertTrue(e.getMessage().startsWith("The getKeys method should only be used when keys for a single row are returned.")); + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/NativeJdbcExtractorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/NativeJdbcExtractorTests.java new file mode 100644 index 00000000000..a5c23af49cc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/NativeJdbcExtractorTests.java @@ -0,0 +1,144 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor; +import org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor; + +/** + * @author Andre Biryukov + * @author Juergen Hoeller + */ +public class NativeJdbcExtractorTests extends TestCase { + + public void testSimpleNativeJdbcExtractor() throws SQLException { + SimpleNativeJdbcExtractor extractor = new SimpleNativeJdbcExtractor(); + + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl dbmdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData dbmd = (DatabaseMetaData) dbmdControl.getMock(); + MockControl con2Control = MockControl.createControl(Connection.class); + Connection con2 = (Connection) con2Control.getMock(); + con.getMetaData(); + conControl.setReturnValue(dbmd, 2); + dbmd.getConnection(); + dbmdControl.setReturnValue(con2, 2); + conControl.replay(); + dbmdControl.replay(); + con2Control.replay(); + + Connection nativeCon = extractor.getNativeConnection(con); + assertEquals(con2, nativeCon); + + MockControl stmtControl = MockControl.createControl(Statement.class); + Statement stmt = (Statement) stmtControl.getMock(); + stmt.getConnection(); + stmtControl.setReturnValue(con); + stmtControl.replay(); + + nativeCon = extractor.getNativeConnectionFromStatement(stmt); + assertEquals(con2, nativeCon); + + Statement nativeStmt = extractor.getNativeStatement(stmt); + assertEquals(nativeStmt, stmt); + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + psControl.replay(); + + PreparedStatement nativePs = extractor.getNativePreparedStatement(ps); + assertEquals(ps, nativePs); + + MockControl csControl = MockControl.createControl(CallableStatement.class); + CallableStatement cs = (CallableStatement) csControl.getMock(); + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + cs.getResultSet(); + csControl.setReturnValue(rs); + csControl.replay(); + rsControl.replay(); + + CallableStatement nativeCs = extractor.getNativeCallableStatement(cs); + assertEquals(cs, nativeCs); + + ResultSet nativeRs = extractor.getNativeResultSet(cs.getResultSet()); + assertEquals(nativeRs, rs); + + conControl.verify(); + dbmdControl.verify(); + con2Control.verify(); + stmtControl.verify(); + psControl.verify(); + csControl.verify(); + rsControl.verify(); + } + + public void testCommonsDbcpNativeJdbcExtractor() throws SQLException { + CommonsDbcpNativeJdbcExtractor extractor = new CommonsDbcpNativeJdbcExtractor(); + assertFalse(extractor.isNativeConnectionNecessaryForNativeStatements()); + + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl stmtControl = MockControl.createControl(Statement.class); + Statement stmt = (Statement) stmtControl.getMock(); + con.getMetaData(); + conControl.setReturnValue(null, 2); + stmt.getConnection(); + stmtControl.setReturnValue(con, 1); + conControl.replay(); + stmtControl.replay(); + + Connection nativeConnection = extractor.getNativeConnection(con); + assertEquals(con, nativeConnection); + + nativeConnection = extractor.getNativeConnectionFromStatement(stmt); + assertEquals(con, nativeConnection); + assertEquals(stmt, extractor.getNativeStatement(stmt)); + + MockControl psControl = MockControl.createControl(PreparedStatement.class); + PreparedStatement ps = (PreparedStatement) psControl.getMock(); + psControl.replay(); + assertEquals(ps, extractor.getNativePreparedStatement(ps)); + + MockControl csControl = MockControl.createControl(CallableStatement.class); + CallableStatement cs = (CallableStatement) csControl.getMock(); + csControl.replay(); + assertEquals(cs, extractor.getNativePreparedStatement(cs)); + + MockControl rsControl = MockControl.createControl(ResultSet.class); + ResultSet rs = (ResultSet) rsControl.getMock(); + rsControl.replay(); + assertEquals(rs, extractor.getNativeResultSet(rs)); + + conControl.verify(); + stmtControl.verify(); + psControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java new file mode 100644 index 00000000000..d5ee4e48798 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.SQLException; +import java.sql.BatchUpdateException; + +import junit.framework.TestCase; + +import org.springframework.dao.CannotAcquireLockException; +import org.springframework.dao.CannotSerializeTransactionException; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.DeadlockLoserDataAccessException; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.InvalidResultSetAccessException; + +/** + * @author Rod Johnson + */ +public class SQLErrorCodeSQLExceptionTranslatorTests extends TestCase { + + private static SQLErrorCodes ERROR_CODES = new SQLErrorCodes(); + static { + ERROR_CODES.setBadSqlGrammarCodes(new String[] { "1", "2" }); + ERROR_CODES.setInvalidResultSetAccessCodes(new String[] { "3", "4" }); + ERROR_CODES.setDataAccessResourceFailureCodes(new String[] { "5" }); + ERROR_CODES.setDataIntegrityViolationCodes(new String[] { "6" }); + ERROR_CODES.setCannotAcquireLockCodes(new String[] { "7" }); + ERROR_CODES.setDeadlockLoserCodes(new String[] { "8" }); + ERROR_CODES.setCannotSerializeTransactionCodes(new String[] { "9" }); + } + + public void testErrorCodeTranslation() { + SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES); + + SQLException badSqlEx = new SQLException("", "", 1); + BadSqlGrammarException bsgex = (BadSqlGrammarException) sext.translate("task", "SQL", badSqlEx); + assertEquals("SQL", bsgex.getSql()); + assertEquals(badSqlEx, bsgex.getSQLException()); + + SQLException invResEx = new SQLException("", "", 4); + InvalidResultSetAccessException irsex = (InvalidResultSetAccessException) sext.translate("task", "SQL", invResEx); + assertEquals("SQL", irsex.getSql()); + assertEquals(invResEx, irsex.getSQLException()); + + checkTranslation(sext, 5, DataAccessResourceFailureException.class); + checkTranslation(sext, 6, DataIntegrityViolationException.class); + checkTranslation(sext, 7, CannotAcquireLockException.class); + checkTranslation(sext, 8, DeadlockLoserDataAccessException.class); + checkTranslation(sext, 9, CannotSerializeTransactionException.class); + + // Test fallback. We assume that no database will ever return this error code, + // but 07xxx will be bad grammar picked up by the fallback SQLState translator + SQLException sex = new SQLException("", "07xxx", 666666666); + BadSqlGrammarException bsgex2 = (BadSqlGrammarException) sext.translate("task", "SQL2", sex); + assertEquals("SQL2", bsgex2.getSql()); + assertEquals(sex, bsgex2.getSQLException()); + } + + private void checkTranslation(SQLExceptionTranslator sext, int errorCode, Class exClass) { + SQLException sex = new SQLException("", "", errorCode); + DataAccessException ex = sext.translate("", "", sex); + assertTrue(exClass.isInstance(ex)); + assertTrue(ex.getCause() == sex); + } + + public void testBatchExceptionTranslation() { + SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES); + + SQLException badSqlEx = new SQLException("", "", 1); + BatchUpdateException batchUdateEx = new BatchUpdateException(); + batchUdateEx.setNextException(badSqlEx); + BadSqlGrammarException bsgex = (BadSqlGrammarException) sext.translate("task", "SQL", batchUdateEx); + assertEquals("SQL", bsgex.getSql()); + assertEquals(badSqlEx, bsgex.getSQLException()); + } + + + public void testCustomTranslateMethodTranslation() { + final String TASK = "TASK"; + final String SQL = "SQL SELECT *"; + final DataAccessException customDex = new DataAccessException("") {}; + + final SQLException badSqlEx = new SQLException("", "", 1); + SQLException intVioEx = new SQLException("", "", 6); + + SQLErrorCodeSQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator() { + protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) { + assertEquals(TASK, task); + assertEquals(SQL, sql); + return (sqlex == badSqlEx) ? customDex : null; + } + }; + sext.setSqlErrorCodes(ERROR_CODES); + + // Shouldn't custom translate this + assertEquals(customDex, sext.translate(TASK, SQL, badSqlEx)); + DataIntegrityViolationException diex = (DataIntegrityViolationException) sext.translate(TASK, SQL, intVioEx); + assertEquals(intVioEx, diex.getCause()); + } + + public void testCustomExceptionTranslation() { + final String TASK = "TASK"; + final String SQL = "SQL SELECT *"; + final SQLErrorCodes customErrorCodes = new SQLErrorCodes(); + final CustomSQLErrorCodesTranslation customTranslation = new CustomSQLErrorCodesTranslation(); + + customErrorCodes.setBadSqlGrammarCodes(new String[] {"1", "2"}); + customErrorCodes.setDataIntegrityViolationCodes(new String[] {"3", "4"}); + customTranslation.setErrorCodes(new String[] {"1"}); + customTranslation.setExceptionClass(CustomErrorCodeException.class); + customErrorCodes.setCustomTranslations(new CustomSQLErrorCodesTranslation[] {customTranslation}); + + SQLErrorCodeSQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(); + sext.setSqlErrorCodes(customErrorCodes); + + // Should custom translate this + SQLException badSqlEx = new SQLException("", "", 1); + assertEquals(CustomErrorCodeException.class, sext.translate(TASK, SQL, badSqlEx).getClass()); + assertEquals(badSqlEx, sext.translate(TASK, SQL, badSqlEx).getCause()); + + // Shouldn't custom translate this + SQLException invResEx = new SQLException("", "", 3); + DataIntegrityViolationException diex = (DataIntegrityViolationException) sext.translate(TASK, SQL, invResEx); + assertEquals(invResEx, diex.getCause()); + + // Shouldn't custom translate this - invalid class + try { + customTranslation.setExceptionClass(String.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodesFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodesFactoryTests.java new file mode 100644 index 00000000000..52e1c1baff2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLErrorCodesFactoryTests.java @@ -0,0 +1,324 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.Arrays; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * Tests for SQLErrorCodes loading. + * + * @author Rod Johnson + * @author Thomas Risberg + */ +public class SQLErrorCodesFactoryTests extends TestCase { + + /** + * Check that a default instance returns empty error codes for an unknown database. + */ + public void testDefaultInstanceWithNoSuchDatabase() { + SQLErrorCodes sec = SQLErrorCodesFactory.getInstance().getErrorCodes("xx"); + assertTrue(sec.getBadSqlGrammarCodes().length == 0); + assertTrue(sec.getDataIntegrityViolationCodes().length == 0); + } + + /** + * Check that a known database produces recognizable codes. + */ + public void testDefaultInstanceWithOracle() { + SQLErrorCodes sec = SQLErrorCodesFactory.getInstance().getErrorCodes("Oracle"); + assertIsOracle(sec); + } + + private void assertIsOracle(SQLErrorCodes sec) { + assertTrue(sec.getBadSqlGrammarCodes().length > 0); + assertTrue(sec.getDataIntegrityViolationCodes().length > 0); + // This had better be a Bad SQL Grammar code + assertTrue(Arrays.binarySearch(sec.getBadSqlGrammarCodes(), "942") >= 0); + // This had better NOT be + assertFalse(Arrays.binarySearch(sec.getBadSqlGrammarCodes(), "9xx42") >= 0); + } + + private void assertIsHsql(SQLErrorCodes sec) { + assertTrue(sec.getBadSqlGrammarCodes().length > 0); + assertTrue(sec.getDataIntegrityViolationCodes().length > 0); + // This had better be a Bad SQL Grammar code + assertTrue(Arrays.binarySearch(sec.getBadSqlGrammarCodes(), "-22") >= 0); + // This had better NOT be + assertFalse(Arrays.binarySearch(sec.getBadSqlGrammarCodes(), "-9") >= 0); + } + + private void assertIsDB2(SQLErrorCodes sec) { + assertTrue(sec.getBadSqlGrammarCodes().length > 0); + assertTrue(sec.getDataIntegrityViolationCodes().length > 0); + + assertFalse(Arrays.binarySearch(sec.getBadSqlGrammarCodes(), "942") >= 0); + // This had better NOT be + assertTrue(Arrays.binarySearch(sec.getBadSqlGrammarCodes(), "-204") >= 0); + } + + public void testLookupOrder() { + class TestSQLErrorCodesFactory extends SQLErrorCodesFactory { + private int lookups = 0; + protected Resource loadResource(String path) { + ++lookups; + if (lookups == 1) { + assertEquals(SQLErrorCodesFactory.SQL_ERROR_CODE_DEFAULT_PATH, path); + return null; + } + else { + // Should have only one more lookup + assertEquals(2, lookups); + assertEquals(SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH, path); + return null; + } + } + } + + // Should have failed to load without error + TestSQLErrorCodesFactory sf = new TestSQLErrorCodesFactory(); + assertTrue(sf.getErrorCodes("XX").getBadSqlGrammarCodes().length == 0); + assertTrue(sf.getErrorCodes("Oracle").getDataIntegrityViolationCodes().length == 0); + } + + /** + * Check that user defined error codes take precedence. + */ + public void testFindUserDefinedCodes() { + class TestSQLErrorCodesFactory extends SQLErrorCodesFactory { + protected Resource loadResource(String path) { + if (SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH.equals(path)) { + return new ClassPathResource("test-error-codes.xml", SQLErrorCodesFactoryTests.class); + } + return null; + } + } + + // Should have loaded without error + TestSQLErrorCodesFactory sf = new TestSQLErrorCodesFactory(); + assertTrue(sf.getErrorCodes("XX").getBadSqlGrammarCodes().length == 0); + assertEquals(2, sf.getErrorCodes("Oracle").getBadSqlGrammarCodes().length); + assertEquals("1", sf.getErrorCodes("Oracle").getBadSqlGrammarCodes()[0]); + assertEquals("2", sf.getErrorCodes("Oracle").getBadSqlGrammarCodes()[1]); + } + + public void testInvalidUserDefinedCodeFormat() { + class TestSQLErrorCodesFactory extends SQLErrorCodesFactory { + protected Resource loadResource(String path) { + if (SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH.equals(path)) { + // Guaranteed to be on the classpath, but most certainly NOT XML + return new ClassPathResource("SQLExceptionTranslator.class", SQLErrorCodesFactoryTests.class); + } + return null; + } + } + + // Should have failed to load without error + TestSQLErrorCodesFactory sf = new TestSQLErrorCodesFactory(); + assertTrue(sf.getErrorCodes("XX").getBadSqlGrammarCodes().length == 0); + assertEquals(0, sf.getErrorCodes("Oracle").getBadSqlGrammarCodes().length); + } + + /** + * Check that custom error codes take precedence. + */ + public void testFindCustomCodes() { + class TestSQLErrorCodesFactory extends SQLErrorCodesFactory { + protected Resource loadResource(String path) { + if (SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH.equals(path)) { + return new ClassPathResource("custom-error-codes.xml", SQLErrorCodesFactoryTests.class); + } + return null; + } + } + + // Should have loaded without error + TestSQLErrorCodesFactory sf = new TestSQLErrorCodesFactory(); + assertEquals(1, sf.getErrorCodes("Oracle").getCustomTranslations().length); + CustomSQLErrorCodesTranslation translation = + (CustomSQLErrorCodesTranslation) sf.getErrorCodes("Oracle").getCustomTranslations()[0]; + assertEquals(CustomErrorCodeException.class, translation.getExceptionClass()); + assertEquals(1, translation.getErrorCodes().length); + } + + public void testDataSourceWithNullMetadata() throws Exception { + + MockControl ctrlConnection = MockControl.createControl(Connection.class); + Connection mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(null); + mockConnection.close(); + ctrlConnection.setVoidCallable(); + ctrlConnection.replay(); + + MockControl ctrlDataSource = MockControl.createControl(DataSource.class); + DataSource mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + ctrlDataSource.replay(); + + SQLErrorCodes sec = SQLErrorCodesFactory.getInstance().getErrorCodes(mockDataSource); + assertIsEmpty(sec); + + ctrlConnection.verify(); + ctrlDataSource.verify(); + } + + public void testGetFromDataSourceWithSQLException() throws Exception { + + SQLException expectedSQLException = new SQLException(); + + MockControl ctrlDataSource = MockControl.createControl(DataSource.class); + DataSource mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setThrowable(expectedSQLException); + ctrlDataSource.replay(); + + SQLErrorCodes sec = SQLErrorCodesFactory.getInstance().getErrorCodes(mockDataSource); + assertIsEmpty(sec); + + ctrlDataSource.verify(); + } + + private void assertIsEmpty(SQLErrorCodes sec) { + // Codes should be empty + assertEquals(0, sec.getBadSqlGrammarCodes().length); + assertEquals(0, sec.getDataIntegrityViolationCodes().length); + } + + private SQLErrorCodes getErrorCodesFromDataSource(String productName, SQLErrorCodesFactory factory) throws Exception { + MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); + md.getDatabaseProductName(); + mdControl.setReturnValue(productName); + mdControl.replay(); + + MockControl ctrlConnection = MockControl.createControl(Connection.class); + Connection mockConnection = (Connection) ctrlConnection.getMock(); + mockConnection.getMetaData(); + ctrlConnection.setReturnValue(md); + mockConnection.close(); + ctrlConnection.setVoidCallable(); + ctrlConnection.replay(); + + MockControl ctrlDataSource = MockControl.createControl(DataSource.class); + DataSource mockDataSource = (DataSource) ctrlDataSource.getMock(); + mockDataSource.getConnection(); + ctrlDataSource.setDefaultReturnValue(mockConnection); + ctrlDataSource.replay(); + + SQLErrorCodesFactory secf = null; + if (factory != null) { + secf = factory; + } + else { + secf = SQLErrorCodesFactory.getInstance(); + } + + SQLErrorCodes sec = secf.getErrorCodes(mockDataSource); + + mdControl.verify(); + ctrlConnection.verify(); + ctrlDataSource.verify(); + + SQLErrorCodes sec2 = secf.getErrorCodes(mockDataSource); + assertSame("Cached per DataSource", sec2, sec); + + return sec; + } + + public void testOracleRecognizedFromMetadata() throws Exception { + SQLErrorCodes sec = getErrorCodesFromDataSource("Oracle", null); + assertIsOracle(sec); + } + + public void testHsqlRecognizedFromMetadata() throws Exception { + SQLErrorCodes sec = getErrorCodesFromDataSource("HSQL Database Engine", null); + assertIsHsql(sec); + } + + public void testDB2RecognizedFromMetadata() throws Exception { + SQLErrorCodes sec = getErrorCodesFromDataSource("DB2", null); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("DB2/", null); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("DB-2", null); + assertIsEmpty(sec); + } + + /** + * Check that wild card database name works. + */ + public void testWildCardNameRecognized() throws Exception { + class WildcardSQLErrorCodesFactory extends SQLErrorCodesFactory { + protected Resource loadResource(String path) { + if (SQLErrorCodesFactory.SQL_ERROR_CODE_OVERRIDE_PATH.equals(path)) { + return new ClassPathResource("wildcard-error-codes.xml", SQLErrorCodesFactoryTests.class); + } + return null; + } + } + + WildcardSQLErrorCodesFactory factory = new WildcardSQLErrorCodesFactory(); + SQLErrorCodes sec = getErrorCodesFromDataSource("DB2", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("DB2 UDB for Xxxxx", factory); + assertIsDB2(sec); + + sec = getErrorCodesFromDataSource("DB3", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("DB3/", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("/DB3", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("/DB3", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("/DB3/", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("DB-3", factory); + assertIsEmpty(sec); + + sec = getErrorCodesFromDataSource("DB1", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("DB1/", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("/DB1", factory); + assertIsEmpty(sec); + sec = getErrorCodesFromDataSource("/DB1/", factory); + assertIsEmpty(sec); + + sec = getErrorCodesFromDataSource("DB0", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("/DB0", factory); + assertIsDB2(sec); + sec = getErrorCodesFromDataSource("DB0/", factory); + assertIsEmpty(sec); + sec = getErrorCodesFromDataSource("/DB0/", factory); + assertIsEmpty(sec); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassFactory.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassFactory.java new file mode 100644 index 00000000000..3d6f05949a7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassFactory.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.SQLDataException; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLIntegrityConstraintViolationException; +import java.sql.SQLInvalidAuthorizationSpecException; +import java.sql.SQLNonTransientConnectionException; +import java.sql.SQLRecoverableException; +import java.sql.SQLSyntaxErrorException; +import java.sql.SQLTimeoutException; +import java.sql.SQLTransactionRollbackException; +import java.sql.SQLTransientConnectionException; + +/** + * Class to generate Java 6 SQLException subclasses for testing purposes. + * + * @author Thomas Risberg + */ +public class SQLExceptionSubclassFactory { + + public static SQLException newSQLDataException(String reason, String SQLState, int vendorCode) { + return new SQLDataException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLFeatureNotSupportedException(String reason, String SQLState, int vendorCode) { + return new SQLFeatureNotSupportedException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLIntegrityConstraintViolationException(String reason, String SQLState, int vendorCode) { + return new SQLIntegrityConstraintViolationException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLInvalidAuthorizationSpecException(String reason, String SQLState, int vendorCode) { + return new SQLInvalidAuthorizationSpecException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLNonTransientConnectionException(String reason, String SQLState, int vendorCode) { + return new SQLNonTransientConnectionException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLSyntaxErrorException(String reason, String SQLState, int vendorCode) { + return new SQLSyntaxErrorException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLTransactionRollbackException(String reason, String SQLState, int vendorCode) { + return new SQLTransactionRollbackException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLTransientConnectionException(String reason, String SQLState, int vendorCode) { + return new SQLTransientConnectionException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLTimeoutException(String reason, String SQLState, int vendorCode) { + return new SQLTimeoutException(reason, SQLState, vendorCode); + } + + public static SQLException newSQLRecoverableException(String reason, String SQLState, int vendorCode) { + return new SQLRecoverableException(reason, SQLState, vendorCode); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassTranslatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassTranslatorTests.java new file mode 100644 index 00000000000..4c63040b537 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLExceptionSubclassTranslatorTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.SQLException; + +import junit.framework.TestCase; + +import org.springframework.core.JdkVersion; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.PermissionDeniedDataAccessException; +import org.springframework.dao.RecoverableDataAccessException; +import org.springframework.dao.TransientDataAccessResourceException; +import org.springframework.jdbc.BadSqlGrammarException; + +/** + * @author Thomas Risberg + */ +public class SQLExceptionSubclassTranslatorTests extends TestCase { + + private static SQLErrorCodes ERROR_CODES = new SQLErrorCodes(); + + static { + ERROR_CODES.setBadSqlGrammarCodes(new String[] { "1" }); + } + + + public void testErrorCodeTranslation() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16) { + return; + } + + SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES); + + SQLException dataIntegrityViolationEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 0); + DataIntegrityViolationException divex = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx); + assertEquals(dataIntegrityViolationEx, divex.getCause()); + + SQLException featureNotSupEx = SQLExceptionSubclassFactory.newSQLFeatureNotSupportedException("", "", 0); + InvalidDataAccessApiUsageException idaex = (InvalidDataAccessApiUsageException) sext.translate("task", "SQL", featureNotSupEx); + assertEquals(featureNotSupEx, idaex.getCause()); + + SQLException dataIntegrityViolationEx2 = SQLExceptionSubclassFactory.newSQLIntegrityConstraintViolationException("", "", 0); + DataIntegrityViolationException divex2 = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx2); + assertEquals(dataIntegrityViolationEx2, divex2.getCause()); + + SQLException permissionDeniedEx = SQLExceptionSubclassFactory.newSQLInvalidAuthorizationSpecException("", "", 0); + PermissionDeniedDataAccessException pdaex = (PermissionDeniedDataAccessException) sext.translate("task", "SQL", permissionDeniedEx); + assertEquals(permissionDeniedEx, pdaex.getCause()); + + SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLNonTransientConnectionException("", "", 0); + DataAccessResourceFailureException darex = (DataAccessResourceFailureException) sext.translate("task", "SQL", dataAccessResourceEx); + assertEquals(dataAccessResourceEx, darex.getCause()); + + SQLException badSqlEx2 = SQLExceptionSubclassFactory.newSQLSyntaxErrorException("", "", 0); + BadSqlGrammarException bsgex2 = (BadSqlGrammarException) sext.translate("task", "SQL2", badSqlEx2); + assertEquals("SQL2", bsgex2.getSql()); + assertEquals(badSqlEx2, bsgex2.getSQLException()); + + SQLException tranRollbackEx = SQLExceptionSubclassFactory.newSQLTransactionRollbackException("", "", 0); + ConcurrencyFailureException cfex = (ConcurrencyFailureException) sext.translate("task", "SQL", tranRollbackEx); + assertEquals(tranRollbackEx, cfex.getCause()); + + SQLException transientConnEx = SQLExceptionSubclassFactory.newSQLTransientConnectionException("", "", 0); + TransientDataAccessResourceException tdarex = (TransientDataAccessResourceException) sext.translate("task", "SQL", transientConnEx); + assertEquals(transientConnEx, tdarex.getCause()); + + SQLException transientConnEx2 = SQLExceptionSubclassFactory.newSQLTimeoutException("", "", 0); + TransientDataAccessResourceException tdarex2 = (TransientDataAccessResourceException) sext.translate("task", "SQL", transientConnEx2); + assertEquals(transientConnEx2, tdarex2.getCause()); + + SQLException recoverableEx = SQLExceptionSubclassFactory.newSQLRecoverableException("", "", 0); + RecoverableDataAccessException rdaex2 = (RecoverableDataAccessException) sext.translate("task", "SQL", recoverableEx); + assertEquals(recoverableEx, rdaex2.getCause()); + + // Test classic error code translation. We should move there next if the exception we pass in is not one + // of the new sub-classes. + SQLException sexEct = new SQLException("", "", 1); + BadSqlGrammarException bsgEct = (BadSqlGrammarException) sext.translate("task", "SQL-ECT", sexEct); + assertEquals("SQL-ECT", bsgEct.getSql()); + assertEquals(sexEct, bsgEct.getSQLException()); + + // Test fallback. We assume that no database will ever return this error code, + // but 07xxx will be bad grammar picked up by the fallback SQLState translator + SQLException sexFbt = new SQLException("", "07xxx", 666666666); + BadSqlGrammarException bsgFbt = (BadSqlGrammarException) sext.translate("task", "SQL-FBT", sexFbt); + assertEquals("SQL-FBT", bsgFbt.getSql()); + assertEquals(sexFbt, bsgFbt.getSQLException()); + // and 08xxx will be data resource failure (non-transient) picked up by the fallback SQLState translator + SQLException sexFbt2 = new SQLException("", "08xxx", 666666666); + DataAccessResourceFailureException darfFbt = (DataAccessResourceFailureException) sext.translate("task", "SQL-FBT2", sexFbt2); + assertEquals(sexFbt2, darfFbt.getCause()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateExceptionTranslatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateExceptionTranslatorTests.java new file mode 100644 index 00000000000..35a66acbf34 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateExceptionTranslatorTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.SQLException; + +import junit.framework.TestCase; + +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.UncategorizedSQLException; + +/** + * + * @author Rod Johnson + * @since 13-Jan-03 + */ +public class SQLStateExceptionTranslatorTests extends TestCase { + + private SQLStateSQLExceptionTranslator trans = new SQLStateSQLExceptionTranslator(); + + // ALSO CHECK CHAIN of SQLExceptions!? + // also allow chain of translators? default if can't do specific? + + public void testBadSqlGrammar() { + String sql = "SELECT FOO FROM BAR"; + SQLException sex = new SQLException("Message", "42001", 1); + try { + throw this.trans.translate("task", sql, sex); + } + catch (BadSqlGrammarException ex) { + // OK + assertTrue("SQL is correct", sql.equals(ex.getSql())); + assertTrue("Exception matches", sex.equals(ex.getSQLException())); + } + } + + public void testInvalidSqlStateCode() { + String sql = "SELECT FOO FROM BAR"; + SQLException sex = new SQLException("Message", "NO SUCH CODE", 1); + try { + throw this.trans.translate("task", sql, sex); + } + catch (UncategorizedSQLException ex) { + // OK + assertTrue("SQL is correct", sql.equals(ex.getSql())); + assertTrue("Exception matches", sex.equals(ex.getSQLException())); + } + } + + /** + * PostgreSQL can return null + * SAP DB can apparently return empty SQL code + * Bug 729170 + */ + public void testMalformedSqlStateCodes() { + String sql = "SELECT FOO FROM BAR"; + SQLException sex = new SQLException("Message", null, 1); + testMalformedSqlStateCode(sex); + + sex = new SQLException("Message", "", 1); + testMalformedSqlStateCode(sex); + + // One char's not allowed + sex = new SQLException("Message", "I", 1); + testMalformedSqlStateCode(sex); + } + + + private void testMalformedSqlStateCode(SQLException sex) { + String sql = "SELECT FOO FROM BAR"; + try { + throw this.trans.translate("task", sql, sex); + } + catch (UncategorizedSQLException ex) { + // OK + assertTrue("SQL is correct", sql.equals(ex.getSql())); + assertTrue("Exception matches", sex.equals(ex.getSQLException())); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java new file mode 100644 index 00000000000..418c0f8e084 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support; + +import java.sql.SQLException; + +import junit.framework.TestCase; + +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.TransientDataAccessResourceException; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.UncategorizedSQLException; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class SQLStateSQLExceptionTranslatorTests extends TestCase { + + private static final String REASON = "The game is afoot!"; + + private static final String TASK = "Counting sheep... yawn."; + + private static final String SQL = "select count(0) from t_sheep where over_fence = ... yawn... 1"; + + + public void testTranslateNullException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new SQLStateSQLExceptionTranslator().translate("", "", null); + } + }.runTest(); + } + + public void testTranslateBadSqlGrammar() throws Exception { + doTest("07", BadSqlGrammarException.class); + } + + public void testTranslateDataIntegrityViolation() throws Exception { + doTest("23", DataIntegrityViolationException.class); + } + + public void testTranslateDataAccessResourceFailure() throws Exception { + doTest("53", DataAccessResourceFailureException.class); + } + + public void testTranslateTransientDataAccessResourceFailure() throws Exception { + doTest("S1", TransientDataAccessResourceException.class); + } + + public void testTranslateConcurrencyFailure() throws Exception { + doTest("40", ConcurrencyFailureException.class); + } + + public void testTranslateUncategorized() throws Exception { + doTest("00000000", UncategorizedSQLException.class); + } + + + private void doTest(String sqlState, Class dataAccessExceptionType) { + SQLException ex = new SQLException(REASON, sqlState); + SQLExceptionTranslator translator = new SQLStateSQLExceptionTranslator(); + DataAccessException dax = translator.translate(TASK, SQL, ex); + assertNotNull("Translation must *never* result in a null DataAccessException being returned.", dax); + assertEquals("Wrong DataAccessException type returned as the result of the translation", dataAccessExceptionType, dax.getClass()); + assertNotNull("The original SQLException must be preserved in the translated DataAccessException", dax.getCause()); + assertSame("The exact same original SQLException must be preserved in the translated DataAccessException", ex, dax.getCause()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/custom-error-codes.xml b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/custom-error-codes.xml new file mode 100644 index 00000000000..a2aa1898320 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/custom-error-codes.xml @@ -0,0 +1,24 @@ + + + + + + + + 1,2 + 1,1400,1722 + + + + 999 + + org.springframework.jdbc.support.CustomErrorCodeException + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/rowset/ResultSetWrappingRowSetTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/rowset/ResultSetWrappingRowSetTests.java new file mode 100644 index 00000000000..489daa2ee1b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/rowset/ResultSetWrappingRowSetTests.java @@ -0,0 +1,223 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support.rowset; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jdbc.InvalidResultSetAccessException; + +/** + * @author Thomas Risberg + */ +public class ResultSetWrappingRowSetTests extends TestCase { + + private MockControl rsetControl; + private ResultSet rset; + private ResultSetWrappingSqlRowSet rowset; + + public void setUp() throws Exception { + rsetControl = MockControl.createControl(ResultSet.class); + rset = (ResultSet) rsetControl.getMock(); + rset.getMetaData(); + rsetControl.setReturnValue(null); + } + + public void testGetBigDecimalInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getBigDecimal", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getBigDecimal", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), BigDecimal.valueOf(1)); + } + + public void testGetBigDecimalString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getBigDecimal", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getBigDecimal", new Class[] {String.class}); + doTest(rset, rowset, "test", BigDecimal.valueOf(1)); + } + + public void testGetStringInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getString", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getString", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), "test"); + } + + public void testGetStringString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getString", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getString", new Class[] {String.class}); + doTest(rset, rowset, "test", "test"); + } + + public void testGetTimestampInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getTimestamp", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getTimestamp", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Timestamp(1234l)); + } + + public void testGetTimestampString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getTimestamp", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getTimestamp", new Class[] {String.class}); + doTest(rset, rowset, "test", new Timestamp(1234l)); + } + + public void testGetDateInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getDate", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getDate", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Date(1234l)); + } + + public void testGetDateString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getDate", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getDate", new Class[] {String.class}); + doTest(rset, rowset, "test", new Date(1234l)); + } + + public void testGetTimeInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getTime", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getTime", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Time(1234l)); + } + + public void testGetTimeString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getTime", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getTime", new Class[] {String.class}); + doTest(rset, rowset, "test", new Time(1234l)); + } + + public void testGetObjectInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getObject", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getObject", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Object()); + } + + public void testGetObjectString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getObject", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getObject", new Class[] {String.class}); + doTest(rset, rowset, "test", new Object()); + } + + public void testGetIntInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getInt", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getInt", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Integer(1)); + } + + public void testGetIntString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getInt", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getInt", new Class[] {String.class}); + doTest(rset, rowset, "test", new Integer(1)); + } + + public void testGetFloatInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getFloat", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getFloat", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Float(1)); + } + + public void testGetFloatString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getFloat", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getFloat", new Class[] {String.class}); + doTest(rset, rowset, "test", new Float(1)); + } + + public void testGetDoubleInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getDouble", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getDouble", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Double(1)); + } + + public void testGetDoubleString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getDouble", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getDouble", new Class[] {String.class}); + doTest(rset, rowset, "test", new Double(1)); + } + + public void testGetLongInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getLong", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getLong", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Long(1)); + } + + public void testGetLongString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getLong", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getLong", new Class[] {String.class}); + doTest(rset, rowset, "test", new Long(1)); + } + + public void testGetBooleanInt() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getBoolean", new Class[] {int.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getBoolean", new Class[] {int.class}); + doTest(rset, rowset, new Integer(1), new Boolean(true)); + } + + public void testGetBooleanString() throws Exception { + Method rset = ResultSet.class.getDeclaredMethod("getBoolean", new Class[] {String.class}); + Method rowset = ResultSetWrappingSqlRowSet.class.getDeclaredMethod("getBoolean", new Class[] {String.class}); + doTest(rset, rowset, "test", new Boolean(true)); + } + + private void doTest(Method rsetMethod, Method rowsetMethod, Object arg, Object ret) throws Exception { + rsetMethod.invoke(rset, new Object[] {arg}); + if (ret instanceof Double) { + rsetControl.setReturnValue(((Double) ret).doubleValue()); + } + else if (ret instanceof Float) { + rsetControl.setReturnValue(((Float) ret).floatValue()); + } + else if (ret instanceof Integer) { + rsetControl.setReturnValue(((Integer) ret).intValue()); + } + else if (ret instanceof Short) { + rsetControl.setReturnValue(((Short) ret).shortValue()); + } + else if (ret instanceof Long) { + rsetControl.setReturnValue(((Long) ret).longValue()); + } + else if (ret instanceof Boolean) { + rsetControl.setReturnValue(((Boolean) ret).booleanValue()); + } + else if (ret instanceof Byte) { + rsetControl.setReturnValue(((Byte) ret).byteValue()); + } + else { + rsetControl.setReturnValue(ret); + } + rsetMethod.invoke(rset, new Object[] {arg}); + rsetControl.setThrowable(new SQLException("test")); + + rsetControl.replay(); + + rowset = new ResultSetWrappingSqlRowSet(rset); + rowsetMethod.invoke(rowset, new Object[] {arg}); + try { + rowsetMethod.invoke(rowset, new Object[] {arg}); + fail("InvalidResultSetAccessException should have been thrown"); + } + catch (InvocationTargetException ex) { + assertEquals(InvalidResultSetAccessException.class, ex.getTargetException().getClass()); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/test-error-codes.xml b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/test-error-codes.xml new file mode 100644 index 00000000000..dd3fc33004b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/test-error-codes.xml @@ -0,0 +1,14 @@ + + + + + + + + 1,2 + 1,1400,1722 + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/wildcard-error-codes.xml b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/wildcard-error-codes.xml new file mode 100644 index 00000000000..b44c0a9c1b8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jdbc/support/wildcard-error-codes.xml @@ -0,0 +1,38 @@ + + + + + + + + 1,2,942 + 1,1400,1722 + + + + *DB0 + -204,1,2 + 3,4 + + + + DB1* + -204,1,2 + 3,4 + + + + *DB2* + -204,1,2 + 3,4 + + + + *DB3* + -204,1,2 + 3,4 + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/StubConnectionFactory.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/StubConnectionFactory.java new file mode 100644 index 00000000000..dced87b7168 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/StubConnectionFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; + +/** + * A stub implementation of the JMS ConnectionFactory for testing. + * + * @author Mark Fisher + */ +public class StubConnectionFactory implements ConnectionFactory { + + public Connection createConnection() throws JMSException { + return null; + } + + public Connection createConnection(String username, String password) throws JMSException { + return null; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/StubQueue.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/StubQueue.java new file mode 100644 index 00000000000..20586ae9522 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/StubQueue.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms; + +import javax.jms.Queue; + +/** + * Stub implementation of the {@link javax.jms.Queue} interface. + * + * @author Rick Evans + */ +public class StubQueue implements Queue { + + public static final String DEFAULT_QUEUE_NAME = "banjo"; + + + private String queueName = DEFAULT_QUEUE_NAME; + + + public StubQueue() { + } + + public StubQueue(String queueName) { + this.queueName = queueName; + } + + + public String getQueueName() { + return this.queueName; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/StubTopic.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/StubTopic.java new file mode 100644 index 00000000000..022ecdfbdb7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/StubTopic.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms; + +import javax.jms.Topic; + +/** + * Stub implementation of the {@link Topic} interface. + * + * @author Rick Evans + */ +public class StubTopic implements Topic { + + public static final String DEFAULT_TOPIC_NAME = "banjo"; + + + private String topicName = DEFAULT_TOPIC_NAME; + + + public StubTopic() { + } + + public StubTopic(String topicName) { + this.topicName = topicName; + } + + + public String getTopicName() { + return this.topicName; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/config/JmsNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/config/JmsNamespaceHandlerTests.java new file mode 100644 index 00000000000..71ce9404815 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/config/JmsNamespaceHandlerTests.java @@ -0,0 +1,247 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.config; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.BeansException; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.ComponentDefinition; +import org.springframework.beans.factory.parsing.CompositeComponentDefinition; +import org.springframework.beans.factory.parsing.EmptyReaderEventListener; +import org.springframework.beans.factory.parsing.PassThroughSourceExtractor; +import org.springframework.beans.factory.parsing.ReaderEventListener; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.jca.endpoint.GenericMessageEndpointManager; +import org.springframework.jms.listener.DefaultMessageListenerContainer; +import org.springframework.jms.listener.endpoint.JmsMessageEndpointManager; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + * @author Christian Dupuis + */ +public class JmsNamespaceHandlerTests extends TestCase { + + private static final String DEFAULT_CONNECTION_FACTORY = "connectionFactory"; + + private static final String EXPLICIT_CONNECTION_FACTORY = "testConnectionFactory"; + + private ToolingTestApplicationContext context; + + + protected void setUp() throws Exception { + this.context = new ToolingTestApplicationContext("jmsNamespaceHandlerTests.xml", getClass()); + } + + protected void tearDown() throws Exception { + this.context.close(); + } + + + public void testBeansCreated() { + Map containers = context.getBeansOfType(DefaultMessageListenerContainer.class); + assertEquals("Context should contain 3 JMS listener containers", 3, containers.size()); + + containers = context.getBeansOfType(GenericMessageEndpointManager.class); + assertEquals("Context should contain 3 JCA endpoint containers", 3, containers.size()); + } + + public void testContainerConfiguration() throws Exception { + Map containers = context.getBeansOfType(DefaultMessageListenerContainer.class); + ConnectionFactory defaultConnectionFactory = (ConnectionFactory) context.getBean(DEFAULT_CONNECTION_FACTORY); + ConnectionFactory explicitConnectionFactory = (ConnectionFactory) context.getBean(EXPLICIT_CONNECTION_FACTORY); + + int defaultConnectionFactoryCount = 0; + int explicitConnectionFactoryCount = 0; + + Iterator iter = containers.values().iterator(); + while (iter.hasNext()) { + DefaultMessageListenerContainer container = (DefaultMessageListenerContainer) iter.next(); + if (container.getConnectionFactory().equals(defaultConnectionFactory)) { + defaultConnectionFactoryCount++; + } + else if (container.getConnectionFactory().equals(explicitConnectionFactory)) { + explicitConnectionFactoryCount++; + } + } + + assertEquals("1 container should have the default connectionFactory", 1, defaultConnectionFactoryCount); + assertEquals("2 containers should have the explicit connectionFactory", 2, explicitConnectionFactoryCount); + } + + public void testListeners() throws Exception { + TestBean testBean1 = (TestBean) context.getBean("testBean1"); + TestBean testBean2 = (TestBean) context.getBean("testBean2"); + TestMessageListener testBean3 = (TestMessageListener) context.getBean("testBean3"); + + assertNull(testBean1.getName()); + assertNull(testBean2.getName()); + assertNull(testBean3.message); + + MockControl control1 = MockControl.createControl(TextMessage.class); + TextMessage message1 = (TextMessage) control1.getMock(); + control1.expectAndReturn(message1.getText(), "Test1"); + control1.replay(); + + MessageListener listener1 = getListener("listener1"); + listener1.onMessage(message1); + assertEquals("Test1", testBean1.getName()); + control1.verify(); + + MockControl control2 = MockControl.createControl(TextMessage.class); + TextMessage message2 = (TextMessage) control2.getMock(); + control2.expectAndReturn(message2.getText(), "Test2"); + control2.replay(); + + MessageListener listener2 = getListener("listener2"); + listener2.onMessage(message2); + assertEquals("Test2", testBean2.getName()); + control2.verify(); + + MockControl control3 = MockControl.createControl(TextMessage.class); + TextMessage message3 = (TextMessage) control3.getMock(); + control3.replay(); + + MessageListener listener3 = getListener(DefaultMessageListenerContainer.class.getName() + "#0"); + listener3.onMessage(message3); + assertSame(message3, testBean3.message); + control3.verify(); + } + + private MessageListener getListener(String containerBeanName) { + DefaultMessageListenerContainer container = (DefaultMessageListenerContainer) this.context.getBean(containerBeanName); + return (MessageListener) container.getMessageListener(); + } + + public void testComponentRegistration() { + assertTrue("Parser should have registered a component named 'listener1'", context.containsComponentDefinition("listener1")); + assertTrue("Parser should have registered a component named 'listener2'", context.containsComponentDefinition("listener2")); + assertTrue("Parser should have registered a component named 'listener3'", context.containsComponentDefinition("listener3")); + assertTrue("Parser should have registered a component named '" + DefaultMessageListenerContainer.class.getName() + "#0'", + context.containsComponentDefinition(DefaultMessageListenerContainer.class.getName() + "#0")); + assertTrue("Parser should have registered a component named '" + JmsMessageEndpointManager.class.getName() + "#0'", + context.containsComponentDefinition(JmsMessageEndpointManager.class.getName() + "#0")); + } + + public void testSourceExtraction() { + Iterator iterator = context.getRegisteredComponents(); + while (iterator.hasNext()) { + ComponentDefinition compDef = (ComponentDefinition) iterator.next(); + if (compDef instanceof CompositeComponentDefinition) { + assertNotNull("CompositeComponentDefinition '" + compDef.getName()+ "' has no source attachment", ((CompositeComponentDefinition) compDef).getSource()); + } + validateComponentDefinition(compDef); + } + } + + private void validateComponentDefinition(ComponentDefinition compDef) { + BeanDefinition[] beanDefs = compDef.getBeanDefinitions(); + for (int i = 0; i < beanDefs.length; i++) { + if (beanDefs[i] instanceof AbstractBeanDefinition) { + assertNotNull("AbstractBeanDefinition has no source attachment", ((AbstractBeanDefinition) beanDefs[i]).getSource()); + } + } + } + + + public static class TestMessageListener implements MessageListener { + + public Message message; + + public void onMessage(Message message) { + this.message = message; + } + } + + + /** + * Internal extension that registers a {@link ReaderEventListener} to store + * registered {@link ComponentDefinition}s. + */ + private static class ToolingTestApplicationContext extends ClassPathXmlApplicationContext { + + private static final Set REGISTERED_COMPONENTS = new HashSet(); + + public ToolingTestApplicationContext(String path, Class clazz) + throws BeansException { + super(path, clazz); + } + + protected void initBeanDefinitionReader( + XmlBeanDefinitionReader beanDefinitionReader) { + beanDefinitionReader.setEventListener(new StoringReaderEventListener(REGISTERED_COMPONENTS)); + beanDefinitionReader.setSourceExtractor(new PassThroughSourceExtractor()); + } + + public boolean containsComponentDefinition(String name) { + Iterator iterator = REGISTERED_COMPONENTS.iterator(); + while (iterator.hasNext()) { + ComponentDefinition cd = (ComponentDefinition) iterator.next(); + if (cd instanceof CompositeComponentDefinition) { + ComponentDefinition[] innerCds = ((CompositeComponentDefinition) cd) + .getNestedComponents(); + for (int i = 0; i < innerCds.length; i++) { + if (innerCds[i].getName().equals(name)) { + return true; + } + } + } + else { + if (cd.getName().equals(name)) { + return true; + } + } + } + return false; + } + + public Iterator getRegisteredComponents() { + return REGISTERED_COMPONENTS.iterator(); + } + } + + + private static class StoringReaderEventListener extends EmptyReaderEventListener { + + protected Set registeredComponents = null; + + public StoringReaderEventListener(Set registeredComponents) { + this.registeredComponents = registeredComponents; + this.registeredComponents.clear(); + } + + public void componentRegistered(ComponentDefinition componentDefinition) { + this.registeredComponents.add(componentDefinition); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/config/jmsNamespaceHandlerTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/jms/config/jmsNamespaceHandlerTests.xml new file mode 100644 index 00000000000..be347db5d2f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/config/jmsNamespaceHandlerTests.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/JmsTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/JmsTransactionManagerTests.java new file mode 100644 index 00000000000..24211c5fd5c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/JmsTransactionManagerTests.java @@ -0,0 +1,505 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.connection; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicSession; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jms.StubQueue; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.JmsTemplate102; +import org.springframework.jms.core.MessageCreator; +import org.springframework.jms.core.SessionCallback; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.UnexpectedRollbackException; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 26.07.2004 + */ +public class JmsTransactionManagerTests extends TestCase { + + public void testTransactionCommit() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + session.commit(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager(cf); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + JmsTemplate jt = new JmsTemplate(cf); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + tm.commit(ts); + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testTransactionRollback() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + session.rollback(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager(cf); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + JmsTemplate jt = new JmsTemplate(cf); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + tm.rollback(ts); + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testParticipatingTransactionWithCommit() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + session.commit(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager(cf); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + final JmsTemplate jt = new JmsTemplate(cf); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + } + }); + tm.commit(ts); + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testParticipatingTransactionWithRollbackOnly() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + session.rollback(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager(cf); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + final JmsTemplate jt = new JmsTemplate(cf); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + status.setRollbackOnly(); + } + }); + try { + tm.commit(ts); + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + } + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testSuspendedTransaction() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 2); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + con.createSession(false, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session2, 1); + session.commit(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + session2.close(); + session2Control.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(2); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager(cf); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + final JmsTemplate jt = new JmsTemplate(cf); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess != session); + return null; + } + }); + } + }); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + tm.commit(ts); + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testTransactionSuspension() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 2); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session2, 1); + session.commit(); + sessionControl.setVoidCallable(1); + session2.commit(); + session2Control.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + session2.close(); + session2Control.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(2); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager(cf); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + final JmsTemplate jt = new JmsTemplate(cf); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess != session); + return null; + } + }); + } + }); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + tm.commit(ts); + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testTransactionCommitWithMessageProducer() throws JMSException { + Destination dest = new StubQueue(); + + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl producerControl = MockControl.createControl(MessageProducer.class); + MessageProducer producer = (MessageProducer) producerControl.getMock(); + MockControl messageControl = MockControl.createControl(Message.class); + final Message message = (Message) messageControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + session.createProducer(dest); + sessionControl.setReturnValue(producer, 1); + producer.send(message); + producerControl.setVoidCallable(1); + session.getTransacted(); + sessionControl.setReturnValue(true, 1); + session.commit(); + sessionControl.setVoidCallable(1); + producer.close(); + producerControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + producerControl.replay(); + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager(cf); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + JmsTemplate jt = new JmsTemplate(cf); + jt.send(dest, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + return message; + } + }); + tm.commit(ts); + + producerControl.verify(); + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testTransactionCommit102WithQueue() throws JMSException { + MockControl cfControl = MockControl.createControl(QueueConnectionFactory.class); + QueueConnectionFactory cf = (QueueConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(QueueConnection.class); + QueueConnection con = (QueueConnection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(QueueSession.class); + final QueueSession session = (QueueSession) sessionControl.getMock(); + + cf.createQueueConnection(); + cfControl.setReturnValue(con, 1); + con.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + session.commit(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager102(cf, false); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + JmsTemplate jt = new JmsTemplate102(cf, false); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + tm.commit(ts); + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + public void testTransactionCommit102WithTopic() throws JMSException { + MockControl cfControl = MockControl.createControl(TopicConnectionFactory.class); + TopicConnectionFactory cf = (TopicConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(TopicConnection.class); + TopicConnection con = (TopicConnection) conControl.getMock(); + MockControl sessionControl = MockControl.createControl(TopicSession.class); + final TopicSession session = (TopicSession) sessionControl.getMock(); + + cf.createTopicConnection(); + cfControl.setReturnValue(con, 1); + con.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(session, 1); + session.commit(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + sessionControl.replay(); + conControl.replay(); + cfControl.replay(); + + JmsTransactionManager tm = new JmsTransactionManager102(cf, true); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + JmsTemplate jt = new JmsTemplate102(cf, true); + jt.execute(new SessionCallback() { + public Object doInJms(Session sess) { + assertTrue(sess == session); + return null; + } + }); + tm.commit(ts); + + sessionControl.verify(); + conControl.verify(); + cfControl.verify(); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/SingleConnectionFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/SingleConnectionFactoryTests.java new file mode 100644 index 00000000000..cf0c87ddf18 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/SingleConnectionFactoryTests.java @@ -0,0 +1,651 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.connection; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicSession; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +/** + * @author Juergen Hoeller + * @since 26.07.2004 + */ +public class SingleConnectionFactoryTests extends TestCase { + + public void testWithConnection() throws JMSException { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(con); + Connection con1 = scf.createConnection(); + con1.start(); + con1.stop(); // should be ignored + con1.close(); // should be ignored + Connection con2 = scf.createConnection(); + con2.start(); + con2.stop(); // should be ignored + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + conControl.verify(); + } + + public void testWithQueueConnection() throws JMSException { + MockControl conControl = MockControl.createControl(QueueConnection.class); + Connection con = (QueueConnection) conControl.getMock(); + + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(con); + QueueConnection con1 = scf.createQueueConnection(); + con1.start(); + con1.stop(); // should be ignored + con1.close(); // should be ignored + QueueConnection con2 = scf.createQueueConnection(); + con2.start(); + con2.stop(); // should be ignored + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + conControl.verify(); + } + + public void testWithTopicConnection() throws JMSException { + MockControl conControl = MockControl.createControl(TopicConnection.class); + Connection con = (TopicConnection) conControl.getMock(); + + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(con); + TopicConnection con1 = scf.createTopicConnection(); + con1.start(); + con1.stop(); // should be ignored + con1.close(); // should be ignored + TopicConnection con2 = scf.createTopicConnection(); + con2.start(); + con2.stop(); // should be ignored + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + conControl.verify(); + } + + public void testWithConnectionFactory() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + Connection con1 = scf.createConnection(); + con1.start(); + con1.close(); // should be ignored + Connection con2 = scf.createConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testWithQueueConnectionFactoryAndJms11Usage() throws JMSException { + MockControl cfControl = MockControl.createControl(QueueConnectionFactory.class); + QueueConnectionFactory cf = (QueueConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(QueueConnection.class); + QueueConnection con = (QueueConnection) conControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + Connection con1 = scf.createConnection(); + con1.start(); + con1.close(); // should be ignored + Connection con2 = scf.createConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testWithQueueConnectionFactoryAndJms102Usage() throws JMSException { + MockControl cfControl = MockControl.createControl(QueueConnectionFactory.class); + QueueConnectionFactory cf = (QueueConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(QueueConnection.class); + QueueConnection con = (QueueConnection) conControl.getMock(); + + cf.createQueueConnection(); + cfControl.setReturnValue(con, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + Connection con1 = scf.createQueueConnection(); + con1.start(); + con1.close(); // should be ignored + Connection con2 = scf.createQueueConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testWithTopicConnectionFactoryAndJms11Usage() throws JMSException { + MockControl cfControl = MockControl.createControl(TopicConnectionFactory.class); + TopicConnectionFactory cf = (TopicConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(TopicConnection.class); + TopicConnection con = (TopicConnection) conControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + Connection con1 = scf.createConnection(); + con1.start(); + con1.close(); // should be ignored + Connection con2 = scf.createConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testWithTopicConnectionFactoryAndJms102Usage() throws JMSException { + MockControl cfControl = MockControl.createControl(TopicConnectionFactory.class); + TopicConnectionFactory cf = (TopicConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(TopicConnection.class); + TopicConnection con = (TopicConnection) conControl.getMock(); + + cf.createTopicConnection(); + cfControl.setReturnValue(con, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + Connection con1 = scf.createTopicConnection(); + con1.start(); + con1.close(); // should be ignored + Connection con2 = scf.createTopicConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testWithConnectionFactoryAndClientId() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.setClientID("myId"); + conControl.setVoidCallable(1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + scf.setClientId("myId"); + Connection con1 = scf.createConnection(); + con1.start(); + con1.close(); // should be ignored + Connection con2 = scf.createConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testWithConnectionFactoryAndExceptionListener() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + + ExceptionListener listener = new ChainedExceptionListener(); + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.setExceptionListener(listener); + conControl.setVoidCallable(1); + con.getExceptionListener(); + conControl.setReturnValue(listener, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + scf.setExceptionListener(listener); + Connection con1 = scf.createConnection(); + assertEquals(listener, con1.getExceptionListener()); + con1.start(); + con1.stop(); // should be ignored + con1.close(); // should be ignored + Connection con2 = scf.createConnection(); + con2.start(); + con2.stop(); // should be ignored + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testWithConnectionFactoryAndReconnectOnException() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + TestConnection con = new TestConnection(); + + cf.createConnection(); + cfControl.setReturnValue(con, 2); + cfControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + scf.setReconnectOnException(true); + Connection con1 = scf.createConnection(); + assertNull(con1.getExceptionListener()); + con1.start(); + con.getExceptionListener().onException(new JMSException("")); + Connection con2 = scf.createConnection(); + con2.start(); + scf.destroy(); // should trigger actual close + + cfControl.verify(); + assertEquals(2, con.getStartCount()); + assertEquals(2, con.getCloseCount()); + } + + public void testWithConnectionFactoryAndExceptionListenerAndReconnectOnException() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + TestConnection con = new TestConnection(); + + TestExceptionListener listener = new TestExceptionListener(); + cf.createConnection(); + cfControl.setReturnValue(con, 2); + cfControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory(cf); + scf.setExceptionListener(listener); + scf.setReconnectOnException(true); + Connection con1 = scf.createConnection(); + assertSame(listener, con1.getExceptionListener()); + con1.start(); + con.getExceptionListener().onException(new JMSException("")); + Connection con2 = scf.createConnection(); + con2.start(); + scf.destroy(); // should trigger actual close + + cfControl.verify(); + assertEquals(2, con.getStartCount()); + assertEquals(2, con.getCloseCount()); + assertEquals(1, listener.getCount()); + } + + public void testConnectionFactory102WithQueue() throws JMSException { + MockControl cfControl = MockControl.createControl(QueueConnectionFactory.class); + QueueConnectionFactory cf = (QueueConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(QueueConnection.class); + QueueConnection con = (QueueConnection) conControl.getMock(); + + cf.createQueueConnection(); + cfControl.setReturnValue(con, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory102(cf, false); + QueueConnection con1 = scf.createQueueConnection(); + con1.start(); + con1.close(); // should be ignored + QueueConnection con2 = scf.createQueueConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testConnectionFactory102WithTopic() throws JMSException { + MockControl cfControl = MockControl.createControl(TopicConnectionFactory.class); + TopicConnectionFactory cf = (TopicConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(TopicConnection.class); + TopicConnection con = (TopicConnection) conControl.getMock(); + + cf.createTopicConnection(); + cfControl.setReturnValue(con, 1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + + SingleConnectionFactory scf = new SingleConnectionFactory102(cf, true); + TopicConnection con1 = scf.createTopicConnection(); + con1.start(); + con1.close(); // should be ignored + TopicConnection con2 = scf.createTopicConnection(); + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + } + + public void testCachingConnectionFactory() throws JMSException { + MockControl cfControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory cf = (ConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl txSessionControl = MockControl.createControl(Session.class); + Session txSession = (Session) txSessionControl.getMock(); + MockControl nonTxSessionControl = MockControl.createControl(Session.class); + Session nonTxSession = (Session) nonTxSessionControl.getMock(); + + cf.createConnection(); + cfControl.setReturnValue(con, 1); + con.createSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(txSession, 1); + txSession.getTransacted(); + txSessionControl.setReturnValue(true, 2); + txSession.rollback(); + txSessionControl.setVoidCallable(1); + txSession.commit(); + txSessionControl.setVoidCallable(1); + txSession.close(); + txSessionControl.setVoidCallable(1); + con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + conControl.setReturnValue(nonTxSession, 1); + nonTxSession.close(); + nonTxSessionControl.setVoidCallable(1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + txSessionControl.replay(); + nonTxSessionControl.replay(); + + CachingConnectionFactory scf = new CachingConnectionFactory(cf); + scf.setReconnectOnException(false); + Connection con1 = scf.createConnection(); + Session session1 = con1.createSession(true, Session.AUTO_ACKNOWLEDGE); + session1.getTransacted(); + session1.close(); // should lead to rollback + session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE); + session1.close(); // should be ignored + con1.start(); + con1.close(); // should be ignored + Connection con2 = scf.createConnection(); + Session session2 = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + session2.close(); // should be ignored + session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE); + session2.commit(); + session2.close(); // should be ignored + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + txSessionControl.verify(); + nonTxSessionControl.verify(); + } + + public void testCachingConnectionFactoryWithQueueConnectionFactoryAndJms102Usage() throws JMSException { + MockControl cfControl = MockControl.createControl(QueueConnectionFactory.class); + QueueConnectionFactory cf = (QueueConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(QueueConnection.class); + QueueConnection con = (QueueConnection) conControl.getMock(); + MockControl txSessionControl = MockControl.createControl(QueueSession.class); + QueueSession txSession = (QueueSession) txSessionControl.getMock(); + MockControl nonTxSessionControl = MockControl.createControl(QueueSession.class); + QueueSession nonTxSession = (QueueSession) nonTxSessionControl.getMock(); + + cf.createQueueConnection(); + cfControl.setReturnValue(con, 1); + con.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(txSession, 1); + txSession.getTransacted(); + txSessionControl.setReturnValue(true, 2); + txSession.rollback(); + txSessionControl.setVoidCallable(2); + txSession.close(); + txSessionControl.setVoidCallable(1); + con.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE); + conControl.setReturnValue(nonTxSession, 1); + nonTxSession.close(); + nonTxSessionControl.setVoidCallable(1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + txSessionControl.replay(); + nonTxSessionControl.replay(); + + CachingConnectionFactory scf = new CachingConnectionFactory(cf); + scf.setReconnectOnException(false); + Connection con1 = scf.createQueueConnection(); + Session session1 = con1.createSession(true, Session.AUTO_ACKNOWLEDGE); + session1.rollback(); + session1.close(); // should be ignored + session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE); + session1.close(); // should be ignored + con1.start(); + con1.close(); // should be ignored + QueueConnection con2 = scf.createQueueConnection(); + Session session2 = con2.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE); + session2.close(); // should be ignored + session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE); + session2.getTransacted(); + session2.close(); // should lead to rollback + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + txSessionControl.verify(); + nonTxSessionControl.verify(); + } + + public void testCachingConnectionFactoryWithTopicConnectionFactoryAndJms102Usage() throws JMSException { + MockControl cfControl = MockControl.createControl(TopicConnectionFactory.class); + TopicConnectionFactory cf = (TopicConnectionFactory) cfControl.getMock(); + MockControl conControl = MockControl.createControl(TopicConnection.class); + TopicConnection con = (TopicConnection) conControl.getMock(); + MockControl txSessionControl = MockControl.createControl(TopicSession.class); + TopicSession txSession = (TopicSession) txSessionControl.getMock(); + MockControl nonTxSessionControl = MockControl.createControl(TopicSession.class); + TopicSession nonTxSession = (TopicSession) nonTxSessionControl.getMock(); + + cf.createTopicConnection(); + cfControl.setReturnValue(con, 1); + con.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); + conControl.setReturnValue(txSession, 1); + txSession.getTransacted(); + txSessionControl.setReturnValue(true, 4); + txSession.rollback(); + txSessionControl.setVoidCallable(2); + txSession.close(); + txSessionControl.setVoidCallable(1); + con.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE); + conControl.setReturnValue(nonTxSession, 1); + nonTxSession.close(); + nonTxSessionControl.setVoidCallable(1); + con.start(); + conControl.setVoidCallable(2); + con.stop(); + conControl.setVoidCallable(1); + con.close(); + conControl.setVoidCallable(1); + + cfControl.replay(); + conControl.replay(); + txSessionControl.replay(); + nonTxSessionControl.replay(); + + CachingConnectionFactory scf = new CachingConnectionFactory(cf); + scf.setReconnectOnException(false); + Connection con1 = scf.createTopicConnection(); + Session session1 = con1.createSession(true, Session.AUTO_ACKNOWLEDGE); + session1.getTransacted(); + session1.close(); // should lead to rollback + session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE); + session1.close(); // should be ignored + con1.start(); + con1.close(); // should be ignored + TopicConnection con2 = scf.createTopicConnection(); + Session session2 = con2.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE); + session2.close(); // should be ignored + session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE); + session2.getTransacted(); + session2.close(); // should be ignored + con2.start(); + con2.close(); // should be ignored + scf.destroy(); // should trigger actual close + + cfControl.verify(); + conControl.verify(); + txSessionControl.verify(); + nonTxSessionControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestConnection.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestConnection.java new file mode 100644 index 00000000000..e37dd2e5dcd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestConnection.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.connection; + +import javax.jms.Connection; +import javax.jms.ConnectionConsumer; +import javax.jms.ConnectionMetaData; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.ServerSessionPool; +import javax.jms.Session; +import javax.jms.Topic; + +/** + * @author Juergen Hoeller + */ +public class TestConnection implements Connection { + + private ExceptionListener exceptionListener; + + private int startCount; + + private int closeCount; + + + public Session createSession(boolean b, int i) throws JMSException { + return null; + } + + public String getClientID() throws JMSException { + return null; + } + + public void setClientID(String paramName) throws JMSException { + } + + public ConnectionMetaData getMetaData() throws JMSException { + return null; + } + + public ExceptionListener getExceptionListener() throws JMSException { + return exceptionListener; + } + + public void setExceptionListener(ExceptionListener exceptionListener) throws JMSException { + this.exceptionListener = exceptionListener; + } + + public void start() throws JMSException { + this.startCount++; + } + + public void stop() throws JMSException { + } + + public void close() throws JMSException { + this.closeCount++; + } + + public ConnectionConsumer createConnectionConsumer(Destination destination, String paramName, ServerSessionPool serverSessionPool, int i) throws JMSException { + return null; + } + + public ConnectionConsumer createDurableConnectionConsumer(Topic topic, String paramName, String paramName1, ServerSessionPool serverSessionPool, int i) throws JMSException { + return null; + } + + + public int getStartCount() { + return startCount; + } + + public int getCloseCount() { + return closeCount; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestExceptionListener.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestExceptionListener.java new file mode 100644 index 00000000000..e3f489f8a84 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/connection/TestExceptionListener.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.connection; + +import javax.jms.ExceptionListener; +import javax.jms.JMSException; + +/** + * @author Juergen Hoeller + */ +public class TestExceptionListener implements ExceptionListener { + + private int count = 0; + + public void onException(JMSException ex) { + this.count++; + } + + public int getCount() { + return count; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102JtaTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102JtaTests.java new file mode 100644 index 00000000000..8918069e1bf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102JtaTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.core; + +/** + * @author Juergen Hoeller + * @since 06.01.2005 + */ +public class JmsTemplate102JtaTests extends JmsTemplate102Tests { + + protected boolean useTransactedSession() { + return true; + } + + protected boolean useTransactedTemplate() { + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102Tests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102Tests.java new file mode 100644 index 00000000000..c9890fd55b4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102Tests.java @@ -0,0 +1,1166 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.core; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueReceiver; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import javax.naming.Context; +import javax.naming.NamingException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jms.InvalidClientIDException; +import org.springframework.jms.InvalidDestinationException; +import org.springframework.jms.InvalidSelectorException; +import org.springframework.jms.JmsException; +import org.springframework.jms.JmsSecurityException; +import org.springframework.jms.MessageEOFException; +import org.springframework.jms.MessageFormatException; +import org.springframework.jms.MessageNotReadableException; +import org.springframework.jms.MessageNotWriteableException; +import org.springframework.jms.ResourceAllocationException; +import org.springframework.jms.TransactionInProgressException; +import org.springframework.jms.TransactionRolledBackException; +import org.springframework.jms.UncategorizedJmsException; +import org.springframework.jms.support.converter.SimpleMessageConverter; +import org.springframework.jms.support.destination.JndiDestinationResolver; +import org.springframework.jndi.JndiTemplate; + +/** + * Unit tests for the JmsTemplate implemented using JMS 1.0.2. + * + * @author Andre Biryukov + * @author Mark Pollack + */ +public class JmsTemplate102Tests extends TestCase { + + private Context mockJndiContext; + private MockControl mockJndiControl; + + private MockControl queueConnectionFactoryControl; + private QueueConnectionFactory mockQueueConnectionFactory; + + private MockControl queueConnectionControl; + private QueueConnection mockQueueConnection; + + private MockControl queueSessionControl; + private QueueSession mockQueueSession; + + private MockControl queueControl; + private Queue mockQueue; + + private MockControl topicConnectionFactoryControl; + private TopicConnectionFactory mockTopicConnectionFactory; + + private MockControl topicConnectionControl; + private TopicConnection mockTopicConnection; + + private MockControl topicSessionControl; + private TopicSession mockTopicSession; + + private MockControl topicControl; + private Topic mockTopic; + + private int deliveryMode = DeliveryMode.PERSISTENT; + private int priority = 9; + private int timeToLive = 10000; + + + /** + * Create the mock objects for testing. + */ + protected void setUp() throws Exception { + mockJndiControl = MockControl.createControl(Context.class); + mockJndiContext = (Context) this.mockJndiControl.getMock(); + + createMockForQueues(); + createMockForTopics(); + + mockJndiContext.close(); + mockJndiControl.replay(); + } + + private void createMockForTopics() throws JMSException, NamingException { + topicConnectionFactoryControl = MockControl.createControl(TopicConnectionFactory.class); + mockTopicConnectionFactory = (TopicConnectionFactory) topicConnectionFactoryControl.getMock(); + + topicConnectionControl = MockControl.createControl(TopicConnection.class); + mockTopicConnection = (TopicConnection) topicConnectionControl.getMock(); + + topicControl = MockControl.createControl(Topic.class); + mockTopic = (Topic) topicControl.getMock(); + + topicSessionControl = MockControl.createControl(TopicSession.class); + mockTopicSession = (TopicSession) topicSessionControl.getMock(); + + mockTopicConnectionFactory.createTopicConnection(); + topicConnectionFactoryControl.setReturnValue(mockTopicConnection); + topicConnectionFactoryControl.replay(); + + mockTopicConnection.createTopicSession(useTransactedTemplate(), Session.AUTO_ACKNOWLEDGE); + topicConnectionControl.setReturnValue(mockTopicSession); + mockTopicSession.getTransacted(); + topicSessionControl.setReturnValue(useTransactedSession()); + + mockJndiContext.lookup("testTopic"); + mockJndiControl.setReturnValue(mockTopic); + } + + private void createMockForQueues() throws JMSException, NamingException { + queueConnectionFactoryControl = MockControl.createControl(QueueConnectionFactory.class); + mockQueueConnectionFactory = (QueueConnectionFactory) queueConnectionFactoryControl.getMock(); + + queueConnectionControl = MockControl.createControl(QueueConnection.class); + mockQueueConnection = (QueueConnection) queueConnectionControl.getMock(); + + queueControl = MockControl.createControl(Queue.class); + mockQueue = (Queue) queueControl.getMock(); + + queueSessionControl = MockControl.createControl(QueueSession.class); + mockQueueSession = (QueueSession) queueSessionControl.getMock(); + + mockQueueConnectionFactory.createQueueConnection(); + queueConnectionFactoryControl.setReturnValue(mockQueueConnection); + queueConnectionFactoryControl.replay(); + + mockQueueConnection.createQueueSession(useTransactedTemplate(), Session.AUTO_ACKNOWLEDGE); + queueConnectionControl.setReturnValue(mockQueueSession); + mockQueueSession.getTransacted(); + queueSessionControl.setReturnValue(useTransactedSession()); + + mockJndiContext.lookup("testQueue"); + mockJndiControl.setReturnValue(mockQueue); + } + + private JmsTemplate102 createTemplate() { + JmsTemplate102 template = new JmsTemplate102(); + JndiDestinationResolver destMan = new JndiDestinationResolver(); + destMan.setJndiTemplate(new JndiTemplate() { + protected Context createInitialContext() { + return mockJndiContext; + } + }); + template.setDestinationResolver(destMan); + template.setSessionTransacted(useTransactedTemplate()); + return template; + } + + protected boolean useTransactedSession() { + return false; + } + + protected boolean useTransactedTemplate() { + return false; + } + + + public void testTopicSessionCallback() throws Exception { + JmsTemplate102 template = createTemplate(); + template.setPubSubDomain(true); + template.setConnectionFactory(mockTopicConnectionFactory); + template.afterPropertiesSet(); + + mockTopicSession.close(); + topicSessionControl.setVoidCallable(1); + + mockTopicConnection.close(); + topicConnectionControl.setVoidCallable(1); + + topicSessionControl.replay(); + topicConnectionControl.replay(); + + template.execute(new SessionCallback() { + public Object doInJms(Session session) throws JMSException { + boolean b = session.getTransacted(); + return null; + } + }); + + topicConnectionFactoryControl.verify(); + topicConnectionControl.verify(); + topicSessionControl.verify(); + } + + /** + * Test the execute(ProducerCallback) using a topic. + */ + public void testTopicProducerCallback() throws Exception { + JmsTemplate102 template = createTemplate(); + template.setPubSubDomain(true); + template.setConnectionFactory(mockTopicConnectionFactory); + template.afterPropertiesSet(); + + MockControl topicPublisherControl = MockControl.createControl(TopicPublisher.class); + TopicPublisher mockTopicPublisher = (TopicPublisher) topicPublisherControl.getMock(); + + mockTopicSession.createPublisher(null); + topicSessionControl.setReturnValue(mockTopicPublisher); + + mockTopicPublisher.getPriority(); + topicPublisherControl.setReturnValue(4); + + mockTopicPublisher.close(); + topicPublisherControl.setVoidCallable(1); + mockTopicSession.close(); + topicSessionControl.setVoidCallable(1); + mockTopicConnection.close(); + topicConnectionControl.setVoidCallable(1); + + topicPublisherControl.replay(); + topicSessionControl.replay(); + topicConnectionControl.replay(); + + template.execute(new ProducerCallback() { + public Object doInJms(Session session, MessageProducer producer) throws JMSException { + boolean b = session.getTransacted(); + int i = producer.getPriority(); + return null; + } + }); + + topicConnectionFactoryControl.verify(); + topicConnectionControl.verify(); + topicSessionControl.verify(); + } + + /** + * Test the execute(ProducerCallback) using a topic. + */ + public void testTopicProducerCallbackWithIdAndTimestampDisabled() throws Exception { + JmsTemplate102 template = createTemplate(); + template.setPubSubDomain(true); + template.setConnectionFactory(mockTopicConnectionFactory); + template.setMessageIdEnabled(false); + template.setMessageTimestampEnabled(false); + template.afterPropertiesSet(); + + MockControl topicPublisherControl = MockControl.createControl(TopicPublisher.class); + TopicPublisher mockTopicPublisher = (TopicPublisher) topicPublisherControl.getMock(); + + mockTopicSession.createPublisher(null); + topicSessionControl.setReturnValue(mockTopicPublisher); + + mockTopicPublisher.setDisableMessageID(true); + topicPublisherControl.setVoidCallable(1); + mockTopicPublisher.setDisableMessageTimestamp(true); + topicPublisherControl.setVoidCallable(1); + mockTopicPublisher.getPriority(); + topicPublisherControl.setReturnValue(4); + + mockTopicPublisher.close(); + topicPublisherControl.setVoidCallable(1); + mockTopicSession.close(); + topicSessionControl.setVoidCallable(1); + mockTopicConnection.close(); + topicConnectionControl.setVoidCallable(1); + + topicPublisherControl.replay(); + topicSessionControl.replay(); + topicConnectionControl.replay(); + + template.execute(new ProducerCallback() { + public Object doInJms(Session session, MessageProducer producer) throws JMSException { + boolean b = session.getTransacted(); + int i = producer.getPriority(); + return null; + } + }); + + topicConnectionFactoryControl.verify(); + topicConnectionControl.verify(); + topicSessionControl.verify(); + } + + /** + * Test the method execute(SessionCallback action) with using the + * point to point domain as specified by the value of isPubSubDomain = false. + */ + public void testQueueSessionCallback() throws Exception { + JmsTemplate102 template = createTemplate(); + // Point-to-Point (queues) are the default domain + template.setConnectionFactory(mockQueueConnectionFactory); + template.afterPropertiesSet(); + + mockQueueSession.close(); + queueSessionControl.setVoidCallable(1); + + mockQueueConnection.close(); + queueConnectionControl.setVoidCallable(1); + + queueSessionControl.replay(); + queueConnectionControl.replay(); + + template.execute(new SessionCallback() { + public Object doInJms(Session session) throws JMSException { + boolean b = session.getTransacted(); + return null; + } + }); + + queueConnectionFactoryControl.verify(); + queueConnectionControl.verify(); + queueSessionControl.verify(); + } + + /** + * Test the method execute(ProducerCallback) with a Queue. + */ + public void testQueueProducerCallback() throws Exception { + JmsTemplate102 template = createTemplate(); + // Point-to-Point (queues) are the default domain. + template.setConnectionFactory(mockQueueConnectionFactory); + template.afterPropertiesSet(); + + MockControl queueSenderControl = MockControl.createControl(QueueSender.class); + QueueSender mockQueueSender = (QueueSender) queueSenderControl.getMock(); + + mockQueueSession.createSender(null); + queueSessionControl.setReturnValue(mockQueueSender); + + mockQueueSender.getPriority(); + queueSenderControl.setReturnValue(4); + + mockQueueSender.close(); + queueSenderControl.setVoidCallable(1); + mockQueueSession.close(); + queueSessionControl.setVoidCallable(1); + mockQueueConnection.close(); + queueConnectionControl.setVoidCallable(1); + + queueSenderControl.replay(); + queueSessionControl.replay(); + queueConnectionControl.replay(); + + template.execute(new ProducerCallback() { + public Object doInJms(Session session, MessageProducer producer) + throws JMSException { + boolean b = session.getTransacted(); + int i = producer.getPriority(); + return null; + } + }); + + queueConnectionFactoryControl.verify(); + queueConnectionControl.verify(); + queueSessionControl.verify(); + } + + public void testQueueProducerCallbackWithIdAndTimestampDisabled() throws Exception { + JmsTemplate102 template = createTemplate(); + // Point-to-Point (queues) are the default domain. + template.setConnectionFactory(mockQueueConnectionFactory); + template.setMessageIdEnabled(false); + template.setMessageTimestampEnabled(false); + template.afterPropertiesSet(); + + MockControl queueSenderControl = MockControl.createControl(QueueSender.class); + QueueSender mockQueueSender = (QueueSender) queueSenderControl.getMock(); + + mockQueueSession.createSender(null); + queueSessionControl.setReturnValue(mockQueueSender); + + mockQueueSender.setDisableMessageID(true); + queueSenderControl.setVoidCallable(1); + mockQueueSender.setDisableMessageTimestamp(true); + queueSenderControl.setVoidCallable(1); + mockQueueSender.getPriority(); + queueSenderControl.setReturnValue(4); + + mockQueueSender.close(); + queueSenderControl.setVoidCallable(1); + mockQueueSession.close(); + queueSessionControl.setVoidCallable(1); + mockQueueConnection.close(); + queueConnectionControl.setVoidCallable(1); + + queueSenderControl.replay(); + queueSessionControl.replay(); + queueConnectionControl.replay(); + + template.execute(new ProducerCallback() { + public Object doInJms(Session session, MessageProducer producer) throws JMSException { + boolean b = session.getTransacted(); + int i = producer.getPriority(); + return null; + } + }); + + queueConnectionFactoryControl.verify(); + queueConnectionControl.verify(); + queueSessionControl.verify(); + } + + /** + * Test the setting of the JmsTemplate properties. + */ + public void testBeanProperties() throws Exception { + JmsTemplate102 template = createTemplate(); + template.setConnectionFactory(mockQueueConnectionFactory); + + assertTrue("connection factory ok", template.getConnectionFactory() == mockQueueConnectionFactory); + + JmsTemplate102 s102 = createTemplate(); + try { + s102.afterPropertiesSet(); + fail("IllegalArgumentException not thrown. ConnectionFactory should be set"); + } + catch (IllegalArgumentException ex) { + // expected + } + + // The default is for the JmsTemplate102 to send to queues. + // Test to make sure exeception is thrown and has reasonable message. + s102 = createTemplate(); + s102.setConnectionFactory(mockTopicConnectionFactory); + try { + s102.afterPropertiesSet(); + fail("IllegalArgumentException not thrown. Mismatch of Destination and ConnectionFactory types."); + } + catch (IllegalArgumentException ex) { + // expected + } + + s102 = createTemplate(); + s102.setConnectionFactory(mockQueueConnectionFactory); + s102.setPubSubDomain(true); + try { + s102.afterPropertiesSet(); + fail("IllegalArgumentException not thrown. Mismatch of Destination and ConnectionFactory types."); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + /** + * Test the method send(String destination, MessgaeCreator c) using + * a queue and default QOS values. + */ + public void testSendStringQueue() throws Exception { + sendQueue(true, false, false, true); + } + + /** + * Test the method send(String destination, MessageCreator c) when + * explicit QOS parameters are enabled, using a queue. + */ + public void testSendStringQueueWithQOS() throws Exception { + sendQueue(false, false, false, false); + } + + /** + * Test the method send(MessageCreator c) using default QOS values. + */ + public void testSendDefaultDestinationQueue() throws Exception { + sendQueue(true, false, true, true); + } + + /** + * Test the method send(MessageCreator c) using explicit QOS values. + */ + public void testSendDefaultDestinationQueueWithQOS() throws Exception { + sendQueue(false, false, true, false); + } + + /** + * Test the method send(String destination, MessageCreator c) using + * a topic and default QOS values. + */ + public void testSendStringTopic() throws Exception { + sendTopic(true, false); + } + + /** + * Test the method send(String destination, MessageCreator c) using explicit + * QOS values. + */ + public void testSendStringTopicWithQOS() throws Exception { + sendTopic(false, false); + } + + /** + * Test the method send(Destination queue, MessgaeCreator c) using + * a queue and default QOS values. + */ + public void testSendQueue() throws Exception { + sendQueue(true, false, false, true); + } + + /** + * Test the method send(Destination queue, MessageCreator c) sing explicit + * QOS values. + */ + public void testSendQueueWithQOS() throws Exception { + sendQueue(false, false, false, false); + } + + /** + * Test the method send(Destination queue, MessgaeCreator c) using + * a topic and default QOS values. + */ + public void testSendTopic() throws Exception { + sendTopic(true, false); + } + + /** + * Test the method send(Destination queue, MessageCreator c) using explicity + * QOS values. + */ + public void testSendTopicWithQOS() throws Exception { + sendQueue(false, false, false, true); + } + + /** + * Common method for testing a send method that uses the MessageCreator + * callback but with different QOS options. + */ + private void sendQueue( + boolean ignoreQOS, boolean explicitQueue, boolean useDefaultDestination, boolean disableIdAndTimestamp) + throws Exception { + + JmsTemplate102 template = createTemplate(); + template.setConnectionFactory(mockQueueConnectionFactory); + template.afterPropertiesSet(); + + if (useDefaultDestination) { + template.setDefaultDestination(mockQueue); + } + if (disableIdAndTimestamp) { + template.setMessageIdEnabled(false); + template.setMessageTimestampEnabled(false); + } + + MockControl queueSenderControl = MockControl.createControl(QueueSender.class); + QueueSender mockQueueSender = (QueueSender) queueSenderControl.getMock(); + + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + if (disableIdAndTimestamp) { + mockQueueSender.setDisableMessageID(true); + queueSenderControl.setVoidCallable(1); + mockQueueSender.setDisableMessageTimestamp(true); + queueSenderControl.setVoidCallable(1); + } + + mockQueueSession.createSender(this.mockQueue); + queueSessionControl.setReturnValue(mockQueueSender); + mockQueueSession.createTextMessage("just testing"); + queueSessionControl.setReturnValue(mockMessage); + + if (useTransactedTemplate()) { + mockQueueSession.commit(); + queueSessionControl.setVoidCallable(1); + } + + if (ignoreQOS) { + mockQueueSender.send(mockMessage); + } + else { + template.setExplicitQosEnabled(true); + template.setDeliveryMode(deliveryMode); + template.setPriority(priority); + template.setTimeToLive(timeToLive); + mockQueueSender.send(mockMessage, deliveryMode, priority, timeToLive); + } + queueSenderControl.setVoidCallable(1); + + mockQueueSender.close(); + queueSenderControl.setVoidCallable(1); + mockQueueSession.close(); + queueSessionControl.setVoidCallable(1); + mockQueueConnection.close(); + queueConnectionControl.setVoidCallable(1); + + queueSenderControl.replay(); + queueSessionControl.replay(); + queueConnectionControl.replay(); + + if (useDefaultDestination) { + template.send(new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + else { + if (explicitQueue) { + template.send(mockQueue, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + else { + template.send("testQueue", new MessageCreator() { + public Message createMessage(Session session) + throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + } + + queueConnectionFactoryControl.verify(); + queueConnectionControl.verify(); + queueSessionControl.verify(); + queueSenderControl.verify(); + } + + private void sendTopic(boolean ignoreQOS, boolean explicitTopic) throws Exception { + JmsTemplate102 template = createTemplate(); + template.setPubSubDomain(true); + template.setConnectionFactory(mockTopicConnectionFactory); + template.afterPropertiesSet(); + + MockControl topicPublisherControl = MockControl.createControl(TopicPublisher.class); + TopicPublisher mockTopicPublisher = (TopicPublisher) topicPublisherControl.getMock(); + + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + mockTopicSession.createPublisher(this.mockTopic); + topicSessionControl.setReturnValue(mockTopicPublisher); + mockTopicSession.createTextMessage("just testing"); + topicSessionControl.setReturnValue(mockMessage); + + if (useTransactedTemplate()) { + mockTopicSession.commit(); + topicSessionControl.setVoidCallable(1); + } + + mockTopicPublisher.close(); + topicPublisherControl.setVoidCallable(1); + mockTopicSession.close(); + topicSessionControl.setVoidCallable(1); + mockTopicConnection.close(); + topicConnectionControl.setVoidCallable(1); + + + topicSessionControl.replay(); + topicConnectionControl.replay(); + + if (ignoreQOS) { + mockTopicPublisher.publish(mockMessage); + } + else { + template.setExplicitQosEnabled(true); + template.setDeliveryMode(deliveryMode); + template.setPriority(priority); + template.setTimeToLive(timeToLive); + mockTopicPublisher.publish(mockMessage, deliveryMode, priority, timeToLive); + } + topicPublisherControl.replay(); + + template.setPubSubDomain(true); + + if (explicitTopic) { + template.send(mockTopic, new MessageCreator() { + public Message createMessage(Session session) + throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + else { + template.send("testTopic", new MessageCreator() { + public Message createMessage(Session session) + throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + + topicConnectionFactoryControl.verify(); + topicConnectionControl.verify(); + topicSessionControl.verify(); + topicPublisherControl.verify(); + } + + public void testConverter() throws Exception { + JmsTemplate102 template = createTemplate(); + template.setConnectionFactory(mockQueueConnectionFactory); + template.setMessageConverter(new SimpleMessageConverter()); + String s = "Hello world"; + + MockControl queueSenderControl = MockControl.createControl(QueueSender.class); + QueueSender mockQueueSender = (QueueSender) queueSenderControl.getMock(); + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + mockQueueSession.createSender(this.mockQueue); + queueSessionControl.setReturnValue(mockQueueSender); + mockQueueSession.createTextMessage("Hello world"); + queueSessionControl.setReturnValue(mockMessage); + + if (useTransactedTemplate()) { + mockQueueSession.commit(); + queueSessionControl.setVoidCallable(1); + } + + mockQueueSender.send(mockMessage); + queueSenderControl.setVoidCallable(1); + + mockQueueSender.close(); + queueSenderControl.setVoidCallable(1); + mockQueueSession.close(); + queueSessionControl.setVoidCallable(1); + mockQueueConnection.close(); + queueConnectionControl.setVoidCallable(1); + + queueSenderControl.replay(); + queueSessionControl.replay(); + queueConnectionControl.replay(); + + template.convertAndSend(mockQueue, s); + + queueConnectionFactoryControl.verify(); + queueConnectionControl.verify(); + queueSessionControl.verify(); + queueSenderControl.verify(); + } + + public void testQueueReceiveDefaultDestination() throws Exception { + doTestReceive(false, false, true, false, false, false, false, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testQueueReceiveDestination() throws Exception { + doTestReceive(false, true, false, false, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testQueueReceiveDestinationWithClientAcknowledge() throws Exception { + doTestReceive(false, true, false, false, true, false, false, 1000); + } + + public void testQueueReceiveStringDestination() throws Exception { + doTestReceive(false, false, false, false, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testQueueReceiveDefaultDestinationWithSelector() throws Exception { + doTestReceive(false, false, true, false, false, true, true, 1000); + } + + public void testQueueReceiveDestinationWithSelector() throws Exception { + doTestReceive(false, true, false, false, false, true, false, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testQueueReceiveDestinationWithClientAcknowledgeWithSelector() throws Exception { + doTestReceive(false, true, false, false, true, true, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testQueueReceiveStringDestinationWithSelector() throws Exception { + doTestReceive(false, false, false, false, false, true, false, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testQueueReceiveAndConvertDefaultDestination() throws Exception { + doTestReceive(false, false, true, true, false, false, false, 1000); + } + + public void testQueueReceiveAndConvertStringDestination() throws Exception { + doTestReceive(false, false, false, true, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testQueueReceiveAndConvertDestination() throws Exception { + doTestReceive(false, true, false, true, false, false, true, 1000); + } + + public void testQueueReceiveAndConvertDefaultDestinationWithSelector() throws Exception { + doTestReceive(false, false, true, true, false, true, true, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testQueueReceiveAndConvertStringDestinationWithSelector() throws Exception { + doTestReceive(false, false, false, true, false, true, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testQueueReceiveAndConvertDestinationWithSelector() throws Exception { + doTestReceive(false, true, false, true, false, true, false, 1000); + } + + public void testTopicReceiveDefaultDestination() throws Exception { + doTestReceive(true, false, true, false, false, false, false, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testTopicReceiveDestination() throws Exception { + doTestReceive(true, true, false, false, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testTopicReceiveDestinationWithClientAcknowledge() throws Exception { + doTestReceive(true, true, false, false, true, false, false, 1000); + } + + public void testTopicReceiveStringDestination() throws Exception { + doTestReceive(true, false, false, false, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testTopicReceiveDefaultDestinationWithSelector() throws Exception { + doTestReceive(true, false, true, false, false, true, true, 1000); + } + + public void testTopicReceiveDestinationWithSelector() throws Exception { + doTestReceive(true, true, false, false, false, true, false, 1000); + } + + public void testTopicReceiveDestinationWithClientAcknowledgeWithSelector() throws Exception { + doTestReceive(true, true, false, false, true, true, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testTopicReceiveStringDestinationWithSelector() throws Exception { + doTestReceive(true, false, false, false, false, true, false, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testTopicReceiveAndConvertDefaultDestination() throws Exception { + doTestReceive(true, false, true, true, false, false, false, 1000); + } + + public void testTopicReceiveAndConvertStringDestination() throws Exception { + doTestReceive(true, false, false, true, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testTopicReceiveAndConvertDestination() throws Exception { + doTestReceive(true, true, false, true, false, false, true, 1000); + } + + public void testTopicReceiveAndConvertDefaultDestinationWithSelector() throws Exception { + doTestReceive(true, false, true, true, false, true, true, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testTopicReceiveAndConvertStringDestinationWithSelector() throws Exception { + doTestReceive(true, false, false, true, false, true, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testTopicReceiveAndConvertDestinationWithSelector() throws Exception { + doTestReceive(true, true, false, true, false, true, false, 1000); + } + + private void doTestReceive( + boolean pubSub, + boolean explicitDestination, boolean useDefaultDestination, boolean testConverter, + boolean clientAcknowledge, boolean messageSelector, boolean noLocal, long timeout) + throws Exception { + + JmsTemplate102 template = createTemplate(); + template.setPubSubDomain(pubSub); + if (pubSub) { + template.setConnectionFactory(mockTopicConnectionFactory); + } + else { + template.setConnectionFactory(mockQueueConnectionFactory); + } + + // Override the default settings for client ack used in the test setup. + // Can't use Session.getAcknowledgeMode() + if (pubSub) { + topicConnectionControl.reset(); + if (clientAcknowledge) { + template.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE); + mockTopicConnection.createTopicSession(useTransactedTemplate(), Session.CLIENT_ACKNOWLEDGE); + } + else { + template.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE); + mockTopicConnection.createTopicSession(useTransactedTemplate(), Session.AUTO_ACKNOWLEDGE); + } + topicConnectionControl.setReturnValue(mockTopicSession); + } + else { + queueConnectionControl.reset(); + if (clientAcknowledge) { + template.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE); + mockQueueConnection.createQueueSession(useTransactedTemplate(), Session.CLIENT_ACKNOWLEDGE); + } + else { + template.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE); + mockQueueConnection.createQueueSession(useTransactedTemplate(), Session.AUTO_ACKNOWLEDGE); + } + queueConnectionControl.setReturnValue(mockQueueSession); + } + + Destination dest = pubSub ? (Destination) mockTopic : (Destination) mockQueue; + + if (useDefaultDestination) { + template.setDefaultDestination(dest); + } + if (noLocal) { + template.setPubSubNoLocal(true); + } + template.setReceiveTimeout(timeout); + + if (pubSub) { + mockTopicConnection.start(); + topicConnectionControl.setVoidCallable(1); + mockTopicConnection.close(); + topicConnectionControl.setVoidCallable(1); + } + else { + mockQueueConnection.start(); + queueConnectionControl.setVoidCallable(1); + mockQueueConnection.close(); + queueConnectionControl.setVoidCallable(1); + } + + String selectorString = "selector"; + MockControl messageConsumerControl = null; + MessageConsumer mockMessageConsumer = null; + + if (pubSub) { + messageConsumerControl = MockControl.createControl(TopicSubscriber.class); + TopicSubscriber mockTopicSubscriber = (TopicSubscriber) messageConsumerControl.getMock(); + mockMessageConsumer = mockTopicSubscriber; + mockTopicSession.createSubscriber(mockTopic, messageSelector ? selectorString : null, noLocal); + topicSessionControl.setReturnValue(mockTopicSubscriber); + } + else { + messageConsumerControl = MockControl.createControl(QueueReceiver.class); + QueueReceiver mockQueueReceiver = (QueueReceiver) messageConsumerControl.getMock(); + mockMessageConsumer = mockQueueReceiver; + mockQueueSession.createReceiver(mockQueue, messageSelector ? selectorString : null); + queueSessionControl.setReturnValue(mockQueueReceiver); + } + + if (useTransactedTemplate()) { + if (pubSub) { + mockTopicSession.commit(); + topicSessionControl.setVoidCallable(1); + } + else { + mockQueueSession.commit(); + queueSessionControl.setVoidCallable(1); + } + } + + if (pubSub) { + mockTopicSession.close(); + topicSessionControl.setVoidCallable(1); + } + else { + mockQueueSession.close(); + queueSessionControl.setVoidCallable(1); + } + + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + if (testConverter) { + mockMessage.getText(); + messageControl.setReturnValue("Hello World!"); + } + if (!useTransactedSession() && clientAcknowledge) { + mockMessage.acknowledge(); + messageControl.setVoidCallable(1); + } + + if (pubSub) { + topicSessionControl.replay(); + topicConnectionControl.replay(); + } + else { + queueSessionControl.replay(); + queueConnectionControl.replay(); + } + messageControl.replay(); + + if (timeout == JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT) { + mockMessageConsumer.receiveNoWait(); + } + else if (timeout == JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT) { + mockMessageConsumer.receive(); + } + else { + mockMessageConsumer.receive(timeout); + } + messageConsumerControl.setReturnValue(mockMessage); + mockMessageConsumer.close(); + messageConsumerControl.setVoidCallable(1); + + messageConsumerControl.replay(); + + Message message = null; + String textFromMessage = null; + + if (useDefaultDestination) { + if (testConverter) { + textFromMessage = (String) + (messageSelector ? template.receiveSelectedAndConvert(selectorString) : + template.receiveAndConvert()); + } + else { + message = (messageSelector ? template.receiveSelected(selectorString) : template.receive()); + } + } + else if (explicitDestination) { + if (testConverter) { + textFromMessage = (String) + (messageSelector ? template.receiveSelectedAndConvert(dest, selectorString) : + template.receiveAndConvert(dest)); + } + else { + message = (messageSelector ? template.receiveSelected(dest, selectorString) : + template.receive(dest)); + } + } + else { + String destinationName = (pubSub ? "testTopic" : "testQueue"); + if (testConverter) { + textFromMessage = (String) + (messageSelector ? template.receiveSelectedAndConvert(destinationName, selectorString) : + template.receiveAndConvert(destinationName)); + } + else { + message = (messageSelector ? template.receiveSelected(destinationName, selectorString) : + template.receive(destinationName)); + } + } + + if (pubSub) { + topicConnectionFactoryControl.verify(); + topicConnectionControl.verify(); + topicSessionControl.verify(); + } + else { + queueConnectionFactoryControl.verify(); + queueConnectionControl.verify(); + queueSessionControl.verify(); + } + messageConsumerControl.verify(); + messageControl.verify(); + + if (testConverter) { + assertEquals("Message text should be equal", "Hello World!", textFromMessage); + } + else { + assertEquals("Messages should refer to the same object", message, mockMessage); + } + } + + public void testIllegalStateException() throws Exception { + doTestJmsException(new javax.jms.IllegalStateException(""), org.springframework.jms.IllegalStateException.class); + } + + public void testInvalidClientIDException() throws Exception { + doTestJmsException(new javax.jms.InvalidClientIDException(""), InvalidClientIDException.class); + } + + public void testInvalidDestinationException() throws Exception { + doTestJmsException(new javax.jms.InvalidDestinationException(""), InvalidDestinationException.class); + } + + public void testInvalidSelectorException() throws Exception { + doTestJmsException(new javax.jms.InvalidSelectorException(""), InvalidSelectorException.class); + } + + public void testJmsSecurityException() throws Exception { + doTestJmsException(new javax.jms.JMSSecurityException(""), JmsSecurityException.class); + } + + public void testMessageEOFException() throws Exception { + doTestJmsException(new javax.jms.MessageEOFException(""), MessageEOFException.class); + } + + public void testMessageFormatException() throws Exception { + doTestJmsException(new javax.jms.MessageFormatException(""), MessageFormatException.class); + } + + public void testMessageNotReadableException() throws Exception { + doTestJmsException(new javax.jms.MessageNotReadableException(""), MessageNotReadableException.class); + } + + public void testMessageNotWriteableException() throws Exception { + doTestJmsException(new javax.jms.MessageNotWriteableException(""), MessageNotWriteableException.class); + } + + public void testResourceAllocationException() throws Exception { + doTestJmsException(new javax.jms.ResourceAllocationException(""), ResourceAllocationException.class); + } + + public void testTransactionInProgressException() throws Exception { + doTestJmsException(new javax.jms.TransactionInProgressException(""), TransactionInProgressException.class); + } + + public void testTransactionRolledBackException() throws Exception { + doTestJmsException(new javax.jms.TransactionRolledBackException(""), TransactionRolledBackException.class); + } + + public void testUncategorizedJmsException() throws Exception { + doTestJmsException(new javax.jms.JMSException(""), UncategorizedJmsException.class); + } + + protected void doTestJmsException(JMSException original, Class thrownExceptionClass) throws Exception { + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockQueueConnectionFactory); + template.setMessageConverter(new SimpleMessageConverter()); + String s = "Hello world"; + + MockControl queueSenderControl = MockControl.createControl(QueueSender.class); + QueueSender mockQueueSender = (QueueSender) queueSenderControl.getMock(); + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + queueSessionControl.reset(); + mockQueueSession.createSender(mockQueue); + queueSessionControl.setReturnValue(mockQueueSender); + mockQueueSession.createTextMessage("Hello world"); + queueSessionControl.setReturnValue(mockMessage); + + mockQueueSender.send(mockMessage); + queueSenderControl.setThrowable(original, 1); + mockQueueSender.close(); + queueSenderControl.setVoidCallable(1); + + mockQueueSession.close(); + queueSessionControl.setVoidCallable(1); + mockQueueConnection.close(); + queueConnectionControl.setVoidCallable(1); + + queueSenderControl.replay(); + queueSessionControl.replay(); + queueConnectionControl.replay(); + + try { + template.convertAndSend(mockQueue, s); + fail("Should have thrown JmsException"); + } + catch (JmsException wrappedEx) { + // expected + assertEquals(thrownExceptionClass, wrappedEx.getClass()); + assertEquals(original, wrappedEx.getCause()); + } + + queueSenderControl.verify(); + queueSessionControl.verify(); + queueConnectionControl.verify(); + queueConnectionFactoryControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102TransactedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102TransactedTests.java new file mode 100644 index 00000000000..20e5b3ed2bb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplate102TransactedTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.core; + +/** + * @author Juergen Hoeller + * @since 06.01.2005 + */ +public class JmsTemplate102TransactedTests extends JmsTemplate102Tests { + + protected boolean useTransactedSession() { + return true; + } + + protected boolean useTransactedTemplate() { + return true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateJtaTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateJtaTests.java new file mode 100644 index 00000000000..f13a7ccd562 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateJtaTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.core; + +/** + * @author Juergen Hoeller + * @since 06.01.2005 + */ +public class JmsTemplateJtaTests extends JmsTemplateTests { + + protected boolean useTransactedSession() { + return true; + } + + protected boolean useTransactedTemplate() { + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTests.java new file mode 100644 index 00000000000..4cd15f43485 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTests.java @@ -0,0 +1,847 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.core; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.Context; +import javax.naming.NamingException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jms.InvalidClientIDException; +import org.springframework.jms.InvalidDestinationException; +import org.springframework.jms.InvalidSelectorException; +import org.springframework.jms.JmsException; +import org.springframework.jms.JmsSecurityException; +import org.springframework.jms.MessageEOFException; +import org.springframework.jms.MessageFormatException; +import org.springframework.jms.MessageNotReadableException; +import org.springframework.jms.MessageNotWriteableException; +import org.springframework.jms.ResourceAllocationException; +import org.springframework.jms.TransactionInProgressException; +import org.springframework.jms.TransactionRolledBackException; +import org.springframework.jms.UncategorizedJmsException; +import org.springframework.jms.connection.ConnectionFactoryUtils; +import org.springframework.jms.connection.SingleConnectionFactory; +import org.springframework.jms.connection.TransactionAwareConnectionFactoryProxy; +import org.springframework.jms.support.JmsUtils; +import org.springframework.jms.support.converter.SimpleMessageConverter; +import org.springframework.jms.support.destination.JndiDestinationResolver; +import org.springframework.jndi.JndiTemplate; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * Unit tests for the JmsTemplate implemented using JMS 1.1. + * + * @author Andre Biryukov + * @author Mark Pollack + */ +public class JmsTemplateTests extends TestCase { + + private Context mockJndiContext; + private MockControl mockJndiControl; + + private MockControl connectionFactoryControl; + private ConnectionFactory mockConnectionFactory; + + private MockControl connectionControl; + private Connection mockConnection; + + private MockControl sessionControl; + private Session mockSession; + + private MockControl queueControl; + private Destination mockQueue; + + private int deliveryMode = DeliveryMode.PERSISTENT; + private int priority = 9; + private int timeToLive = 10000; + + + /** + * Create the mock objects for testing. + */ + protected void setUp() throws Exception { + mockJndiControl = MockControl.createControl(Context.class); + mockJndiContext = (Context) this.mockJndiControl.getMock(); + + createMockforDestination(); + + mockJndiContext.close(); + mockJndiControl.replay(); + } + + private void createMockforDestination() throws JMSException, NamingException { + connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + mockConnectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + + connectionControl = MockControl.createControl(Connection.class); + mockConnection = (Connection) connectionControl.getMock(); + + sessionControl = MockControl.createControl(Session.class); + mockSession = (Session) sessionControl.getMock(); + + queueControl = MockControl.createControl(Queue.class); + mockQueue = (Queue) queueControl.getMock(); + + mockConnectionFactory.createConnection(); + connectionFactoryControl.setReturnValue(mockConnection); + connectionFactoryControl.replay(); + + mockConnection.createSession(useTransactedTemplate(), Session.AUTO_ACKNOWLEDGE); + connectionControl.setReturnValue(mockSession); + mockSession.getTransacted(); + sessionControl.setReturnValue(useTransactedSession()); + + mockJndiContext.lookup("testDestination"); + mockJndiControl.setReturnValue(mockQueue); + } + + private JmsTemplate createTemplate() { + JmsTemplate template = new JmsTemplate(); + JndiDestinationResolver destMan = new JndiDestinationResolver(); + destMan.setJndiTemplate(new JndiTemplate() { + protected Context createInitialContext() { + return mockJndiContext; + } + }); + template.setDestinationResolver(destMan); + template.setSessionTransacted(useTransactedTemplate()); + return template; + } + + protected boolean useTransactedSession() { + return false; + } + + protected boolean useTransactedTemplate() { + return false; + } + + + public void testExceptionStackTrace() { + JMSException jmsEx = new JMSException("could not connect"); + Exception innerEx = new Exception("host not found"); + jmsEx.setLinkedException(innerEx); + JmsException springJmsEx = JmsUtils.convertJmsAccessException(jmsEx); + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + springJmsEx.printStackTrace(out); + String trace = sw.toString(); + assertTrue("inner jms exception not found", trace.indexOf("host not found") > 0); + } + + public void testProducerCallback() throws Exception { + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockConnectionFactory); + + MockControl messageProducerControl = MockControl.createControl(MessageProducer.class); + MessageProducer mockMessageProducer = (MessageProducer) messageProducerControl.getMock(); + + mockSession.createProducer(null); + sessionControl.setReturnValue(mockMessageProducer); + + mockMessageProducer.getPriority(); + messageProducerControl.setReturnValue(4); + + mockMessageProducer.close(); + messageProducerControl.setVoidCallable(1); + mockSession.close(); + sessionControl.setVoidCallable(1); + mockConnection.close(); + connectionControl.setVoidCallable(1); + + messageProducerControl.replay(); + sessionControl.replay(); + connectionControl.replay(); + + template.execute(new ProducerCallback() { + public Object doInJms(Session session, MessageProducer producer) throws JMSException { + boolean b = session.getTransacted(); + int i = producer.getPriority(); + return null; + } + }); + + connectionFactoryControl.verify(); + connectionControl.verify(); + sessionControl.verify(); + } + + public void testProducerCallbackWithIdAndTimestampDisabled() throws Exception { + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockConnectionFactory); + template.setMessageIdEnabled(false); + template.setMessageTimestampEnabled(false); + + MockControl messageProducerControl = MockControl.createControl(MessageProducer.class); + MessageProducer mockMessageProducer = (MessageProducer) messageProducerControl.getMock(); + + mockSession.createProducer(null); + sessionControl.setReturnValue(mockMessageProducer); + + mockMessageProducer.setDisableMessageID(true); + messageProducerControl.setVoidCallable(1); + mockMessageProducer.setDisableMessageTimestamp(true); + messageProducerControl.setVoidCallable(1); + mockMessageProducer.getPriority(); + messageProducerControl.setReturnValue(4); + + mockMessageProducer.close(); + messageProducerControl.setVoidCallable(1); + mockSession.close(); + sessionControl.setVoidCallable(1); + mockConnection.close(); + connectionControl.setVoidCallable(1); + + messageProducerControl.replay(); + sessionControl.replay(); + connectionControl.replay(); + + template.execute(new ProducerCallback() { + public Object doInJms(Session session, MessageProducer producer) throws JMSException { + boolean b = session.getTransacted(); + int i = producer.getPriority(); + return null; + } + }); + + connectionFactoryControl.verify(); + connectionControl.verify(); + sessionControl.verify(); + } + + /** + * Test the method execute(SessionCallback action). + */ + public void testSessionCallback() throws Exception { + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockConnectionFactory); + + mockSession.close(); + sessionControl.setVoidCallable(1); + + mockConnection.close(); + connectionControl.setVoidCallable(1); + + sessionControl.replay(); + connectionControl.replay(); + + template.execute(new SessionCallback() { + public Object doInJms(Session session) throws JMSException { + boolean b = session.getTransacted(); + return null; + } + }); + + connectionFactoryControl.verify(); + connectionControl.verify(); + sessionControl.verify(); + } + + public void testSessionCallbackWithinSynchronizedTransaction() throws Exception { + SingleConnectionFactory scf = new SingleConnectionFactory(mockConnectionFactory); + JmsTemplate template = createTemplate(); + template.setConnectionFactory(scf); + + mockConnection.start(); + connectionControl.setVoidCallable(3); + // We're gonna call getTransacted 3 times, i.e. 2 more times. + mockSession.getTransacted(); + sessionControl.setReturnValue(useTransactedSession(), 2); + if (useTransactedTemplate()) { + mockSession.commit(); + sessionControl.setVoidCallable(1); + } + mockSession.close(); + sessionControl.setVoidCallable(1); + mockConnection.stop(); + connectionControl.setVoidCallable(1); + mockConnection.close(); + connectionControl.setVoidCallable(1); + + sessionControl.replay(); + connectionControl.replay(); + + TransactionSynchronizationManager.initSynchronization(); + try { + template.execute(new SessionCallback() { + public Object doInJms(Session session) throws JMSException { + boolean b = session.getTransacted(); + return null; + } + }); + template.execute(new SessionCallback() { + public Object doInJms(Session session) throws JMSException { + boolean b = session.getTransacted(); + return null; + } + }); + + assertSame(mockSession, ConnectionFactoryUtils.getTransactionalSession(scf, null, false)); + assertSame(mockSession, ConnectionFactoryUtils.getTransactionalSession(scf, scf.createConnection(), false)); + + TransactionAwareConnectionFactoryProxy tacf = new TransactionAwareConnectionFactoryProxy(scf); + Connection tac = tacf.createConnection(); + Session tas = tac.createSession(false, Session.AUTO_ACKNOWLEDGE); + boolean b = tas.getTransacted(); + tas.close(); + tac.close(); + + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + TransactionSynchronization synch = (TransactionSynchronization) synchs.get(0); + synch.beforeCommit(false); + synch.beforeCompletion(); + synch.afterCommit(); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + scf.destroy(); + } + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + + connectionFactoryControl.verify(); + connectionControl.verify(); + sessionControl.verify(); + } + + /** + * Test sending to a destination using the method + * send(Destination d, MessageCreator messageCreator) + */ + public void testSendDestination() throws Exception { + doTestSendDestination(true, false, true, false); + } + + /** + * Test seding to a destination using the method + * send(String d, MessageCreator messageCreator) + */ + public void testSendDestinationName() throws Exception { + doTestSendDestination(false, false, true, false); + } + + /** + * Test sending to a destination using the method + * send(Destination d, MessageCreator messageCreator) using QOS parameters. + */ + public void testSendDestinationWithQOS() throws Exception { + doTestSendDestination(true, false, false, true); + } + + /** + * Test sending to a destination using the method + * send(String d, MessageCreator messageCreator) using QOS parameters. + */ + public void testSendDestinationNameWithQOS() throws Exception { + doTestSendDestination(false, false, false, true); + } + + /** + * Test sending to the default destination. + */ + public void testSendDefaultDestination() throws Exception { + doTestSendDestination(true, true, true, true); + } + + /** + * Test sending to the default destination name. + */ + public void testSendDefaultDestinationName() throws Exception { + doTestSendDestination(false, true, true, true); + } + + /** + * Test sending to the default destination using explicit QOS parameters. + */ + public void testSendDefaultDestinationWithQOS() throws Exception { + doTestSendDestination(true, true, false, false); + } + + /** + * Test sending to the default destination name using explicit QOS parameters. + */ + public void testSendDefaultDestinationNameWithQOS() throws Exception { + doTestSendDestination(false, true, false, false); + } + + /** + * Common method for testing a send method that uses the MessageCreator + * callback but with different QOS options. + * @param ignoreQOS test using default QOS options. + */ + private void doTestSendDestination( + boolean explicitDestination, boolean useDefaultDestination, + boolean ignoreQOS, boolean disableIdAndTimestamp) throws Exception { + + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockConnectionFactory); + + String destinationName = "testDestination"; + + if (useDefaultDestination) { + if (explicitDestination) { + template.setDefaultDestination(mockQueue); + } + else { + template.setDefaultDestinationName(destinationName); + } + } + if (disableIdAndTimestamp) { + template.setMessageIdEnabled(false); + template.setMessageTimestampEnabled(false); + } + + MockControl messageProducerControl = MockControl.createControl(MessageProducer.class); + MessageProducer mockMessageProducer = (MessageProducer) messageProducerControl.getMock(); + + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + mockSession.createProducer(mockQueue); + sessionControl.setReturnValue(mockMessageProducer); + mockSession.createTextMessage("just testing"); + sessionControl.setReturnValue(mockMessage); + + if (useTransactedTemplate()) { + mockSession.commit(); + sessionControl.setVoidCallable(1); + } + + if (disableIdAndTimestamp) { + mockMessageProducer.setDisableMessageID(true); + messageProducerControl.setVoidCallable(1); + mockMessageProducer.setDisableMessageTimestamp(true); + messageProducerControl.setVoidCallable(1); + } + + if (ignoreQOS) { + mockMessageProducer.send(mockMessage); + } + else { + template.setExplicitQosEnabled(true); + template.setDeliveryMode(deliveryMode); + template.setPriority(priority); + template.setTimeToLive(timeToLive); + mockMessageProducer.send(mockMessage, deliveryMode, priority, timeToLive); + } + messageProducerControl.setVoidCallable(1); + + mockMessageProducer.close(); + messageProducerControl.setVoidCallable(1); + mockSession.close(); + sessionControl.setVoidCallable(1); + mockConnection.close(); + connectionControl.setVoidCallable(1); + + messageProducerControl.replay(); + sessionControl.replay(); + connectionControl.replay(); + + if (useDefaultDestination) { + template.send(new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + else { + if (explicitDestination) { + template.send(mockQueue, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + else { + template.send(destinationName, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("just testing"); + } + }); + } + } + + connectionFactoryControl.verify(); + connectionControl.verify(); + sessionControl.verify(); + messageProducerControl.verify(); + } + + public void testConverter() throws Exception { + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockConnectionFactory); + template.setMessageConverter(new SimpleMessageConverter()); + String s = "Hello world"; + + MockControl messageProducerControl = MockControl.createControl(MessageProducer.class); + MessageProducer mockMessageProducer = (MessageProducer) messageProducerControl.getMock(); + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + mockSession.createProducer(mockQueue); + sessionControl.setReturnValue(mockMessageProducer); + mockSession.createTextMessage("Hello world"); + sessionControl.setReturnValue(mockMessage); + + mockMessageProducer.send(mockMessage); + messageProducerControl.setVoidCallable(1); + mockMessageProducer.close(); + messageProducerControl.setVoidCallable(1); + + if (useTransactedTemplate()) { + mockSession.commit(); + sessionControl.setVoidCallable(1); + } + + mockSession.close(); + sessionControl.setVoidCallable(1); + mockConnection.close(); + connectionControl.setVoidCallable(1); + + messageProducerControl.replay(); + sessionControl.replay(); + connectionControl.replay(); + + template.convertAndSend(mockQueue, s); + + messageProducerControl.verify(); + sessionControl.verify(); + connectionControl.verify(); + connectionFactoryControl.verify(); + } + + public void testReceiveDefaultDestination() throws Exception { + doTestReceive(true, true, false, false, false, false, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testReceiveDefaultDestinationName() throws Exception { + doTestReceive(false, true, false, false, false, false, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testReceiveDestination() throws Exception { + doTestReceive(true, false, false, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testReceiveDestinationWithClientAcknowledge() throws Exception { + doTestReceive(true, false, false, true, false, false, 1000); + } + + public void testReceiveDestinationName() throws Exception { + doTestReceive(false, false, false, false, false, true, 1000); + } + + public void testReceiveDefaultDestinationWithSelector() throws Exception { + doTestReceive(true, true, false, false, true, true, 1000); + } + + public void testReceiveDefaultDestinationNameWithSelector() throws Exception { + doTestReceive(false, true, false, false, true, true, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testReceiveDestinationWithSelector() throws Exception { + doTestReceive(true, false, false, false, true, false, 1000); + } + + public void testReceiveDestinationWithClientAcknowledgeWithSelector() throws Exception { + doTestReceive(true, false, false, true, true, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testReceiveDestinationNameWithSelector() throws Exception { + doTestReceive(false, false, false, false, true, false, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testReceiveAndConvertDefaultDestination() throws Exception { + doTestReceive(true, true, true, false, false, false, 1000); + } + + public void testReceiveAndConvertDefaultDestinationName() throws Exception { + doTestReceive(false, true, true, false, false, false, 1000); + } + + public void testReceiveAndConvertDestinationName() throws Exception { + doTestReceive(false, false, true, false, false, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testReceiveAndConvertDestination() throws Exception { + doTestReceive(true, false, true, false, false, true, 1000); + } + + public void testReceiveAndConvertDefaultDestinationWithSelector() throws Exception { + doTestReceive(true, true, true, false, true, true, JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); + } + + public void testReceiveAndConvertDestinationNameWithSelector() throws Exception { + doTestReceive(false, false, true, false, true, true, JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT); + } + + public void testReceiveAndConvertDestinationWithSelector() throws Exception { + doTestReceive(true, false, true, false, true, false, 1000); + } + + private void doTestReceive( + boolean explicitDestination, boolean useDefaultDestination, boolean testConverter, + boolean clientAcknowledge, boolean messageSelector, boolean noLocal, long timeout) + throws Exception { + + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockConnectionFactory); + + String destinationName = "testDestination"; + + if (useDefaultDestination) { + if (explicitDestination) { + template.setDefaultDestination(mockQueue); + } + else { + template.setDefaultDestinationName(destinationName); + } + } + if (noLocal) { + template.setPubSubNoLocal(true); + } + template.setReceiveTimeout(timeout); + + mockConnection.start(); + connectionControl.setVoidCallable(1); + mockConnection.close(); + connectionControl.setVoidCallable(1); + + MockControl messageConsumerControl = MockControl.createControl(MessageConsumer.class); + MessageConsumer mockMessageConsumer = (MessageConsumer) messageConsumerControl.getMock(); + + String selectorString = "selector"; + mockSession.createConsumer(mockQueue, messageSelector ? selectorString : null); + sessionControl.setReturnValue(mockMessageConsumer); + + if (useTransactedTemplate()) { + mockSession.commit(); + sessionControl.setVoidCallable(1); + } + else if (!useTransactedSession()) { + mockSession.getAcknowledgeMode(); + if (clientAcknowledge) { + sessionControl.setReturnValue(Session.CLIENT_ACKNOWLEDGE, 1); + } + else { + sessionControl.setReturnValue(Session.AUTO_ACKNOWLEDGE, 1); + } + } + + mockSession.close(); + sessionControl.setVoidCallable(1); + + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + if (testConverter) { + mockMessage.getText(); + messageControl.setReturnValue("Hello World!"); + } + if (!useTransactedSession() && clientAcknowledge) { + mockMessage.acknowledge(); + messageControl.setVoidCallable(1); + } + + sessionControl.replay(); + connectionControl.replay(); + messageControl.replay(); + + if (timeout == JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT) { + mockMessageConsumer.receiveNoWait(); + } + else if (timeout == JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT) { + mockMessageConsumer.receive(); + } + else { + mockMessageConsumer.receive(timeout); + } + + messageConsumerControl.setReturnValue(mockMessage); + mockMessageConsumer.close(); + messageConsumerControl.setVoidCallable(1); + + messageConsumerControl.replay(); + + Message message = null; + String textFromMessage = null; + + if (useDefaultDestination) { + if (testConverter) { + textFromMessage = (String) + (messageSelector ? template.receiveSelectedAndConvert(selectorString) : + template.receiveAndConvert()); + } + else { + message = (messageSelector ? template.receiveSelected(selectorString) : template.receive()); + } + } + else if (explicitDestination) { + if (testConverter) { + textFromMessage = (String) + (messageSelector ? template.receiveSelectedAndConvert(mockQueue, selectorString) : + template.receiveAndConvert(mockQueue)); + } + else { + message = (messageSelector ? template.receiveSelected(mockQueue, selectorString) : + template.receive(mockQueue)); + } + } + else { + if (testConverter) { + textFromMessage = (String) + (messageSelector ? template.receiveSelectedAndConvert(destinationName, selectorString) : + template.receiveAndConvert(destinationName)); + } + else { + message = (messageSelector ? template.receiveSelected(destinationName, selectorString) : + template.receive(destinationName)); + } + } + + connectionFactoryControl.verify(); + connectionControl.verify(); + sessionControl.verify(); + messageConsumerControl.verify(); + messageControl.verify(); + + if (testConverter) { + assertEquals("Message text should be equal", "Hello World!", textFromMessage); + } + else { + assertEquals("Messages should refer to the same object", message, mockMessage); + } + } + + public void testIllegalStateException() throws Exception { + doTestJmsException(new javax.jms.IllegalStateException(""), org.springframework.jms.IllegalStateException.class); + } + + public void testInvalidClientIDException() throws Exception { + doTestJmsException(new javax.jms.InvalidClientIDException(""), InvalidClientIDException.class); + } + + public void testInvalidDestinationException() throws Exception { + doTestJmsException(new javax.jms.InvalidDestinationException(""), InvalidDestinationException.class); + } + + public void testInvalidSelectorException() throws Exception { + doTestJmsException(new javax.jms.InvalidSelectorException(""), InvalidSelectorException.class); + } + + public void testJmsSecurityException() throws Exception { + doTestJmsException(new javax.jms.JMSSecurityException(""), JmsSecurityException.class); + } + + public void testMessageEOFException() throws Exception { + doTestJmsException(new javax.jms.MessageEOFException(""), MessageEOFException.class); + } + + public void testMessageFormatException() throws Exception { + doTestJmsException(new javax.jms.MessageFormatException(""), MessageFormatException.class); + } + + public void testMessageNotReadableException() throws Exception { + doTestJmsException(new javax.jms.MessageNotReadableException(""), MessageNotReadableException.class); + } + + public void testMessageNotWriteableException() throws Exception { + doTestJmsException(new javax.jms.MessageNotWriteableException(""), MessageNotWriteableException.class); + } + + public void testResourceAllocationException() throws Exception { + doTestJmsException(new javax.jms.ResourceAllocationException(""), ResourceAllocationException.class); + } + + public void testTransactionInProgressException() throws Exception { + doTestJmsException(new javax.jms.TransactionInProgressException(""), TransactionInProgressException.class); + } + + public void testTransactionRolledBackException() throws Exception { + doTestJmsException(new javax.jms.TransactionRolledBackException(""), TransactionRolledBackException.class); + } + + public void testUncategorizedJmsException() throws Exception { + doTestJmsException(new javax.jms.JMSException(""), UncategorizedJmsException.class); + } + + protected void doTestJmsException(JMSException original, Class thrownExceptionClass) throws Exception { + JmsTemplate template = createTemplate(); + template.setConnectionFactory(mockConnectionFactory); + template.setMessageConverter(new SimpleMessageConverter()); + String s = "Hello world"; + + MockControl messageProducerControl = MockControl.createControl(MessageProducer.class); + MessageProducer mockMessageProducer = (MessageProducer) messageProducerControl.getMock(); + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage mockMessage = (TextMessage) messageControl.getMock(); + + sessionControl.reset(); + mockSession.createProducer(mockQueue); + sessionControl.setReturnValue(mockMessageProducer); + mockSession.createTextMessage("Hello world"); + sessionControl.setReturnValue(mockMessage); + + mockMessageProducer.send(mockMessage); + messageProducerControl.setThrowable(original, 1); + mockMessageProducer.close(); + messageProducerControl.setVoidCallable(1); + + mockSession.close(); + sessionControl.setVoidCallable(1); + mockConnection.close(); + connectionControl.setVoidCallable(1); + + messageProducerControl.replay(); + sessionControl.replay(); + connectionControl.replay(); + + try { + template.convertAndSend(mockQueue, s); + fail("Should have thrown JmsException"); + } + catch (JmsException wrappedEx) { + // expected + assertEquals(thrownExceptionClass, wrappedEx.getClass()); + assertEquals(original, wrappedEx.getCause()); + } + + messageProducerControl.verify(); + sessionControl.verify(); + connectionControl.verify(); + connectionFactoryControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTransactedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTransactedTests.java new file mode 100644 index 00000000000..a3874798cc6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/JmsTemplateTransactedTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.core; + +/** + * @author Juergen Hoeller + * @since 06.01.2005 + */ +public class JmsTemplateTransactedTests extends JmsTemplateTests { + + protected boolean useTransactedSession() { + return true; + } + + protected boolean useTransactedTemplate() { + return true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/core/support/JmsGatewaySupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/support/JmsGatewaySupportTests.java new file mode 100644 index 00000000000..1007b4c1d70 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/core/support/JmsGatewaySupportTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.jms.core.support; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.ConnectionFactory; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jms.core.JmsTemplate; + +/** + * @author Mark Pollack + * @since 24.9.2004 + */ +public class JmsGatewaySupportTests extends TestCase { + + public void testJmsGatewaySupportWithConnectionFactory() throws Exception { + MockControl connectionFactoryControl = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory mockConnectionFactory = (ConnectionFactory) connectionFactoryControl.getMock(); + connectionFactoryControl.replay(); + final List test = new ArrayList(); + JmsGatewaySupport gateway = new JmsGatewaySupport() { + protected void initGateway() { + test.add("test"); + } + }; + gateway.setConnectionFactory(mockConnectionFactory); + gateway.afterPropertiesSet(); + assertEquals("Correct ConnectionFactory", mockConnectionFactory, gateway.getConnectionFactory()); + assertEquals("Correct JmsTemplate", mockConnectionFactory, gateway.getJmsTemplate().getConnectionFactory()); + assertEquals("initGatway called", test.size(), 1); + connectionFactoryControl.verify(); + + } + public void testJmsGatewaySupportWithJmsTemplate() throws Exception { + JmsTemplate template = new JmsTemplate(); + final List test = new ArrayList(); + JmsGatewaySupport gateway = new JmsGatewaySupport() { + protected void initGateway() { + test.add("test"); + } + }; + gateway.setJmsTemplate(template); + gateway.afterPropertiesSet(); + assertEquals("Correct JmsTemplate", template, gateway.getJmsTemplate()); + assertEquals("initGateway called", test.size(), 1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/AbstractMessageListenerContainerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/AbstractMessageListenerContainerTests.java new file mode 100644 index 00000000000..77e28962507 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/AbstractMessageListenerContainerTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; + +/** + * Unit tests for the {@link AbstractMessageListenerContainer} class. + * + * @author Rick Evans + */ +public abstract class AbstractMessageListenerContainerTests extends TestCase { + + protected abstract AbstractMessageListenerContainer getContainer(); + + + public void testSettingMessageListenerToANullType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + getContainer().setMessageListener(null); + } + }.runTest(); + } + + public void testSettingMessageListenerToAnUnsupportedType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + getContainer().setMessageListener("Bingo"); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/SimpleMessageListenerContainerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/SimpleMessageListenerContainerTests.java new file mode 100644 index 00000000000..d029d74b752 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/SimpleMessageListenerContainerTests.java @@ -0,0 +1,607 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener; + +import java.util.HashSet; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.easymock.MockControl; +import org.easymock.internal.AlwaysMatcher; + +import org.springframework.core.task.TaskExecutor; +import org.springframework.jms.StubQueue; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class SimpleMessageListenerContainerTests extends AbstractMessageListenerContainerTests { + + private static final String DESTINATION_NAME = "foo"; + + private static final String EXCEPTION_MESSAGE = "This.Is.It"; + + private static final StubQueue QUEUE_DESTINATION = new StubQueue(); + + + private SimpleMessageListenerContainer container; + + + protected void setUp() throws Exception { + this.container = (SimpleMessageListenerContainer) getContainer(); + } + + protected AbstractMessageListenerContainer getContainer() { + return new SimpleMessageListenerContainer(); + } + + + public void testSessionTransactedModeReallyDoesDefaultToFalse() throws Exception { + assertFalse("The [pubSubLocal] property of SimpleMessageListenerContainer " + + "must default to false. Change this test (and the " + + "attendant Javadoc) if you have changed the default.", + container.isPubSubNoLocal()); + } + + public void testSettingConcurrentConsumersToZeroIsNotAllowed() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + container.setConcurrentConsumers(0); + container.afterPropertiesSet(); + } + }.runTest(); + } + + public void testSettingConcurrentConsumersToANegativeValueIsNotAllowed() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + container.setConcurrentConsumers(-198); + container.afterPropertiesSet(); + } + }.runTest(); + } + + public void testInitDoesNotStartTheConnectionIfAutoStartIsSetToFalse() throws Exception { + MockControl mockMessageConsumer = MockControl.createControl(MessageConsumer.class); + MessageConsumer messageConsumer = (MessageConsumer) mockMessageConsumer.getMock(); + messageConsumer.setMessageListener(null); + // anon. inner class passed in, so just expect a call... + mockMessageConsumer.setMatcher(new AlwaysMatcher()); + mockMessageConsumer.setVoidCallable(); + mockMessageConsumer.replay(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + // Queue gets created in order to create MessageConsumer for that Destination... + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + // and then the MessageConsumer gets created... + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + // session gets created in order to register MessageListener... + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + + this.container.setMessageListener(new TestMessageListener()); + this.container.setAutoStartup(false); + this.container.afterPropertiesSet(); + + mockMessageConsumer.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + public void testInitStartsTheConnectionByDefault() throws Exception { + MockControl mockMessageConsumer = MockControl.createControl(MessageConsumer.class); + MessageConsumer messageConsumer = (MessageConsumer) mockMessageConsumer.getMock(); + messageConsumer.setMessageListener(null); + // anon. inner class passed in, so just expect a call... + mockMessageConsumer.setMatcher(new AlwaysMatcher()); + mockMessageConsumer.setVoidCallable(); + mockMessageConsumer.replay(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + // Queue gets created in order to create MessageConsumer for that Destination... + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + // and then the MessageConsumer gets created... + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + // session gets created in order to register MessageListener... + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + // and the connection is start()ed after the listener is registered... + connection.start(); + mockConnection.setVoidCallable(); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + + this.container.setMessageListener(new TestMessageListener()); + this.container.afterPropertiesSet(); + + mockMessageConsumer.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + public void testCorrectSessionExposedForSessionAwareMessageListenerInvocation() throws Exception { + final SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + MockControl mockSession = MockControl.createControl(Session.class); + final Session session = (Session) mockSession.getMock(); + // Queue gets created in order to create MessageConsumer for that Destination... + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + // and then the MessageConsumer gets created... + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + // an exception is thrown, so the rollback logic is being applied here... + session.getTransacted(); + mockSession.setReturnValue(false); + session.getAcknowledgeMode(); + mockSession.setReturnValue(Session.AUTO_ACKNOWLEDGE); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + // session gets created in order to register MessageListener... + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + // and the connection is start()ed after the listener is registered... + connection.start(); + mockConnection.setVoidCallable(); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + final HashSet failure = new HashSet(); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + this.container.setMessageListener(new SessionAwareMessageListener() { + public void onMessage(Message message, Session sess) { + try { + // Check correct Session passed into SessionAwareMessageListener. + assertSame(sess, session); + } + catch (Throwable ex) { + failure.add("MessageListener execution failed: " + ex); + } + } + }); + + this.container.afterPropertiesSet(); + + MockControl mockMessage = MockControl.createControl(Message.class); + final Message message = (Message) mockMessage.getMock(); + mockMessage.replay(); + messageConsumer.sendMessage(message); + + if (!failure.isEmpty()) { + fail(failure.iterator().next().toString()); + } + + mockMessage.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + public void testTaskExecutorCorrectlyInvokedWhenSpecified() throws Exception { + final SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + MockControl mockSession = MockControl.createControl(Session.class); + final Session session = (Session) mockSession.getMock(); + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + session.getTransacted(); + mockSession.setReturnValue(false); + session.getAcknowledgeMode(); + mockSession.setReturnValue(Session.AUTO_ACKNOWLEDGE); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + connection.start(); + mockConnection.setVoidCallable(); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + final TestMessageListener listener = new TestMessageListener(); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + this.container.setMessageListener(listener); + this.container.setTaskExecutor(new TaskExecutor() { + public void execute(Runnable task) { + listener.executorInvoked = true; + assertFalse(listener.listenerInvoked); + task.run(); + assertTrue(listener.listenerInvoked); + } + }); + this.container.afterPropertiesSet(); + + MockControl mockMessage = MockControl.createControl(Message.class); + final Message message = (Message) mockMessage.getMock(); + mockMessage.replay(); + messageConsumer.sendMessage(message); + + assertTrue(listener.executorInvoked); + assertTrue(listener.listenerInvoked); + mockMessage.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + public void testRegisteredExceptionListenerIsInvokedOnException() throws Exception { + final SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + // Queue gets created in order to create MessageConsumer for that Destination... + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + // and then the MessageConsumer gets created... + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + // an exception is thrown, so the rollback logic is being applied here... + session.getTransacted(); + mockSession.setReturnValue(false); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + // session gets created in order to register MessageListener... + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + // and the connection is start()ed after the listener is registered... + connection.start(); + mockConnection.setVoidCallable(); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + final JMSException theException = new JMSException(EXCEPTION_MESSAGE); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + this.container.setMessageListener(new SessionAwareMessageListener() { + public void onMessage(Message message, Session session) throws JMSException { + throw theException; + } + }); + + MockControl mockExceptionListener = MockControl.createControl(ExceptionListener.class); + ExceptionListener exceptionListener = (ExceptionListener) mockExceptionListener.getMock(); + exceptionListener.onException(theException); + mockExceptionListener.setVoidCallable(); + mockExceptionListener.replay(); + + this.container.setExceptionListener(exceptionListener); + this.container.afterPropertiesSet(); + + // manually trigger an Exception with the above bad MessageListener... + MockControl mockMessage = MockControl.createControl(Message.class); + final Message message = (Message) mockMessage.getMock(); + mockMessage.replay(); + + // a Throwable from a MessageListener MUST simply be swallowed... + messageConsumer.sendMessage(message); + + mockExceptionListener.verify(); + mockMessage.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + public void testNoRollbackOccursIfSessionIsNotTransactedAndThatExceptionsDo_NOT_Propagate() throws Exception { + final SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + // Queue gets created in order to create MessageConsumer for that Destination... + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + // and then the MessageConsumer gets created... + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + // an exception is thrown, so the rollback logic is being applied here... + session.getTransacted(); + mockSession.setReturnValue(false); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + // session gets created in order to register MessageListener... + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + // and the connection is start()ed after the listener is registered... + connection.start(); + mockConnection.setVoidCallable(); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + this.container.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + throw new UnsupportedOperationException(); + } + }); + this.container.afterPropertiesSet(); + + // manually trigger an Exception with the above bad MessageListener... + MockControl mockMessage = MockControl.createControl(Message.class); + final Message message = (Message) mockMessage.getMock(); + mockMessage.replay(); + + // a Throwable from a MessageListener MUST simply be swallowed... + messageConsumer.sendMessage(message); + + mockMessage.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + public void testTransactedSessionsGetRollbackLogicAppliedAndThatExceptionsStillDo_NOT_Propagate() throws Exception { + this.container.setSessionTransacted(true); + + final SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + // Queue gets created in order to create MessageConsumer for that Destination... + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + // and then the MessageConsumer gets created... + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + // an exception is thrown, so the rollback logic is being applied here... + session.getTransacted(); + mockSession.setReturnValue(true); + // Session is rolled back 'cos it is transacted... + session.rollback(); + mockSession.setVoidCallable(); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + // session gets created in order to register MessageListener... + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + // and the connection is start()ed after the listener is registered... + connection.start(); + mockConnection.setVoidCallable(); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + this.container.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + throw new UnsupportedOperationException(); + } + }); + this.container.afterPropertiesSet(); + + // manually trigger an Exception with the above bad MessageListener... + MockControl mockMessage = MockControl.createControl(Message.class); + final Message message = (Message) mockMessage.getMock(); + mockMessage.replay(); + + // a Throwable from a MessageListener MUST simply be swallowed... + messageConsumer.sendMessage(message); + + mockMessage.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + public void testDestroyClosesConsumersSessionsAndConnectionInThatOrder() throws Exception { + MockControl mockMessageConsumer = MockControl.createControl(MessageConsumer.class); + MessageConsumer messageConsumer = (MessageConsumer) mockMessageConsumer.getMock(); + messageConsumer.setMessageListener(null); + // anon. inner class passed in, so just expect a call... + mockMessageConsumer.setMatcher(new AlwaysMatcher()); + mockMessageConsumer.setVoidCallable(); + // closing down... + messageConsumer.close(); + mockMessageConsumer.setVoidCallable(); + mockMessageConsumer.replay(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + // Queue gets created in order to create MessageConsumer for that Destination... + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(QUEUE_DESTINATION); + // and then the MessageConsumer gets created... + session.createConsumer(QUEUE_DESTINATION, null); // no MessageSelector... + mockSession.setReturnValue(messageConsumer); + // closing down... + session.close(); + mockSession.setVoidCallable(); + mockSession.replay(); + + MockControl mockConnection = MockControl.createControl(Connection.class); + Connection connection = (Connection) mockConnection.getMock(); + connection.setExceptionListener(this.container); + mockConnection.setVoidCallable(); + // session gets created in order to register MessageListener... + connection.createSession(this.container.isSessionTransacted(), this.container.getSessionAcknowledgeMode()); + mockConnection.setReturnValue(session); + // and the connection is start()ed after the listener is registered... + connection.start(); + mockConnection.setVoidCallable(); + // closing down... + connection.close(); + mockConnection.setVoidCallable(); + mockConnection.replay(); + + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + connectionFactory.createConnection(); + mockConnectionFactory.setReturnValue(connection); + mockConnectionFactory.replay(); + + this.container.setConnectionFactory(connectionFactory); + this.container.setDestinationName(DESTINATION_NAME); + + this.container.setMessageListener(new TestMessageListener()); + this.container.afterPropertiesSet(); + this.container.destroy(); + + mockMessageConsumer.verify(); + mockSession.verify(); + mockConnection.verify(); + mockConnectionFactory.verify(); + } + + + private static class TestMessageListener implements MessageListener { + + public boolean executorInvoked = false; + + public boolean listenerInvoked = false; + + public void onMessage(Message message) { + this.listenerInvoked = true; + } + } + + + private static class SimpleMessageConsumer implements MessageConsumer { + + private MessageListener messageListener; + + public void sendMessage(Message message) throws JMSException { + this.messageListener.onMessage(message); + } + + public String getMessageSelector() throws JMSException { + throw new UnsupportedOperationException(); + } + + public MessageListener getMessageListener() throws JMSException { + return this.messageListener; + } + + public void setMessageListener(MessageListener messageListener) throws JMSException { + this.messageListener = messageListener; + } + + public Message receive() throws JMSException { + throw new UnsupportedOperationException(); + } + + public Message receive(long l) throws JMSException { + throw new UnsupportedOperationException(); + } + + public Message receiveNoWait() throws JMSException { + throw new UnsupportedOperationException(); + } + + public void close() throws JMSException { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageContentsDelegate.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageContentsDelegate.java new file mode 100644 index 00000000000..6686a8e53a3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageContentsDelegate.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +import java.util.Map; + +/** + * See the MessageListenerAdapterTests class for usage. + * + * @author Rick Evans + * @author Juergen Hoeller + */ +public interface MessageContentsDelegate { + + void handleMessage(CharSequence message); + + void handleMessage(Map message); + + void handleMessage(byte[] message); + + void handleMessage(Number message); + + void handleMessage(Object message); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageDelegate.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageDelegate.java new file mode 100644 index 00000000000..ecff85c7bc5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageDelegate.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +import javax.jms.BytesMessage; +import javax.jms.MapMessage; +import javax.jms.ObjectMessage; +import javax.jms.TextMessage; + +/** + * See the MessageListenerAdapterTests class for usage. + * + * @author Rick Evans + */ +public interface MessageDelegate { + + void handleMessage(TextMessage message); + + void handleMessage(MapMessage message); + + void handleMessage(BytesMessage message); + + void handleMessage(ObjectMessage message); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapter102Tests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapter102Tests.java new file mode 100644 index 00000000000..f9e44d1b6a3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapter102Tests.java @@ -0,0 +1,432 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.springframework.jms.support.converter.SimpleMessageConverter102; +import org.springframework.test.AssertThrows; + +import javax.jms.*; + +/** + * Unit tests for the {@link MessageListenerAdapter102} class. + * + * @author Rick Evans + */ +public final class MessageListenerAdapter102Tests extends TestCase { + + private static final String TEXT = "The Runaways"; + private static final String CORRELATION_ID = "100"; + private static final String RESPONSE_TEXT = "Old Lace"; + + + public void testWithMessageContentsDelegateForBytesMessage() throws Exception { + + MockControl mockBytesMessage = MockControl.createControl(BytesMessage.class); + BytesMessage bytesMessage = (BytesMessage) mockBytesMessage.getMock(); + // BytesMessage contents must be unwrapped... + bytesMessage.readBytes(null); + mockBytesMessage.setMatcher(MockControl.ALWAYS_MATCHER); + mockBytesMessage.setReturnValue(TEXT.getBytes().length); + mockBytesMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageContentsDelegate.class); + MessageContentsDelegate delegate = (MessageContentsDelegate) mockDelegate.getMock(); + delegate.handleMessage(TEXT.getBytes()); + mockDelegate.setMatcher(MockControl.ALWAYS_MATCHER); + mockDelegate.setVoidCallable(); + mockDelegate.replay(); + + MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate); + adapter.onMessage(bytesMessage); + + mockDelegate.verify(); + mockBytesMessage.verify(); + } + + public void testWithMessageDelegate() throws Exception { + + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + mockTextMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageDelegate.class); + MessageDelegate delegate = (MessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(textMessage); + mockDelegate.setVoidCallable(); + mockDelegate.replay(); + + MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate); + // we DON'T want the default SimpleMessageConversion happening... + adapter.setMessageConverter(null); + adapter.onMessage(textMessage); + + mockDelegate.verify(); + mockTextMessage.verify(); + } + + public void testThatTheDefaultMessageConverterisIndeedTheSimpleMessageConverter102() throws Exception { + MessageListenerAdapter102 adapter = new MessageListenerAdapter102(); + assertNotNull("The default [MessageConverter] must never be null.", adapter.getMessageConverter()); + assertTrue("The default [MessageConverter] must be of the type [SimpleMessageConverter102]; if you've just changed it, then change this test to reflect your change.", adapter.getMessageConverter() instanceof SimpleMessageConverter102); + } + + public void testWithResponsiveMessageDelegate_DoesNotSendReturnTextMessageIfNoSessionSupplied() throws Exception { + + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + mockTextMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(textMessage); + mockDelegate.setReturnValue(TEXT); + mockDelegate.replay(); + + MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate); + // we DON'T want the default SimpleMessageConversion happening... + adapter.setMessageConverter(null); + adapter.onMessage(textMessage); + + mockDelegate.verify(); + mockTextMessage.verify(); + } + + public void testWithResponsiveMessageDelegateWithDefaultDestination_SendsReturnTextMessageWhenSessionSuppliedForQueue() throws Exception { + + MockControl mockDestination = MockControl.createControl(Queue.class); + Queue destination = (Queue) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(null); // we want to fall back to the default... + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockQueueSender = MockControl.createControl(QueueSender.class); + QueueSender queueSender = (QueueSender) mockQueueSender.getMock(); + queueSender.send(responseTextMessage); + mockQueueSender.setVoidCallable(); + queueSender.close(); + mockQueueSender.setVoidCallable(); + mockQueueSender.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + QueueSession session = (QueueSession) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + session.createSender(destination); + mockSession.setReturnValue(queueSender); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + adapter.setDefaultResponseDestination(destination); + adapter.onMessage(sentTextMessage, session); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + mockDestination.verify(); + mockQueueSender.verify(); + } + + public void testWithResponsiveMessageDelegateWithDefaultDestination_SendsReturnTextMessageWhenSessionSuppliedForTopic() throws Exception { + + MockControl mockDestination = MockControl.createControl(Topic.class); + Topic destination = (Topic) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(null); // we want to fall back to the default... + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockTopicPublisher = MockControl.createControl(TopicPublisher.class); + TopicPublisher topicPublisher = (TopicPublisher) mockTopicPublisher.getMock(); + topicPublisher.publish(responseTextMessage); + mockTopicPublisher.setVoidCallable(); + topicPublisher.close(); + mockTopicPublisher.setVoidCallable(); + mockTopicPublisher.replay(); + + MockControl mockSession = MockControl.createControl(TopicSession.class); + TopicSession session = (TopicSession) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + session.createPublisher(destination); + mockSession.setReturnValue(topicPublisher); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + adapter.setDefaultResponseDestination(destination); + adapter.onMessage(sentTextMessage, session); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + mockDestination.verify(); + mockTopicPublisher.verify(); + } + + public void testWithResponsiveMessageDelegateNoDefaultDestination_SendsReturnTextMessageWhenSessionSupplied() throws Exception { + + MockControl mockDestination = MockControl.createControl(Queue.class); + Queue destination = (Queue) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(destination); + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockQueueSender = MockControl.createControl(QueueSender.class); + QueueSender queueSender = (QueueSender) mockQueueSender.getMock(); + queueSender.send(responseTextMessage); + mockQueueSender.setVoidCallable(); + queueSender.close(); + mockQueueSender.setVoidCallable(); + mockQueueSender.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + QueueSession session = (QueueSession) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + session.createSender(destination); + mockSession.setReturnValue(queueSender); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + adapter.onMessage(sentTextMessage, session); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + mockDestination.verify(); + mockQueueSender.verify(); + } + + public void testWithResponsiveMessageDelegateNoDefaultDestinationAndNoReplyToDestination_SendsReturnTextMessageWhenSessionSupplied() throws Exception { + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + final TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(null); + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + final QueueSession session = (QueueSession) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + final MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + new AssertThrows(InvalidDestinationException.class) { + public void test() throws Exception { + adapter.onMessage(sentTextMessage, session); + } + }.runTest(); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + } + + public void testWithResponsiveMessageDelegateNoDefaultDestination_SendsReturnTextMessageWhenSessionSupplied_AndSendingThrowsJMSException() throws Exception { + + MockControl mockDestination = MockControl.createControl(Queue.class); + Queue destination = (Queue) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + final TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(destination); + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockQueueSender = MockControl.createControl(QueueSender.class); + QueueSender queueSender = (QueueSender) mockQueueSender.getMock(); + queueSender.send(responseTextMessage); + mockQueueSender.setThrowable(new JMSException("Dow!")); + // ensure that regardless of a JMSException the producer is closed... + queueSender.close(); + mockQueueSender.setVoidCallable(); + mockQueueSender.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + final QueueSession session = (QueueSession) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + session.createSender(destination); + mockSession.setReturnValue(queueSender); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + final MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + new AssertThrows(JMSException.class) { + public void test() throws Exception { + adapter.onMessage(sentTextMessage, session); + } + }.runTest(); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + mockDestination.verify(); + mockQueueSender.verify(); + } + + public void testWithResponsiveMessageDelegateDoesNotSendReturnTextMessageWhenSessionSupplied_AndListenerMethodThrowsException() throws Exception { + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + final TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + mockSentTextMessage.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + final QueueSession session = (QueueSession) mockSession.getMock(); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setThrowable(new IllegalArgumentException("Dow!")); + mockDelegate.replay(); + + final MessageListenerAdapter102 adapter = new MessageListenerAdapter102(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + new AssertThrows(ListenerExecutionFailedException.class) { + public void test() throws Exception { + adapter.onMessage(sentTextMessage, session); + } + }.runTest(); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockSession.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapterTests.java new file mode 100644 index 00000000000..b66d07a9076 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/MessageListenerAdapterTests.java @@ -0,0 +1,657 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +import java.io.Serializable; + +import javax.jms.BytesMessage; +import javax.jms.IllegalStateException; +import javax.jms.InvalidDestinationException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jms.support.converter.MessageConversionException; +import org.springframework.jms.support.converter.SimpleMessageConverter; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class MessageListenerAdapterTests extends TestCase { + + private static final String TEXT = "I fancy a good cuppa right now"; + + private static final Integer NUMBER = new Integer(1); + + private static final SerializableObject OBJECT = new SerializableObject(); + + private static final String CORRELATION_ID = "100"; + + private static final String RESPONSE_TEXT = "... wi' some full fat creamy milk. Top banana."; + + + public void testWithMessageContentsDelegateForTextMessage() throws Exception { + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + // TextMessage contents must be unwrapped... + textMessage.getText(); + mockTextMessage.setReturnValue(TEXT); + mockTextMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageContentsDelegate.class); + MessageContentsDelegate delegate = (MessageContentsDelegate) mockDelegate.getMock(); + delegate.handleMessage(TEXT); + mockDelegate.setVoidCallable(); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate); + adapter.onMessage(textMessage); + + mockDelegate.verify(); + mockTextMessage.verify(); + } + + public void testWithMessageContentsDelegateForBytesMessage() throws Exception { + MockControl mockBytesMessage = MockControl.createControl(BytesMessage.class); + BytesMessage bytesMessage = (BytesMessage) mockBytesMessage.getMock(); + // BytesMessage contents must be unwrapped... + bytesMessage.getBodyLength(); + mockBytesMessage.setReturnValue(TEXT.getBytes().length); + bytesMessage.readBytes(null); + mockBytesMessage.setMatcher(MockControl.ALWAYS_MATCHER); + mockBytesMessage.setReturnValue(TEXT.getBytes().length); + mockBytesMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageContentsDelegate.class); + MessageContentsDelegate delegate = (MessageContentsDelegate) mockDelegate.getMock(); + delegate.handleMessage(TEXT.getBytes()); + mockDelegate.setMatcher(MockControl.ALWAYS_MATCHER); + mockDelegate.setVoidCallable(); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate); + adapter.onMessage(bytesMessage); + + mockDelegate.verify(); + mockBytesMessage.verify(); + } + + public void testWithMessageContentsDelegateForObjectMessage() throws Exception { + MockControl mockObjectMessage = MockControl.createControl(ObjectMessage.class); + ObjectMessage objectMessage = (ObjectMessage) mockObjectMessage.getMock(); + objectMessage.getObject(); + mockObjectMessage.setReturnValue(NUMBER); + mockObjectMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageContentsDelegate.class); + MessageContentsDelegate delegate = (MessageContentsDelegate) mockDelegate.getMock(); + delegate.handleMessage(NUMBER); + mockDelegate.setVoidCallable(); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate); + adapter.onMessage(objectMessage); + + mockDelegate.verify(); + mockObjectMessage.verify(); + } + + public void testWithMessageContentsDelegateForObjectMessageWithPlainObject() throws Exception { + MockControl mockObjectMessage = MockControl.createControl(ObjectMessage.class); + ObjectMessage objectMessage = (ObjectMessage) mockObjectMessage.getMock(); + objectMessage.getObject(); + mockObjectMessage.setReturnValue(OBJECT); + mockObjectMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageContentsDelegate.class); + MessageContentsDelegate delegate = (MessageContentsDelegate) mockDelegate.getMock(); + delegate.handleMessage(OBJECT); + mockDelegate.setVoidCallable(); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate); + adapter.onMessage(objectMessage); + + mockDelegate.verify(); + mockObjectMessage.verify(); + } + + public void testWithMessageDelegate() throws Exception { + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + mockTextMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageDelegate.class); + MessageDelegate delegate = (MessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(textMessage); + mockDelegate.setVoidCallable(); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate); + // we DON'T want the default SimpleMessageConversion happening... + adapter.setMessageConverter(null); + adapter.onMessage(textMessage); + + mockDelegate.verify(); + mockTextMessage.verify(); + } + + public void testWhenTheAdapterItselfIsTheDelegate() throws Exception { + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + // TextMessage contents must be unwrapped... + textMessage.getText(); + mockTextMessage.setReturnValue(TEXT); + mockTextMessage.replay(); + + StubMessageListenerAdapter adapter = new StubMessageListenerAdapter(); + adapter.onMessage(textMessage); + assertTrue(adapter.wasCalled()); + + mockTextMessage.verify(); + } + + public void testRainyDayWithNoApplicableHandlingMethods() throws Exception { + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + // TextMessage contents must be unwrapped... + textMessage.getText(); + mockTextMessage.setReturnValue(TEXT); + mockTextMessage.replay(); + + StubMessageListenerAdapter adapter = new StubMessageListenerAdapter(); + adapter.setDefaultListenerMethod("walnutsRock"); + adapter.onMessage(textMessage); + assertFalse(adapter.wasCalled()); + + mockTextMessage.verify(); + } + + public void testThatAnExceptionThrownFromTheHandlingMethodIsSimplySwallowedByDefault() throws Exception { + final IllegalArgumentException exception = new IllegalArgumentException(); + + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + mockTextMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(MessageDelegate.class); + MessageDelegate delegate = (MessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(textMessage); + mockDelegate.setThrowable(exception); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected void handleListenerException(Throwable ex) { + assertNotNull("The Throwable passed to the handleListenerException(..) method must never be null.", ex); + assertTrue("The Throwable passed to the handleListenerException(..) method must be of type [ListenerExecutionFailedException].", + ex instanceof ListenerExecutionFailedException); + ListenerExecutionFailedException lefx = (ListenerExecutionFailedException) ex; + Throwable cause = lefx.getCause(); + assertNotNull("The cause of a ListenerExecutionFailedException must be preserved.", cause); + assertSame(exception, cause); + } + }; + // we DON'T want the default SimpleMessageConversion happening... + adapter.setMessageConverter(null); + adapter.onMessage(textMessage); + + mockDelegate.verify(); + mockTextMessage.verify(); + } + + public void testThatTheDefaultMessageConverterisIndeedTheSimpleMessageConverter() throws Exception { + MessageListenerAdapter adapter = new MessageListenerAdapter(); + assertNotNull("The default [MessageConverter] must never be null.", adapter.getMessageConverter()); + assertTrue("The default [MessageConverter] must be of the type [SimpleMessageConverter]", + adapter.getMessageConverter() instanceof SimpleMessageConverter); + } + + public void testThatWhenNoDelegateIsSuppliedTheDelegateIsAssumedToBeTheMessageListenerAdapterItself() throws Exception { + MessageListenerAdapter adapter = new MessageListenerAdapter(); + assertSame(adapter, adapter.getDelegate()); + } + + public void testThatTheDefaultMessageHandlingMethodNameIsTheConstantDefault() throws Exception { + MessageListenerAdapter adapter = new MessageListenerAdapter(); + assertEquals(MessageListenerAdapter.ORIGINAL_DEFAULT_LISTENER_METHOD, adapter.getDefaultListenerMethod()); + } + + public void testWithResponsiveMessageDelegate_DoesNotSendReturnTextMessageIfNoSessionSupplied() throws Exception { + MockControl mockTextMessage = MockControl.createControl(TextMessage.class); + TextMessage textMessage = (TextMessage) mockTextMessage.getMock(); + mockTextMessage.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(textMessage); + mockDelegate.setReturnValue(TEXT); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate); + // we DON'T want the default SimpleMessageConversion happening... + adapter.setMessageConverter(null); + adapter.onMessage(textMessage); + + mockDelegate.verify(); + mockTextMessage.verify(); + } + + public void testWithResponsiveMessageDelegateWithDefaultDestination_SendsReturnTextMessageWhenSessionSupplied() throws Exception { + MockControl mockDestination = MockControl.createControl(Queue.class); + Queue destination = (Queue) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(null); // we want to fall back to the default... + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockQueueSender = MockControl.createControl(QueueSender.class); + QueueSender queueSender = (QueueSender) mockQueueSender.getMock(); + queueSender.send(responseTextMessage); + mockQueueSender.setVoidCallable(); + queueSender.close(); + mockQueueSender.setVoidCallable(); + mockQueueSender.replay(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + session.createProducer(destination); + mockSession.setReturnValue(queueSender); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + adapter.setDefaultResponseDestination(destination); + adapter.onMessage(sentTextMessage, session); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + mockDestination.verify(); + mockQueueSender.verify(); + } + + public void testWithResponsiveMessageDelegateNoDefaultDestination_SendsReturnTextMessageWhenSessionSupplied() throws Exception { + MockControl mockDestination = MockControl.createControl(Queue.class); + Queue destination = (Queue) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(null); + sentTextMessage.getJMSMessageID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(destination); + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockMessageProducer = MockControl.createControl(MessageProducer.class); + MessageProducer messageProducer = (MessageProducer) mockMessageProducer.getMock(); + messageProducer.send(responseTextMessage); + mockMessageProducer.setVoidCallable(); + messageProducer.close(); + mockMessageProducer.setVoidCallable(); + mockMessageProducer.replay(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + session.createProducer(destination); + mockSession.setReturnValue(messageProducer); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + adapter.onMessage(sentTextMessage, session); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + mockDestination.verify(); + mockMessageProducer.verify(); + } + + public void testWithResponsiveMessageDelegateNoDefaultDestinationAndNoReplyToDestination_SendsReturnTextMessageWhenSessionSupplied() throws Exception { + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + final TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(null); + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + final QueueSession session = (QueueSession) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + final MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + new AssertThrows(InvalidDestinationException.class) { + public void test() throws Exception { + adapter.onMessage(sentTextMessage, session); + } + }.runTest(); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + } + + public void testWithResponsiveMessageDelegateNoDefaultDestination_SendsReturnTextMessageWhenSessionSupplied_AndSendingThrowsJMSException() throws Exception { + MockControl mockDestination = MockControl.createControl(Queue.class); + Queue destination = (Queue) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + final TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(destination); + mockSentTextMessage.replay(); + + MockControl mockResponseTextMessage = MockControl.createControl(TextMessage.class); + TextMessage responseTextMessage = (TextMessage) mockResponseTextMessage.getMock(); + responseTextMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseTextMessage.setVoidCallable(); + mockResponseTextMessage.replay(); + + MockControl mockMessageProducer = MockControl.createControl(MessageProducer.class); + MessageProducer messageProducer = (MessageProducer) mockMessageProducer.getMock(); + messageProducer.send(responseTextMessage); + mockMessageProducer.setThrowable(new JMSException("Dow!")); + // ensure that regardless of a JMSException the producer is closed... + messageProducer.close(); + mockMessageProducer.setVoidCallable(); + mockMessageProducer.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + final QueueSession session = (QueueSession) mockSession.getMock(); + session.createTextMessage(RESPONSE_TEXT); + mockSession.setReturnValue(responseTextMessage); + session.createProducer(destination); + mockSession.setReturnValue(messageProducer); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + final MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + new AssertThrows(JMSException.class) { + public void test() throws Exception { + adapter.onMessage(sentTextMessage, session); + } + }.runTest(); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockResponseTextMessage.verify(); + mockSession.verify(); + mockDestination.verify(); + mockMessageProducer.verify(); + } + + public void testWithResponsiveMessageDelegateDoesNotSendReturnTextMessageWhenSessionSupplied_AndListenerMethodThrowsException() throws Exception { + MockControl mockMessage = MockControl.createControl(TextMessage.class); + final TextMessage message = (TextMessage) mockMessage.getMock(); + mockMessage.replay(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + final QueueSession session = (QueueSession) mockSession.getMock(); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(message); + mockDelegate.setThrowable(new IllegalArgumentException("Dow!")); + mockDelegate.replay(); + + final MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + new AssertThrows(ListenerExecutionFailedException.class) { + public void test() throws Exception { + adapter.onMessage(message, session); + } + }.runTest(); + + mockDelegate.verify(); + mockMessage.verify(); + mockSession.verify(); + } + + public void testFailsIfNoDefaultListenerMethodNameIsSupplied() throws Exception { + MockControl mockMessage = MockControl.createControl(TextMessage.class); + final TextMessage message = (TextMessage) mockMessage.getMock(); + message.getText(); + mockMessage.setReturnValue(TEXT); + + mockMessage.replay(); + + final MessageListenerAdapter adapter = new MessageListenerAdapter() { + protected void handleListenerException(Throwable ex) { + assertTrue(ex instanceof IllegalStateException); + } + }; + adapter.setDefaultListenerMethod(null); + adapter.onMessage(message); + + mockMessage.verify(); + } + + public void testFailsWhenOverriddenGetListenerMethodNameReturnsNull() throws Exception { + MockControl mockMessage = MockControl.createControl(TextMessage.class); + final TextMessage message = (TextMessage) mockMessage.getMock(); + message.getText(); + mockMessage.setReturnValue(TEXT); + + mockMessage.replay(); + + final MessageListenerAdapter adapter = new MessageListenerAdapter() { + protected void handleListenerException(Throwable ex) { + assertTrue(ex instanceof javax.jms.IllegalStateException); + } + protected String getListenerMethodName(Message originalMessage, Object extractedMessage) { + return null; + } + }; + adapter.setDefaultListenerMethod(null); + adapter.onMessage(message); + + mockMessage.verify(); + } + + public void testWithResponsiveMessageDelegateWhenReturnTypeIsNotAJMSMessageAndNoMessageConverterIsSupplied() throws Exception { + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + final TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + mockSentTextMessage.replay(); + + MockControl mockSession = MockControl.createControl(Session.class); + final Session session = (Session) mockSession.getMock(); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveMessageDelegate.class); + ResponsiveMessageDelegate delegate = (ResponsiveMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(RESPONSE_TEXT); + mockDelegate.replay(); + + final MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + adapter.setMessageConverter(null); + new AssertThrows(MessageConversionException.class) { + public void test() throws Exception { + adapter.onMessage(sentTextMessage, session); + } + }.runTest(); + + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockSession.verify(); + } + + public void testWithResponsiveMessageDelegateWhenReturnTypeIsAJMSMessageAndNoMessageConverterIsSupplied() throws Exception { + MockControl mockDestination = MockControl.createControl(Queue.class); + Queue destination = (Queue) mockDestination.getMock(); + mockDestination.replay(); + + MockControl mockSentTextMessage = MockControl.createControl(TextMessage.class); + final TextMessage sentTextMessage = (TextMessage) mockSentTextMessage.getMock(); + // correlation ID is queried when response is being created... + sentTextMessage.getJMSCorrelationID(); + mockSentTextMessage.setReturnValue(CORRELATION_ID); + // Reply-To is queried when response is being created... + sentTextMessage.getJMSReplyTo(); + mockSentTextMessage.setReturnValue(destination); + mockSentTextMessage.replay(); + + MockControl mockResponseMessage = MockControl.createControl(TextMessage.class); + TextMessage responseMessage = (TextMessage) mockResponseMessage.getMock(); + responseMessage.setJMSCorrelationID(CORRELATION_ID); + mockResponseMessage.setVoidCallable(); + mockResponseMessage.replay(); + + MockControl mockQueueSender = MockControl.createControl(QueueSender.class); + QueueSender queueSender = (QueueSender) mockQueueSender.getMock(); + queueSender.send(responseMessage); + mockQueueSender.setVoidCallable(); + queueSender.close(); + mockQueueSender.setVoidCallable(); + mockQueueSender.replay(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + session.createProducer(destination); + mockSession.setReturnValue(queueSender); + mockSession.replay(); + + MockControl mockDelegate = MockControl.createControl(ResponsiveJmsTextMessageReturningMessageDelegate.class); + ResponsiveJmsTextMessageReturningMessageDelegate delegate = (ResponsiveJmsTextMessageReturningMessageDelegate) mockDelegate.getMock(); + delegate.handleMessage(sentTextMessage); + mockDelegate.setReturnValue(responseMessage); + mockDelegate.replay(); + + final MessageListenerAdapter adapter = new MessageListenerAdapter(delegate) { + protected Object extractMessage(Message message) { + return message; + } + }; + adapter.setMessageConverter(null); + adapter.onMessage(sentTextMessage, session); + + mockDestination.verify(); + mockDelegate.verify(); + mockSentTextMessage.verify(); + mockSession.verify(); + mockQueueSender.verify(); + mockResponseMessage.verify(); + } + + + private static class SerializableObject implements Serializable { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveJmsTextMessageReturningMessageDelegate.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveJmsTextMessageReturningMessageDelegate.java new file mode 100644 index 00000000000..ffa07f4f294 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveJmsTextMessageReturningMessageDelegate.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +import javax.jms.TextMessage; +import javax.jms.MapMessage; +import javax.jms.BytesMessage; +import javax.jms.ObjectMessage; + +import java.util.Map; +import java.io.Serializable; + +/** + * See the MessageListenerAdapterTests class for usage. + * + * @author Rick Evans + */ +public interface ResponsiveJmsTextMessageReturningMessageDelegate { + + TextMessage handleMessage(TextMessage message); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveMessageDelegate.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveMessageDelegate.java new file mode 100644 index 00000000000..cb1dedb0939 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/ResponsiveMessageDelegate.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +import java.io.Serializable; +import java.util.Map; + +import javax.jms.BytesMessage; +import javax.jms.MapMessage; +import javax.jms.ObjectMessage; +import javax.jms.TextMessage; + +/** + * See the MessageListenerAdapterTests class for usage. + * + * @author Rick Evans + */ +public interface ResponsiveMessageDelegate { + + String handleMessage(TextMessage message); + + Map handleMessage(MapMessage message); + + byte[] handleMessage(BytesMessage message); + + Serializable handleMessage(ObjectMessage message); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter.java new file mode 100644 index 00000000000..4973cda8ce5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +/** + * Stub extension of the {@link MessageListenerAdapter} class for use in testing. + * + * @author Rick Evans + */ +public class StubMessageListenerAdapter extends MessageListenerAdapter { + + private boolean wasCalled; + + + public boolean wasCalled() { + return this.wasCalled; + } + + + public void handleMessage(String message) { + this.wasCalled = true; + } + + protected void handleListenerException(Throwable ex) { + System.out.println(ex); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter102.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter102.java new file mode 100644 index 00000000000..20ea0c40bb6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/adapter/StubMessageListenerAdapter102.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.adapter; + +/** + * Stub extension of the {@link MessageListenerAdapter102} class for use in testing. + * + * @author Rick Evans + */ +public class StubMessageListenerAdapter102 extends MessageListenerAdapter102 { + + private boolean wasCalled; + + + public boolean wasCalled() { + return this.wasCalled; + } + + + public void handleMessage(String message) { + this.wasCalled = true; + } + + protected void handleListenerException(Throwable ex) { + System.out.println(ex); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/DefaultJmsActivationSpecFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/DefaultJmsActivationSpecFactoryTests.java new file mode 100644 index 00000000000..3b7e23a91f6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/DefaultJmsActivationSpecFactoryTests.java @@ -0,0 +1,168 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.endpoint; + +import javax.jms.Destination; +import javax.jms.Session; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jca.StubResourceAdapter; +import org.springframework.jms.StubQueue; +import org.springframework.jms.support.destination.DestinationResolver; + +/** + * @author Agim Emruli + * @author Juergen Hoeller + */ +public class DefaultJmsActivationSpecFactoryTests extends TestCase { + + private JmsActivationSpecConfig activationSpecConfig; + + protected void setUp() throws Exception { + activationSpecConfig = new JmsActivationSpecConfig(); + activationSpecConfig.setMaxConcurrency(5); + activationSpecConfig.setPrefetchSize(3); + activationSpecConfig.setAcknowledgeMode(Session.AUTO_ACKNOWLEDGE); + activationSpecConfig.setClientId("clientid"); + activationSpecConfig.setDestinationName("destinationname"); + activationSpecConfig.setDurableSubscriptionName("durableSubscriptionName"); + activationSpecConfig.setMessageSelector("selector"); + } + + public void testActiveMQResourceAdapterSetup() { + activationSpecConfig.setAcknowledgeMode(Session.SESSION_TRANSACTED); + JmsActivationSpecFactory activationSpecFactory = new DefaultJmsActivationSpecFactory(); + StubActiveMQActivationSpec spec = (StubActiveMQActivationSpec) activationSpecFactory.createActivationSpec( + new StubActiveMQResourceAdapter(), activationSpecConfig); + + assertEquals(5, spec.getMaxSessions()); + assertEquals(3, spec.getMaxMessagesPerSessions()); + assertTrue(spec.isUseRAManagedTransaction()); + } + + public void testWebSphereResourceAdapterSetup() throws Exception { + Destination destination = new StubQueue(); + + MockControl control = MockControl.createControl(DestinationResolver.class); + DestinationResolver destinationResolver = (DestinationResolver) control.getMock(); + + destinationResolver.resolveDestinationName(null, "destinationname", false); + control.setReturnValue(destination); + control.replay(); + + DefaultJmsActivationSpecFactory activationSpecFactory = new DefaultJmsActivationSpecFactory(); + activationSpecFactory.setDestinationResolver(destinationResolver); + + StubWebSphereActivationSpecImpl spec = (StubWebSphereActivationSpecImpl) activationSpecFactory + .createActivationSpec(new StubWebSphereResourceAdapterImpl(), activationSpecConfig); + + control.verify(); + + assertEquals(destination, spec.getDestination()); + assertEquals(5, spec.getMaxConcurrency()); + assertEquals(3, spec.getMaxBatchSize()); + } + + + private static class StubActiveMQResourceAdapter extends StubResourceAdapter { + } + + + private static class StubWebSphereResourceAdapterImpl extends StubResourceAdapter { + } + + + private static class StubActiveMQActivationSpec extends StubJmsActivationSpec { + + private int maxSessions; + + private int maxMessagesPerSessions; + + private String destination; + + private boolean useRAManagedTransaction; + + public void setMaxSessions(int maxSessions) { + this.maxSessions = maxSessions; + } + + public void setMaxMessagesPerSessions(int maxMessagesPerSessions) { + this.maxMessagesPerSessions = maxMessagesPerSessions; + } + + public int getMaxSessions() { + return maxSessions; + } + + public int getMaxMessagesPerSessions() { + return maxMessagesPerSessions; + } + + public String getDestination() { + return destination; + } + + public void setDestination(String destination) { + this.destination = destination; + } + + public boolean isUseRAManagedTransaction() { + return useRAManagedTransaction; + } + + public void setUseRAManagedTransaction(boolean useRAManagedTransaction) { + this.useRAManagedTransaction = useRAManagedTransaction; + } + } + + + private static class StubWebSphereActivationSpecImpl extends StubJmsActivationSpec { + + private Destination destination; + + private int maxConcurrency; + + private int maxBatchSize; + + public void setDestination(Destination destination) { + this.destination = destination; + } + + public Destination getDestination() { + return destination; + } + + public int getMaxConcurrency() { + return maxConcurrency; + } + + public void setMaxConcurrency(int maxConcurrency) { + this.maxConcurrency = maxConcurrency; + } + + public int getMaxBatchSize() { + return maxBatchSize; + } + + public void setMaxBatchSize(int maxBatchSize) { + this.maxBatchSize = maxBatchSize; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpec.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpec.java new file mode 100644 index 00000000000..6ffa02b4881 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpec.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.endpoint; + +import javax.jms.Destination; + +import org.springframework.jca.StubActivationSpec; + +/** + * StubActivationSpec which implements all required and optional properties (see + * specification Appendix B.2) except the destination attribute. Because this + * can be a string but also an {@link Destination} object, which is configured + * as an administrated object. + * + * @author Agim Emruli + */ +public class StubJmsActivationSpec extends StubActivationSpec { + + private String destinationType; + + private String subscriptionDurability; + + private String subscriptionName; + + private String clientId; + + private String messageSelector; + + private String acknowledgeMode; + + + public String getDestinationType() { + return destinationType; + } + + public void setDestinationType(String destinationType) { + this.destinationType = destinationType; + } + + public String getSubscriptionDurability() { + return subscriptionDurability; + } + + public void setSubscriptionDurability(String subscriptionDurability) { + this.subscriptionDurability = subscriptionDurability; + } + + public String getSubscriptionName() { + return subscriptionName; + } + + public void setSubscriptionName(String subscriptionName) { + this.subscriptionName = subscriptionName; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getMessageSelector() { + return messageSelector; + } + + public void setMessageSelector(String messageSelector) { + this.messageSelector = messageSelector; + } + + public String getAcknowledgeMode() { + return acknowledgeMode; + } + + public void setAcknowledgeMode(String acknowledgeMode) { + this.acknowledgeMode = acknowledgeMode; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpecFactory.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpecFactory.java new file mode 100644 index 00000000000..1be6176bd69 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/listener/endpoint/StubJmsActivationSpecFactory.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.listener.endpoint; + +import javax.resource.spi.ActivationSpec; +import javax.resource.spi.ResourceAdapter; + +import org.springframework.jca.StubActivationSpec; + +/** + * @author Juergen Hoeller + */ +public class StubJmsActivationSpecFactory implements JmsActivationSpecFactory { + + public ActivationSpec createActivationSpec(ResourceAdapter adapter, JmsActivationSpecConfig config) { + return new StubActivationSpec(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/remoting/JmsInvokerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/remoting/JmsInvokerTests.java new file mode 100644 index 00000000000..8c307cd603e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/remoting/JmsInvokerTests.java @@ -0,0 +1,414 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.remoting; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Enumeration; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSession; +import javax.jms.Session; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.jms.support.converter.MessageConversionException; +import org.springframework.jms.support.converter.SimpleMessageConverter; + +/** + * @author Juergen Hoeller + */ +public class JmsInvokerTests extends TestCase { + + private MockControl connectionFactoryControl; + private QueueConnectionFactory mockConnectionFactory; + + private MockControl connectionControl; + private QueueConnection mockConnection; + + private MockControl sessionControl; + private QueueSession mockSession; + + private MockControl queueControl; + private Queue mockQueue; + + + protected void setUp() throws Exception { + connectionFactoryControl = MockControl.createControl(QueueConnectionFactory.class); + mockConnectionFactory = (QueueConnectionFactory) connectionFactoryControl.getMock(); + + connectionControl = MockControl.createControl(QueueConnection.class); + mockConnection = (QueueConnection) connectionControl.getMock(); + + sessionControl = MockControl.createControl(QueueSession.class); + mockSession = (QueueSession) sessionControl.getMock(); + + queueControl = MockControl.createControl(Queue.class); + mockQueue = (Queue) queueControl.getMock(); + + mockConnectionFactory.createQueueConnection(); + connectionFactoryControl.setReturnValue(mockConnection, 8); + + mockConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + connectionControl.setReturnValue(mockSession, 8); + + mockConnection.start(); + connectionControl.setVoidCallable(8); + + connectionFactoryControl.replay(); + connectionControl.replay(); + } + + + public void testJmsInvokerProxyFactoryBeanAndServiceExporter() throws Throwable { + sessionControl.replay(); + + doTestJmsInvokerProxyFactoryBeanAndServiceExporter(false); + } + + public void testJmsInvokerProxyFactoryBeanAndServiceExporterWithDynamicQueue() throws Throwable { + mockSession.createQueue("myQueue"); + sessionControl.setReturnValue(mockQueue, 8); + sessionControl.replay(); + + doTestJmsInvokerProxyFactoryBeanAndServiceExporter(true); + } + + private void doTestJmsInvokerProxyFactoryBeanAndServiceExporter(boolean dynamicQueue) throws Throwable { + TestBean target = new TestBean("myname", 99); + + final JmsInvokerServiceExporter exporter = new JmsInvokerServiceExporter(); + exporter.setServiceInterface(ITestBean.class); + exporter.setService(target); + exporter.setMessageConverter(new MockSimpleMessageConverter()); + exporter.afterPropertiesSet(); + + JmsInvokerProxyFactoryBean pfb = new JmsInvokerProxyFactoryBean() { + protected Message doExecuteRequest(Session session, Queue queue, Message requestMessage) throws JMSException { + MockControl exporterSessionControl = MockControl.createControl(Session.class); + Session mockExporterSession = (Session) exporterSessionControl.getMock(); + ResponseStoringProducer mockProducer = new ResponseStoringProducer(); + mockExporterSession.createProducer(requestMessage.getJMSReplyTo()); + exporterSessionControl.setReturnValue(mockProducer); + exporterSessionControl.replay(); + exporter.onMessage(requestMessage, mockExporterSession); + exporterSessionControl.verify(); + assertTrue(mockProducer.closed); + return mockProducer.response; + } + }; + pfb.setServiceInterface(ITestBean.class); + pfb.setConnectionFactory(this.mockConnectionFactory); + if (dynamicQueue) { + pfb.setQueueName("myQueue"); + } + else { + pfb.setQueue(this.mockQueue); + } + pfb.setMessageConverter(new MockSimpleMessageConverter()); + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + + assertEquals("myname", proxy.getName()); + assertEquals(99, proxy.getAge()); + proxy.setAge(50); + assertEquals(50, proxy.getAge()); + proxy.setStringArray(new String[] {"str1", "str2"}); + assertTrue(Arrays.equals(new String[] {"str1", "str2"}, proxy.getStringArray())); + + try { + proxy.exceptional(new IllegalStateException()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + try { + proxy.exceptional(new IllegalAccessException()); + fail("Should have thrown IllegalAccessException"); + } + catch (IllegalAccessException ex) { + // expected + } + + connectionFactoryControl.verify(); + connectionControl.verify(); + sessionControl.verify(); + } + + + private static class ResponseStoringProducer implements MessageProducer { + + public Message response; + + public boolean closed = false; + + public void setDisableMessageID(boolean b) throws JMSException { + } + + public boolean getDisableMessageID() throws JMSException { + return false; + } + + public void setDisableMessageTimestamp(boolean b) throws JMSException { + } + + public boolean getDisableMessageTimestamp() throws JMSException { + return false; + } + + public void setDeliveryMode(int i) throws JMSException { + } + + public int getDeliveryMode() throws JMSException { + return 0; + } + + public void setPriority(int i) throws JMSException { + } + + public int getPriority() throws JMSException { + return 0; + } + + public void setTimeToLive(long l) throws JMSException { + } + + public long getTimeToLive() throws JMSException { + return 0; + } + + public Destination getDestination() throws JMSException { + return null; + } + + public void close() throws JMSException { + this.closed = true; + } + + public void send(Message message) throws JMSException { + this.response = message; + } + + public void send(Message message, int i, int i1, long l) throws JMSException { + } + + public void send(Destination destination, Message message) throws JMSException { + } + + public void send(Destination destination, Message message, int i, int i1, long l) throws JMSException { + } + } + + + private static class MockObjectMessage implements ObjectMessage { + + private Serializable serializable; + + private Destination replyTo; + + public MockObjectMessage(Serializable serializable) { + this.serializable = serializable; + } + + public void setObject(Serializable serializable) throws JMSException { + this.serializable = serializable; + } + + public Serializable getObject() throws JMSException { + return serializable; + } + + public String getJMSMessageID() throws JMSException { + return null; + } + + public void setJMSMessageID(String string) throws JMSException { + } + + public long getJMSTimestamp() throws JMSException { + return 0; + } + + public void setJMSTimestamp(long l) throws JMSException { + } + + public byte[] getJMSCorrelationIDAsBytes() throws JMSException { + return new byte[0]; + } + + public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException { + } + + public void setJMSCorrelationID(String string) throws JMSException { + } + + public String getJMSCorrelationID() throws JMSException { + return null; + } + + public Destination getJMSReplyTo() throws JMSException { + return replyTo; + } + + public void setJMSReplyTo(Destination destination) throws JMSException { + this.replyTo = destination; + } + + public Destination getJMSDestination() throws JMSException { + return null; + } + + public void setJMSDestination(Destination destination) throws JMSException { + } + + public int getJMSDeliveryMode() throws JMSException { + return 0; + } + + public void setJMSDeliveryMode(int i) throws JMSException { + } + + public boolean getJMSRedelivered() throws JMSException { + return false; + } + + public void setJMSRedelivered(boolean b) throws JMSException { + } + + public String getJMSType() throws JMSException { + return null; + } + + public void setJMSType(String string) throws JMSException { + } + + public long getJMSExpiration() throws JMSException { + return 0; + } + + public void setJMSExpiration(long l) throws JMSException { + } + + public int getJMSPriority() throws JMSException { + return 0; + } + + public void setJMSPriority(int i) throws JMSException { + } + + public void clearProperties() throws JMSException { + } + + public boolean propertyExists(String string) throws JMSException { + return false; + } + + public boolean getBooleanProperty(String string) throws JMSException { + return false; + } + + public byte getByteProperty(String string) throws JMSException { + return 0; + } + + public short getShortProperty(String string) throws JMSException { + return 0; + } + + public int getIntProperty(String string) throws JMSException { + return 0; + } + + public long getLongProperty(String string) throws JMSException { + return 0; + } + + public float getFloatProperty(String string) throws JMSException { + return 0; + } + + public double getDoubleProperty(String string) throws JMSException { + return 0; + } + + public String getStringProperty(String string) throws JMSException { + return null; + } + + public Object getObjectProperty(String string) throws JMSException { + return null; + } + + public Enumeration getPropertyNames() throws JMSException { + return null; + } + + public void setBooleanProperty(String string, boolean b) throws JMSException { + } + + public void setByteProperty(String string, byte b) throws JMSException { + } + + public void setShortProperty(String string, short i) throws JMSException { + } + + public void setIntProperty(String string, int i) throws JMSException { + } + + public void setLongProperty(String string, long l) throws JMSException { + } + + public void setFloatProperty(String string, float v) throws JMSException { + } + + public void setDoubleProperty(String string, double v) throws JMSException { + } + + public void setStringProperty(String string, String string1) throws JMSException { + } + + public void setObjectProperty(String string, Object object) throws JMSException { + } + + public void acknowledge() throws JMSException { + } + + public void clearBody() throws JMSException { + } + } + + + private static class MockSimpleMessageConverter extends SimpleMessageConverter { + + public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException { + return new MockObjectMessage((Serializable) object); + } + }; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/support/JmsAccessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/JmsAccessorTests.java new file mode 100644 index 00000000000..49d2a5dca1f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/JmsAccessorTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.support; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +import javax.jms.Session; + +/** + * Unit tests for the {@link JmsAccessor} class. + * + * @author Rick Evans + */ +public final class JmsAccessorTests extends TestCase { + + public void testChokesIfConnectionFactoryIsNotSupplied() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + JmsAccessor accessor = new StubJmsAccessor(); + accessor.afterPropertiesSet(); + } + }.runTest(); + } + + public void testSessionTransactedModeReallyDoesDefaultToFalse() throws Exception { + JmsAccessor accessor = new StubJmsAccessor(); + assertFalse("The [sessionTransacted] property of JmsAccessor must default to " + + "false. Change this test (and the attendant Javadoc) if you have " + + "changed the default.", + accessor.isSessionTransacted()); + } + + public void testAcknowledgeModeReallyDoesDefaultToAutoAcknowledge() throws Exception { + JmsAccessor accessor = new StubJmsAccessor(); + assertEquals("The [sessionAcknowledgeMode] property of JmsAccessor must default to " + + "[Session.AUTO_ACKNOWLEDGE]. Change this test (and the attendant " + + "Javadoc) if you have changed the default.", + Session.AUTO_ACKNOWLEDGE, + accessor.getSessionAcknowledgeMode()); + } + + public void testSetAcknowledgeModeNameChokesIfBadAckModeIsSupplied() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new StubJmsAccessor().setSessionAcknowledgeModeName("Tally ho chaps!"); + } + }.runTest(); + } + + + /** + * Crummy, stub, do-nothing subclass of the JmsAccessor class for use in testing. + */ + private static final class StubJmsAccessor extends JmsAccessor { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverter102Tests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverter102Tests.java new file mode 100644 index 00000000000..6aedec71f5c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverter102Tests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.support; + +import junit.framework.TestCase; +import org.easymock.ArgumentsMatcher; +import org.easymock.MockControl; +import org.springframework.jms.support.converter.SimpleMessageConverter102; + +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; +import java.util.Arrays; + +/** + * Unit tests for the {@link SimpleMessageConverter102} class. + * + * @author Juergen Hoeller + * @author Rick Evans + */ +public final class SimpleMessageConverter102Tests extends TestCase { + + public void testByteArrayConversion102() throws JMSException { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl messageControl = MockControl.createControl(BytesMessage.class); + BytesMessage message = (BytesMessage) messageControl.getMock(); + + byte[] content = new byte[5000]; + + session.createBytesMessage(); + sessionControl.setReturnValue(message, 1); + message.writeBytes(content); + messageControl.setVoidCallable(1); + message.readBytes(new byte[SimpleMessageConverter102.BUFFER_SIZE]); + messageControl.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] arg0, Object[] arg1) { + byte[] one = (byte[]) arg0[0]; + byte[] two = (byte[]) arg1[0]; + return Arrays.equals(one, two); + } + + public String toString(Object[] arg0) { + return "bla"; + } + }); + messageControl.setReturnValue(SimpleMessageConverter102.BUFFER_SIZE, 1); + message.readBytes(new byte[SimpleMessageConverter102.BUFFER_SIZE]); + messageControl.setReturnValue(5000 - SimpleMessageConverter102.BUFFER_SIZE, 1); + sessionControl.replay(); + messageControl.replay(); + + SimpleMessageConverter102 converter = new SimpleMessageConverter102(); + Message msg = converter.toMessage(content, session); + assertEquals(content.length, ((byte[]) converter.fromMessage(msg)).length); + + sessionControl.verify(); + messageControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverterTests.java new file mode 100644 index 00000000000..0c0b6da2ed5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/SimpleMessageConverterTests.java @@ -0,0 +1,259 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.support; + +import junit.framework.TestCase; +import org.easymock.ArgumentsMatcher; +import org.easymock.MockControl; +import org.springframework.jms.support.converter.MessageConversionException; +import org.springframework.jms.support.converter.SimpleMessageConverter; +import org.springframework.test.AssertThrows; + +import javax.jms.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Unit tests for the {@link SimpleMessageConverter} class. + * + * @author Juergen Hoeller + * @author Rick Evans + * @since 18.09.2004 + */ +public final class SimpleMessageConverterTests extends TestCase { + + public void testStringConversion() throws JMSException { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl messageControl = MockControl.createControl(TextMessage.class); + TextMessage message = (TextMessage) messageControl.getMock(); + + String content = "test"; + + session.createTextMessage(content); + sessionControl.setReturnValue(message, 1); + message.getText(); + messageControl.setReturnValue(content, 1); + sessionControl.replay(); + messageControl.replay(); + + SimpleMessageConverter converter = new SimpleMessageConverter(); + Message msg = converter.toMessage(content, session); + assertEquals(content, converter.fromMessage(msg)); + + sessionControl.verify(); + messageControl.verify(); + } + + public void testByteArrayConversion() throws JMSException { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl messageControl = MockControl.createControl(BytesMessage.class); + BytesMessage message = (BytesMessage) messageControl.getMock(); + + byte[] content = "test".getBytes(); + + session.createBytesMessage(); + sessionControl.setReturnValue(message, 1); + message.writeBytes(content); + messageControl.setVoidCallable(1); + message.getBodyLength(); + messageControl.setReturnValue(content.length, 1); + message.readBytes(new byte[content.length]); + messageControl.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] arg0, Object[] arg1) { + byte[] one = (byte[]) arg0[0]; + byte[] two = (byte[]) arg1[0]; + return Arrays.equals(one, two); + } + + public String toString(Object[] arg0) { + return "bla"; + } + }); + messageControl.setReturnValue(content.length, 1); + sessionControl.replay(); + messageControl.replay(); + + SimpleMessageConverter converter = new SimpleMessageConverter(); + Message msg = converter.toMessage(content, session); + assertEquals(content.length, ((byte[]) converter.fromMessage(msg)).length); + + sessionControl.verify(); + messageControl.verify(); + } + + public void testMapConversion() throws JMSException { + + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl messageControl = MockControl.createControl(MapMessage.class); + MapMessage message = (MapMessage) messageControl.getMock(); + + Map content = new HashMap(); + content.put("key1", "value1"); + content.put("key2", "value2"); + + session.createMapMessage(); + sessionControl.setReturnValue(message, 1); + message.setObject("key1", "value1"); + messageControl.setVoidCallable(1); + message.setObject("key2", "value2"); + messageControl.setVoidCallable(1); + message.getMapNames(); + messageControl.setReturnValue(Collections.enumeration(content.keySet())); + message.getObject("key1"); + messageControl.setReturnValue("value1", 1); + message.getObject("key2"); + messageControl.setReturnValue("value2", 1); + + sessionControl.replay(); + messageControl.replay(); + + SimpleMessageConverter converter = new SimpleMessageConverter(); + Message msg = converter.toMessage(content, session); + assertEquals(content, converter.fromMessage(msg)); + + sessionControl.verify(); + messageControl.verify(); + } + + public void testSerializableConversion() throws JMSException { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl messageControl = MockControl.createControl(ObjectMessage.class); + ObjectMessage message = (ObjectMessage) messageControl.getMock(); + + Integer content = new Integer(5); + + session.createObjectMessage(content); + sessionControl.setReturnValue(message, 1); + message.getObject(); + messageControl.setReturnValue(content, 1); + sessionControl.replay(); + messageControl.replay(); + + SimpleMessageConverter converter = new SimpleMessageConverter(); + Message msg = converter.toMessage(content, session); + assertEquals(content, converter.fromMessage(msg)); + + sessionControl.verify(); + messageControl.verify(); + } + + public void testToMessageThrowsExceptionIfGivenNullObjectToConvert() throws Exception { + new AssertThrows(MessageConversionException.class) { + public void test() throws Exception { + new SimpleMessageConverter().toMessage(null, null); + } + }.runTest(); + } + + public void testToMessageThrowsExceptionIfGivenIncompatibleObjectToConvert() throws Exception { + new AssertThrows(MessageConversionException.class) { + public void test() throws Exception { + new SimpleMessageConverter().toMessage(new Object(), null); + } + }.runTest(); + } + + public void testToMessageSimplyReturnsMessageAsIsIfSuppliedWithMessage() throws JMSException { + + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + MockControl messageControl = MockControl.createControl(ObjectMessage.class); + ObjectMessage message = (ObjectMessage) messageControl.getMock(); + + sessionControl.replay(); + messageControl.replay(); + + SimpleMessageConverter converter = new SimpleMessageConverter(); + Message msg = converter.toMessage(message, session); + assertSame(message, msg); + + sessionControl.verify(); + messageControl.verify(); + } + + public void testFromMessageSimplyReturnsMessageAsIsIfSuppliedWithMessage() throws JMSException { + + MockControl messageControl = MockControl.createControl(Message.class); + Message message = (Message) messageControl.getMock(); + + messageControl.replay(); + + SimpleMessageConverter converter = new SimpleMessageConverter(); + Object msg = converter.fromMessage(message); + assertSame(message, msg); + + messageControl.verify(); + } + + public void testMapConversionWhereMapHasNonStringTypesForKeys() throws JMSException { + + MockControl messageControl = MockControl.createControl(MapMessage.class); + MapMessage message = (MapMessage) messageControl.getMock(); + messageControl.replay(); + + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + session.createMapMessage(); + sessionControl.setReturnValue(message); + sessionControl.replay(); + + final Map content = new HashMap(); + content.put(new Integer(1), "value1"); + + final SimpleMessageConverter converter = new SimpleMessageConverter(); + new AssertThrows(MessageConversionException.class) { + public void test() throws Exception { + converter.toMessage(content, session); + } + }.runTest(); + + sessionControl.verify(); + } + + public void testMapConversionWhereMapHasNNullForKey() throws JMSException { + + MockControl messageControl = MockControl.createControl(MapMessage.class); + MapMessage message = (MapMessage) messageControl.getMock(); + messageControl.replay(); + + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + session.createMapMessage(); + sessionControl.setReturnValue(message); + sessionControl.replay(); + + final Map content = new HashMap(); + content.put(null, "value1"); + + final SimpleMessageConverter converter = new SimpleMessageConverter(); + new AssertThrows(MessageConversionException.class) { + public void test() throws Exception { + converter.toMessage(content, session); + } + }.runTest(); + + sessionControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/DynamicDestinationResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/DynamicDestinationResolverTests.java new file mode 100644 index 00000000000..e968d8cf28b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/DynamicDestinationResolverTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.support.destination; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSession; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.jms.StubQueue; +import org.springframework.jms.StubTopic; + +/** + * @author Rick Evans + */ +public class DynamicDestinationResolverTests extends TestCase { + + private static final String DESTINATION_NAME = "foo"; + + + public void testResolveWithPubSubTopicSession() throws Exception { + + Topic expectedDestination = new StubTopic(); + + MockControl mockSession = MockControl.createControl(TopicSession.class); + TopicSession session = (TopicSession) mockSession.getMock(); + session.createTopic(DESTINATION_NAME); + mockSession.setReturnValue(expectedDestination); + mockSession.replay(); + + testResolveDestination(session, expectedDestination, true); + + mockSession.verify(); + } + + public void testResolveWithPubSubVanillaSession() throws Exception { + + Topic expectedDestination = new StubTopic(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + session.createTopic(DESTINATION_NAME); + mockSession.setReturnValue(expectedDestination); + mockSession.replay(); + + testResolveDestination(session, expectedDestination, true); + + mockSession.verify(); + } + + public void testResolveWithPointToPointQueueSession() throws Exception { + + Queue expectedDestination = new StubQueue(); + + MockControl mockSession = MockControl.createControl(QueueSession.class); + Session session = (Session) mockSession.getMock(); + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(expectedDestination); + mockSession.replay(); + + testResolveDestination(session, expectedDestination, false); + + mockSession.verify(); + } + + public void testResolveWithPointToPointVanillaSession() throws Exception { + + Queue expectedDestination = new StubQueue(); + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + session.createQueue(DESTINATION_NAME); + mockSession.setReturnValue(expectedDestination); + mockSession.replay(); + + testResolveDestination(session, expectedDestination, false); + + mockSession.verify(); + } + + private static void testResolveDestination(Session session, Destination expectedDestination, boolean isPubSub) throws JMSException { + DynamicDestinationResolver resolver = new DynamicDestinationResolver(); + Destination destination = resolver.resolveDestinationName(session, DESTINATION_NAME, isPubSub); + assertNotNull(destination); + assertSame(expectedDestination, destination); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JmsDestinationAccessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JmsDestinationAccessorTests.java new file mode 100644 index 00000000000..80a16af6005 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JmsDestinationAccessorTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.support.destination; + +import javax.jms.ConnectionFactory; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + */ +public class JmsDestinationAccessorTests extends TestCase { + + public void testChokesIfDestinationResolverIsetToNullExplcitly() throws Exception { + MockControl mockConnectionFactory = MockControl.createControl(ConnectionFactory.class); + final ConnectionFactory connectionFactory = (ConnectionFactory) mockConnectionFactory.getMock(); + mockConnectionFactory.replay(); + + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + JmsDestinationAccessor accessor = new StubJmsDestinationAccessor(); + accessor.setConnectionFactory(connectionFactory); + accessor.setDestinationResolver(null); + accessor.afterPropertiesSet(); + } + }.runTest(); + + mockConnectionFactory.verify(); + } + + public void testSessionTransactedModeReallyDoesDefaultToFalse() throws Exception { + JmsDestinationAccessor accessor = new StubJmsDestinationAccessor(); + assertFalse("The [pubSubDomain] property of JmsDestinationAccessor must default to " + + "false (i.e. Queues are used by default). Change this test (and the " + + "attendant Javadoc) if you have changed the default.", + accessor.isPubSubDomain()); + } + + + private static class StubJmsDestinationAccessor extends JmsDestinationAccessor { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JndiDestinationResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JndiDestinationResolverTests.java new file mode 100644 index 00000000000..8e1b3ee71fb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jms/support/destination/JndiDestinationResolverTests.java @@ -0,0 +1,156 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.support.destination; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.test.AssertThrows; +import org.springframework.jms.StubTopic; + +import javax.jms.Destination; +import javax.jms.Session; +import javax.naming.NamingException; + +/** + * @author Rick Evans + */ +public class JndiDestinationResolverTests extends TestCase { + + private static final String DESTINATION_NAME = "foo"; + + private static final Destination DESTINATION = new StubTopic(); + + + public void testHitsCacheSecondTimeThrough() throws Exception { + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + mockSession.replay(); + + JndiDestinationResolver resolver = new OneTimeLookupJndiDestinationResolver(); + Destination destination = resolver.resolveDestinationName(session, DESTINATION_NAME, true); + assertNotNull(destination); + assertSame(DESTINATION, destination); + + mockSession.verify(); + } + + public void testDoesNotUseCacheIfCachingIsTurnedOff() throws Exception { + + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + mockSession.replay(); + + CountingCannedJndiDestinationResolver resolver + = new CountingCannedJndiDestinationResolver(); + resolver.setCache(false); + Destination destination = resolver.resolveDestinationName(session, DESTINATION_NAME, true); + assertNotNull(destination); + assertSame(DESTINATION, destination); + assertEquals(1, resolver.getCallCount()); + + destination = resolver.resolveDestinationName(session, DESTINATION_NAME, true); + assertNotNull(destination); + assertSame(DESTINATION, destination); + assertEquals(2, resolver.getCallCount()); + + mockSession.verify(); + } + + public void testDelegatesToFallbackIfNotResolvedInJndi() throws Exception { + MockControl mockSession = MockControl.createControl(Session.class); + Session session = (Session) mockSession.getMock(); + mockSession.replay(); + + MockControl mockDestinationResolver = MockControl.createControl(DestinationResolver.class); + DestinationResolver dynamicResolver = (DestinationResolver) mockDestinationResolver.getMock(); + dynamicResolver.resolveDestinationName(session, DESTINATION_NAME, true); + mockDestinationResolver.setReturnValue(DESTINATION); + mockDestinationResolver.replay(); + + JndiDestinationResolver resolver = new JndiDestinationResolver() { + protected Object lookup(String jndiName, Class requiredClass) throws NamingException { + throw new NamingException(); + } + }; + resolver.setFallbackToDynamicDestination(true); + resolver.setDynamicDestinationResolver(dynamicResolver); + Destination destination = resolver.resolveDestinationName(session, DESTINATION_NAME, true); + + assertNotNull(destination); + assertSame(DESTINATION, destination); + + mockSession.verify(); + mockDestinationResolver.verify(); + } + + public void testDoesNotDelegateToFallbackIfNotResolvedInJndi() throws Exception { + MockControl mockSession = MockControl.createControl(Session.class); + final Session session = (Session) mockSession.getMock(); + mockSession.replay(); + + MockControl mockDestinationResolver = MockControl.createControl(DestinationResolver.class); + DestinationResolver dynamicResolver = (DestinationResolver) mockDestinationResolver.getMock(); + mockDestinationResolver.replay(); + + final JndiDestinationResolver resolver = new JndiDestinationResolver() { + protected Object lookup(String jndiName, Class requiredClass) throws NamingException { + throw new NamingException(); + } + }; + resolver.setDynamicDestinationResolver(dynamicResolver); + + new AssertThrows(DestinationResolutionException.class) { + public void test() throws Exception { + resolver.resolveDestinationName(session, DESTINATION_NAME, true); + } + }.runTest(); + + mockSession.verify(); + mockDestinationResolver.verify(); + } + + + private static class OneTimeLookupJndiDestinationResolver extends JndiDestinationResolver { + + private boolean called; + + protected Object lookup(String jndiName, Class requiredType) throws NamingException { + if (called) { + fail("Must not be delegating to lookup(..), must be resolving from cache."); + } + assertEquals(DESTINATION_NAME, jndiName); + called = true; + return DESTINATION; + } + } + + private static class CountingCannedJndiDestinationResolver extends JndiDestinationResolver { + + private int callCount; + + public int getCallCount() { + return this.callCount; + } + + protected Object lookup(String jndiName, Class requiredType) throws NamingException { + ++this.callCount; + return DESTINATION; + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractJmxTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractJmxTests.java new file mode 100644 index 00000000000..bb94cbe364a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractJmxTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Base JMX test class that pre-loads an ApplicationContext from a user-configurable file. Override the + * {@link #getApplicationContextPath()} method to control the configuration file location. + * + * @author Rob Harrop + * @author Juergen Hoeller + */ +public abstract class AbstractJmxTests extends AbstractMBeanServerTests { + + private ConfigurableApplicationContext ctx; + + + protected final void onSetUp() throws Exception { + ctx = loadContext(getApplicationContextPath()); + } + + protected final void onTearDown() throws Exception { + if (ctx != null) { + ctx.close(); + } + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/applicationContext.xml"; + } + + protected ApplicationContext getContext() { + return this.ctx; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java new file mode 100644 index 00000000000..5ea36a20042 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx; + +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.GenericApplicationContext; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public abstract class AbstractMBeanServerTests extends TestCase { + + protected MBeanServer server; + + public final void setUp() throws Exception { + this.server = MBeanServerFactory.createMBeanServer(); + try { + onSetUp(); + } + catch (Exception ex) { + releaseServer(); + throw ex; + } + } + + protected ConfigurableApplicationContext loadContext(String configLocation) { + GenericApplicationContext ctx = new GenericApplicationContext(); + new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(configLocation); + ctx.getDefaultListableBeanFactory().registerSingleton("server", this.server); + ctx.refresh(); + return ctx; + } + + protected void tearDown() throws Exception { + releaseServer(); + onTearDown(); + } + + private void releaseServer() { + MBeanServerFactory.releaseMBeanServer(getServer()); + } + + protected void onTearDown() throws Exception { + } + + protected void onSetUp() throws Exception { + } + + public MBeanServer getServer() { + return this.server; + } + + protected void assertIsRegistered(String message, ObjectName objectName) { + assertTrue(message, getServer().isRegistered(objectName)); + } + + protected void assertIsNotRegistered(String message, ObjectName objectName) { + assertFalse(message, getServer().isRegistered(objectName)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/IJmxTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/IJmxTestBean.java new file mode 100644 index 00000000000..74d579fb8a7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/IJmxTestBean.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public interface IJmxTestBean { + + public int add(int x, int y); + + public long myOperation(); + + public int getAge(); + + public void setAge(int age); + + public void setName(String name) throws Exception; + + public String getName(); + + // used to test invalid methods that exist in the proxy interface + public void dontExposeMe(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/JmxTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/JmxTestBean.java new file mode 100644 index 00000000000..e73f6106c76 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/JmxTestBean.java @@ -0,0 +1,143 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx; + +import java.io.IOException; + +/** + * @@org.springframework.jmx.export.metadata.ManagedResource + * (description="My Managed Bean", objectName="spring:bean=test", + * log=true, logFile="jmx.log", currencyTimeLimit=15, persistPolicy="OnUpdate", + * persistPeriod=200, persistLocation="./foo", persistName="bar.jmx") + * @@org.springframework.jmx.export.metadata.ManagedNotification + * (name="My Notification", description="A Notification", notificationType="type.foo,type.bar") + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class JmxTestBean implements IJmxTestBean { + + private String name; + + private String nickName; + + private int age; + + private boolean isSuperman; + + + /** + * @@org.springframework.jmx.export.metadata.ManagedAttribute + * (description="The Age Attribute", currencyTimeLimit=15) + */ + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + /** + * @@org.springframework.jmx.export.metadata.ManagedOperation(currencyTimeLimit=30) + */ + public long myOperation() { + return 1L; + } + + /** + * @@org.springframework.jmx.export.metadata.ManagedAttribute + * (description="The Name Attribute", currencyTimeLimit=20, + * defaultValue="bar", persistPolicy="OnUpdate") + */ + public void setName(String name) throws Exception { + if ("Juergen".equals(name)) { + throw new IllegalArgumentException("Juergen"); + } + if ("Juergen Class".equals(name)) { + throw new ClassNotFoundException("Juergen"); + } + if ("Juergen IO".equals(name)) { + throw new IOException("Juergen"); + } + this.name = name; + } + + /** + * @@org.springframework.jmx.export.metadata.ManagedAttribute + * (defaultValue="foo", persistPeriod=300) + */ + public String getName() { + return name; + } + + /** + * @@org.springframework.jmx.export.metadata.ManagedAttribute(description="The Nick + * Name + * Attribute") + */ + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getNickName() { + return this.nickName; + } + + public void setSuperman(boolean superman) { + this.isSuperman = superman; + } + + /** + * @@org.springframework.jmx.export.metadata.ManagedAttribute(description="The Is + * Superman + * Attribute") + */ + public boolean isSuperman() { + return isSuperman; + } + + /** + * @@org.springframework.jmx.export.metadata.ManagedOperation(description="Add Two + * Numbers + * Together") + * @@org.springframework.jmx.export.metadata.ManagedOperationParameter(index=0, name="x", description="Left operand") + * @@org.springframework.jmx.export.metadata.ManagedOperationParameter(index=1, name="y", description="Right operand") + */ + public int add(int x, int y) { + return x + y; + } + + /** + * Test method that is not exposed by the MetadataAssembler. + */ + public void dontExposeMe() { + throw new RuntimeException(); + } + + protected void someProtectedMethod() { + } + + private void somePrivateMethod() { + } + + protected void getSomething() { + } + + private void getSomethingElse() { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/CommonsAttributesMBeanProxyFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/CommonsAttributesMBeanProxyFactoryBeanTests.java new file mode 100644 index 00000000000..db05ccd709f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/CommonsAttributesMBeanProxyFactoryBeanTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.access; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jmx.AbstractJmxTests; +import org.springframework.jmx.IJmxTestBean; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * Tests creation of JMX MBean proxies. + * + * @author Rob Harrop + */ +public class CommonsAttributesMBeanProxyFactoryBeanTests extends AbstractJmxTests { + + private static final String OBJECT_NAME = "bean:name=testBean1"; + + protected ObjectName getObjectName() throws Exception { + return ObjectNameManager.getInstance(OBJECT_NAME); + } + + public void testProxyFactory() throws Exception { + MBeanProxyFactoryBean fb = getProxyFactory(); + fb.setProxyInterface(IJmxTestBean.class); + fb.afterPropertiesSet(); + + IJmxTestBean bean = (IJmxTestBean) fb.getObject(); + assertNotNull("Proxy should not be null", bean); + } + + public void testInvalidJdkProxy() throws Exception { + MBeanProxyFactoryBean fb = getProxyFactory(); + try { + fb.afterPropertiesSet(); + fail("Should not be able to create JDK proxy with no proxy interfaces"); + } + catch (Exception ex) { + // expected + } + } + + public void testWithLocatedMBeanServer() throws Exception { + MBeanProxyFactoryBean fb = new MBeanProxyFactoryBean(); + fb.setProxyInterface(IJmxTestBean.class); + fb.setObjectName(OBJECT_NAME); + fb.afterPropertiesSet(); + IJmxTestBean proxy = (IJmxTestBean)fb.getObject(); + assertNotNull("Proxy should not be null", proxy); + assertEquals("Incorrect name value", "TEST", proxy.getName()); + } + + public void testProxyFactoryBeanWithAutodetect() throws Exception { + try { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("proxyFactoryBean.xml", getClass())); + bf.preInstantiateSingletons(); + } + catch (BeanCreationException ex) { + if (ex.getCause().getClass() == MBeanInfoRetrievalException.class) { + fail("MBeanProxyFactoryBean should be ignored by MBeanExporter when running autodetect process"); + } + else { + throw ex; + } + } + } + + private MBeanProxyFactoryBean getProxyFactory() throws MalformedObjectNameException { + MBeanProxyFactoryBean fb = new MBeanProxyFactoryBean(); + fb.setServer(getServer()); + fb.setObjectName(OBJECT_NAME); + return fb; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java new file mode 100644 index 00000000000..bb8dd6619cb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java @@ -0,0 +1,313 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.access; + +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.BindException; +import java.util.HashMap; +import java.util.Map; + +import javax.management.Descriptor; +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +import org.springframework.jmx.AbstractMBeanServerTests; +import org.springframework.jmx.IJmxTestBean; +import org.springframework.jmx.JmxException; +import org.springframework.jmx.JmxTestBean; +import org.springframework.jmx.export.MBeanExporter; +import org.springframework.jmx.export.assembler.AbstractReflectiveMBeanInfoAssembler; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class MBeanClientInterceptorTests extends AbstractMBeanServerTests { + + protected static final String OBJECT_NAME = "spring:test=proxy"; + + protected JmxTestBean target; + + protected boolean runTests = true; + + public void onSetUp() throws Exception { + target = new JmxTestBean(); + target.setAge(100); + target.setName("Rob Harrop"); + + MBeanExporter adapter = new MBeanExporter(); + Map beans = new HashMap(); + beans.put(OBJECT_NAME, target); + adapter.setServer(getServer()); + adapter.setBeans(beans); + adapter.setAssembler(new ProxyTestAssembler()); + adapter.afterPropertiesSet(); + } + + protected MBeanServerConnection getServerConnection() throws Exception { + return getServer(); + } + + protected IJmxTestBean getProxy() throws Exception { + MBeanProxyFactoryBean factory = new MBeanProxyFactoryBean(); + factory.setServer(getServerConnection()); + factory.setProxyInterface(IJmxTestBean.class); + factory.setObjectName(OBJECT_NAME); + factory.afterPropertiesSet(); + return (IJmxTestBean) factory.getObject(); + } + + public void testProxyClassIsDifferent() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + assertTrue("The proxy class should be different than the base class", + (proxy.getClass() != IJmxTestBean.class)); + } + + public void testDifferentProxiesSameClass() throws Exception { + if (!runTests) return; + IJmxTestBean proxy1 = getProxy(); + IJmxTestBean proxy2 = getProxy(); + + assertNotSame("The proxies should NOT be the same", proxy1, proxy2); + assertSame("The proxy classes should be the same", proxy1.getClass(), proxy2.getClass()); + } + + public void testGetAttributeValue() throws Exception { + if (!runTests) return; + IJmxTestBean proxy1 = getProxy(); + int age = proxy1.getAge(); + assertEquals("The age should be 100", 100, age); + } + + public void testSetAttributeValue() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + proxy.setName("Rob Harrop"); + assertEquals("The name of the bean should have been updated", "Rob Harrop", target.getName()); + } + + public void testSetAttributeValueWithRuntimeException() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + try { + proxy.setName("Juergen"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testSetAttributeValueWithCheckedException() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + try { + proxy.setName("Juergen Class"); + fail("Should have thrown ClassNotFoundException"); + } + catch (ClassNotFoundException ex) { + // expected + } + } + + public void testSetAttributeValueWithIOException() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + try { + proxy.setName("Juergen IO"); + fail("Should have thrown IOException"); + } + catch (IOException ex) { + // expected + } + } + + public void testSetReadOnlyAttribute() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + try { + proxy.setAge(900); + fail("Should not be able to write to a read only attribute"); + } + catch (InvalidInvocationException ex) { + // success + } + } + + public void testInvokeNoArgs() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + long result = proxy.myOperation(); + assertEquals("The operation should return 1", 1, result); + } + + public void testInvokeArgs() throws Exception { + if (!runTests) return; + IJmxTestBean proxy = getProxy(); + int result = proxy.add(1, 2); + assertEquals("The operation should return 3", 3, result); + } + + public void testInvokeUnexposedMethodWithException() throws Exception { + if (!runTests) return; + IJmxTestBean bean = getProxy(); + try { + bean.dontExposeMe(); + fail("Method dontExposeMe should throw an exception"); + } + catch (InvalidInvocationException desired) { + // success + } + } + + public void testLazyConnectionToRemote() throws Exception { + if (!runTests) return; + + JMXServiceURL url = new JMXServiceURL("service:jmx:jmxmp://localhost:9876"); + JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, null, getServer()); + + MBeanProxyFactoryBean factory = new MBeanProxyFactoryBean(); + factory.setServiceUrl(url.toString()); + factory.setProxyInterface(IJmxTestBean.class); + factory.setObjectName(OBJECT_NAME); + factory.setConnectOnStartup(false); + factory.setRefreshOnConnectFailure(true); + // should skip connection to the server + factory.afterPropertiesSet(); + IJmxTestBean bean = (IJmxTestBean) factory.getObject(); + + // now start the connector + try { + connector.start(); + } + catch (BindException ex) { + // couldn't bind to local port 9876 - let's skip the remainder of this test + System.out.println( + "Skipping JMX LazyConnectionToRemote test because binding to local port 9876 failed: " + + ex.getMessage()); + return; + } + + // should now be able to access data via the lazy proxy + try { + assertEquals("Rob Harrop", bean.getName()); + assertEquals(100, bean.getAge()); + } + finally { + connector.stop(); + } + + try { + bean.getName(); + } + catch (JmxException ex) { + // expected + } + + connector = JMXConnectorServerFactory.newJMXConnectorServer(url, null, getServer()); + connector.start(); + + // should now be able to access data via the lazy proxy + try { + assertEquals("Rob Harrop", bean.getName()); + assertEquals(100, bean.getAge()); + } + finally { + connector.stop(); + } + } + + // Commented out because of a side effect with the the started platform MBeanServer. + /* + public void testMXBeanAttributeAccess() throws Exception { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + + MBeanClientInterceptor interceptor = new MBeanClientInterceptor(); + interceptor.setServer(ManagementFactory.getPlatformMBeanServer()); + interceptor.setObjectName("java.lang:type=Memory"); + interceptor.setManagementInterface(MemoryMXBean.class); + MemoryMXBean proxy = (MemoryMXBean) ProxyFactory.getProxy(MemoryMXBean.class, interceptor); + assertTrue(proxy.getHeapMemoryUsage().getMax() > 0); + } + + public void testMXBeanOperationAccess() throws Exception { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + + MBeanClientInterceptor interceptor = new MBeanClientInterceptor(); + interceptor.setServer(ManagementFactory.getPlatformMBeanServer()); + interceptor.setObjectName("java.lang:type=Threading"); + ThreadMXBean proxy = (ThreadMXBean) ProxyFactory.getProxy(ThreadMXBean.class, interceptor); + assertTrue(proxy.getThreadInfo(Thread.currentThread().getId()).getStackTrace() != null); + } + */ + + + private static class ProxyTestAssembler extends AbstractReflectiveMBeanInfoAssembler { + + protected boolean includeReadAttribute(Method method, String beanKey) { + return true; + } + + protected boolean includeWriteAttribute(Method method, String beanKey) { + if ("setAge".equals(method.getName())) { + return false; + } + return true; + } + + protected boolean includeOperation(Method method, String beanKey) { + if ("dontExposeMe".equals(method.getName())) { + return false; + } + return true; + } + + protected String getOperationDescription(Method method) { + return method.getName(); + } + + protected String getAttributeDescription(PropertyDescriptor propertyDescriptor) { + return propertyDescriptor.getDisplayName(); + } + + protected void populateAttributeDescriptor(Descriptor descriptor, Method getter, Method setter) { + + } + + protected void populateOperationDescriptor(Descriptor descriptor, Method method) { + + } + + protected String getDescription(String beanKey, Class beanClass) { + return ""; + } + + protected void populateMBeanDescriptor(Descriptor mbeanDescriptor, String beanKey, Class beanClass) { + + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java new file mode 100644 index 00000000000..86d59b300a4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.access; + +import java.net.BindException; +import java.net.MalformedURLException; + +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * @author Rob Harrop + */ +public class RemoteMBeanClientInterceptorTests extends MBeanClientInterceptorTests { + + private static final String SERVICE_URL = "service:jmx:jmxmp://localhost:9876"; + + private JMXConnectorServer connectorServer; + + private JMXConnector connector; + + public void onSetUp() throws Exception { + super.onSetUp(); + this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(getServiceUrl(), null, getServer()); + try { + this.connectorServer.start(); + } + catch (BindException ex) { + // skipping tests, server already running at this port + runTests = false; + } + } + + private JMXServiceURL getServiceUrl() throws MalformedURLException { + return new JMXServiceURL(SERVICE_URL); + } + + protected MBeanServerConnection getServerConnection() throws Exception { + this.connector = JMXConnectorFactory.connect(getServiceUrl()); + return this.connector.getMBeanServerConnection(); + } + + public void tearDown() throws Exception { + if (this.connector != null) { + this.connector.close(); + } + this.connectorServer.stop(); + super.tearDown(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/proxyFactoryBean.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/proxyFactoryBean.xml new file mode 100644 index 00000000000..d7d5254f1c3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/access/proxyFactoryBean.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.springframework.jmx.IJmxTestBean + + + bean:name=proxyTestBean1 + + + + + + TEST + + + 100 + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/applicationContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/applicationContext.xml new file mode 100644 index 00000000000..d9a4d10cc79 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/applicationContext.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java new file mode 100644 index 00000000000..24211666e19 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.management.ObjectName; + +import org.springframework.jmx.AbstractJmxTests; + +/** + * @author Rob Harrop + */ +public class CustomEditorConfigurerTests extends AbstractJmxTests { + + private final SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd"); + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/customConfigurer.xml"; + } + + public void testDatesInJmx() throws Exception { + System.out.println(getServer().getClass().getName()); + ObjectName oname = new ObjectName("bean:name=dateRange"); + + Date startJmx = (Date) getServer().getAttribute(oname, "StartDate"); + Date endJmx = (Date) getServer().getAttribute(oname, "EndDate"); + + assertEquals("startDate ", getStartDate(), startJmx); + assertEquals("endDate ", getEndDate(), endJmx); + } + + public void testGetDates() throws Exception { + DateRange dr = (DateRange) getContext().getBean("dateRange"); + + assertEquals("startDate ", getStartDate(), dr.getStartDate()); + assertEquals("endDate ", getEndDate(), dr.getEndDate()); + } + + private Date getStartDate() throws ParseException { + Date start = df.parse("2004/10/12"); + return start; + } + + private Date getEndDate() throws ParseException { + Date end = df.parse("2004/11/13"); + return end; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/DateRange.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/DateRange.java new file mode 100644 index 00000000000..8b2feda1481 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/DateRange.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export; + +import java.util.Date; + +/** + * @author Rob Harrop + */ +public class DateRange { + + private Date startDate; + + private Date endDate; + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/ExceptionOnInitBean.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/ExceptionOnInitBean.java new file mode 100644 index 00000000000..4733ef89d9c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/ExceptionOnInitBean.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export; + +/** + * @author Rob Harrop + */ +public class ExceptionOnInitBean { + + private boolean exceptOnInit = false; + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void setExceptOnInit(boolean exceptOnInit) { + this.exceptOnInit = exceptOnInit; + } + + public ExceptionOnInitBean() { + if (exceptOnInit) { + throw new RuntimeException("I am being init'd!"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/LazyInitMBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/LazyInitMBeanTests.java new file mode 100644 index 00000000000..9410c609b01 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/LazyInitMBeanTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class LazyInitMBeanTests extends TestCase { + + public void testLazyInit() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(getApplicationContextPath()); + ctx.close(); + } + + public void testInvokeOnLazyInitBean() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(getApplicationContextPath()); + assertFalse(ctx.getBeanFactory().containsSingleton("testBean")); + assertFalse(ctx.getBeanFactory().containsSingleton("testBean2")); + try { + MBeanServer server = (MBeanServer) ctx.getBean("server"); + ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean2"); + String name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", "foo", name); + } + finally { + ctx.close(); + } + } + + private String getApplicationContextPath() { + return "org/springframework/jmx/export/lazyInit.xml"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java new file mode 100644 index 00000000000..d95c6b4f28b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.ObjectName; +import javax.management.MBeanInfo; +import javax.management.modelmbean.RequiredModelMBean; +import javax.management.modelmbean.ModelMBeanInfo; +import javax.management.modelmbean.ModelMBeanInfoSupport; + +import org.springframework.jmx.AbstractMBeanServerTests; +import org.springframework.jmx.JmxTestBean; +import org.springframework.jmx.export.naming.ObjectNamingStrategy; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class MBeanExporterOperationsTests extends AbstractMBeanServerTests { + + public void testRegisterManagedResourceWithUserSuppliedObjectName() throws Exception { + ObjectName objectName = ObjectNameManager.getInstance("spring:name=Foo"); + + JmxTestBean bean = new JmxTestBean(); + bean.setName("Rob Harrop"); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.registerManagedResource(bean, objectName); + + String name = (String) getServer().getAttribute(objectName, "Name"); + assertEquals("Incorrect name on MBean", name, bean.getName()); + } + + public void testRegisterExistingMBeanWithUserSuppliedObjectName() throws Exception { + ObjectName objectName = ObjectNameManager.getInstance("spring:name=Foo"); + ModelMBeanInfo info = new ModelMBeanInfoSupport("myClass", "myDescription", null, null, null, null); + RequiredModelMBean bean = new RequiredModelMBean(info); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.registerManagedResource(bean, objectName); + + MBeanInfo infoFromServer = getServer().getMBeanInfo(objectName); + assertEquals(info, infoFromServer); + } + + public void testRegisterManagedResourceWithGeneratedObjectName() throws Exception { + final ObjectName objectNameTemplate = ObjectNameManager.getInstance("spring:type=Test"); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.setNamingStrategy(new ObjectNamingStrategy() { + public ObjectName getObjectName(Object managedBean, String beanKey) { + return objectNameTemplate; + } + }); + + JmxTestBean bean1 = new JmxTestBean(); + JmxTestBean bean2 = new JmxTestBean(); + + ObjectName reg1 = exporter.registerManagedResource(bean1); + ObjectName reg2 = exporter.registerManagedResource(bean2); + + assertIsRegistered("Bean 1 not registered with MBeanServer", reg1); + assertIsRegistered("Bean 2 not registered with MBeanServer", reg2); + + assertObjectNameMatchesTemplate(objectNameTemplate, reg1); + assertObjectNameMatchesTemplate(objectNameTemplate, reg2); + } + + public void testRegisterManagedResourceWithGeneratedObjectNameWithoutUniqueness() throws Exception { + final ObjectName objectNameTemplate = ObjectNameManager.getInstance("spring:type=Test"); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.setEnsureUniqueRuntimeObjectNames(false); + exporter.setNamingStrategy(new ObjectNamingStrategy() { + public ObjectName getObjectName(Object managedBean, String beanKey) { + return objectNameTemplate; + } + }); + + JmxTestBean bean1 = new JmxTestBean(); + JmxTestBean bean2 = new JmxTestBean(); + + ObjectName reg1 = exporter.registerManagedResource(bean1); + assertIsRegistered("Bean 1 not registered with MBeanServer", reg1); + + try { + exporter.registerManagedResource(bean2); + fail("Shouldn't be able to register a runtime MBean with a reused ObjectName."); + } + catch (MBeanExportException e) { + assertEquals("Incorrect root cause", InstanceAlreadyExistsException.class, e.getCause().getClass()); + } + } + + private void assertObjectNameMatchesTemplate(ObjectName objectNameTemplate, ObjectName registeredName) { + assertEquals("Domain is incorrect", objectNameTemplate.getDomain(), registeredName.getDomain()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java new file mode 100644 index 00000000000..1005694df80 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java @@ -0,0 +1,760 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.management.Attribute; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBeanInfo; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jmx.AbstractMBeanServerTests; +import org.springframework.jmx.IJmxTestBean; +import org.springframework.jmx.JmxTestBean; +import org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler; +import org.springframework.jmx.export.assembler.MBeanInfoAssembler; +import org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler; +import org.springframework.jmx.export.naming.SelfNaming; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * Integration tests for the MBeanExporter class. + * + * @author Rob Harrop + * @author Juergen Hoeller + * @author Rick Evans + * @author Mark Fisher + */ +public class MBeanExporterTests extends AbstractMBeanServerTests { + + private static final String OBJECT_NAME = "spring:test=jmxMBeanAdaptor"; + + + public void testRegisterNonNotificationListenerType() throws Exception { + Map listeners = new HashMap(); + // put a non-NotificationListener instance in as a value... + listeners.put("*", this); + MBeanExporter exporter = new MBeanExporter(); + try { + exporter.setNotificationListenerMappings(listeners); + fail("Must have thrown an IllegalArgumentException when registering a non-NotificationListener instance as a NotificationListener."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testRegisterNullNotificationListenerType() throws Exception { + Map listeners = new HashMap(); + // put null in as a value... + listeners.put("*", null); + MBeanExporter exporter = new MBeanExporter(); + try { + exporter.setNotificationListenerMappings(listeners); + fail("Must have thrown an IllegalArgumentException when registering a null instance as a NotificationListener."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testRegisterNotificationListenerForNonExistentMBean() throws Exception { + Map listeners = new HashMap(); + NotificationListener dummyListener = new NotificationListener() { + public void handleNotification(Notification notification, Object handback) { + throw new UnsupportedOperationException(); + } + }; + // the MBean with the supplied object name does not exist... + listeners.put("spring:type=Test", dummyListener); + MBeanExporter exporter = new MBeanExporter(); + exporter.setBeans(getBeanMap()); + exporter.setServer(server); + exporter.setNotificationListenerMappings(listeners); + try { + exporter.afterPropertiesSet(); + fail("Must have thrown an MBeanExportException when registering a NotificationListener on a non-existent MBean."); + } + catch (MBeanExportException expected) { + assertTrue(expected.contains(InstanceNotFoundException.class)); + } + } + + public void testWithSuppliedMBeanServer() throws Exception { + MBeanExporter exporter = new MBeanExporter(); + exporter.setBeans(getBeanMap()); + exporter.setServer(server); + exporter.afterPropertiesSet(); + assertIsRegistered("The bean was not registered with the MBeanServer", ObjectNameManager.getInstance(OBJECT_NAME)); + } + + /** Fails if JVM platform MBean server has been started already + public void testWithLocatedMBeanServer() throws Exception { + MBeanExporter adaptor = new MBeanExporter(); + adaptor.setBeans(getBeanMap()); + adaptor.afterPropertiesSet(); + assertIsRegistered("The bean was not registered with the MBeanServer", ObjectNameManager.getInstance(OBJECT_NAME)); + server.unregisterMBean(new ObjectName(OBJECT_NAME)); + } + */ + + public void testUserCreatedMBeanRegWithDynamicMBean() throws Exception { + Map map = new HashMap(); + map.put("spring:name=dynBean", new TestDynamicMBean()); + + InvokeDetectAssembler asm = new InvokeDetectAssembler(); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(map); + exporter.setAssembler(asm); + exporter.afterPropertiesSet(); + + Object name = server.getAttribute(ObjectNameManager.getInstance("spring:name=dynBean"), "Name"); + assertEquals("The name attribute is incorrect", "Rob Harrop", name); + assertFalse("Assembler should not have been invoked", asm.invoked); + } + + public void testAutodetectMBeans() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("autodetectMBeans.xml", getClass())); + try { + bf.getBean("exporter"); + MBeanServer server = (MBeanServer) bf.getBean("server"); + ObjectInstance instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=true")); + assertNotNull(instance); + instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean2=true")); + assertNotNull(instance); + instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean3=true")); + assertNotNull(instance); + } + finally { + bf.destroySingletons(); + } + } + + public void testAutodetectWithExclude() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("autodetectMBeans.xml", getClass())); + try { + bf.getBean("exporter"); + MBeanServer server = (MBeanServer) bf.getBean("server"); + ObjectInstance instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=true")); + assertNotNull(instance); + + try { + server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=false")); + fail("MBean with name spring:mbean=false should have been excluded"); + } + catch (InstanceNotFoundException expected) { + } + } + finally { + bf.destroySingletons(); + } + } + + public void testAutodetectLazyMBeans() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("autodetectLazyMBeans.xml", getClass())); + try { + bf.getBean("exporter"); + MBeanServer server = (MBeanServer) bf.getBean("server"); + + ObjectName oname = ObjectNameManager.getInstance("spring:mbean=true"); + assertNotNull(server.getObjectInstance(oname)); + String name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", "Rob Harrop", name); + + oname = ObjectNameManager.getInstance("spring:mbean=another"); + assertNotNull(server.getObjectInstance(oname)); + name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", "Juergen Hoeller", name); + } + finally { + bf.destroySingletons(); + } + } + + public void testAutodetectNoMBeans() throws Exception { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("autodetectNoMBeans.xml", getClass())); + try { + bf.getBean("exporter"); + } + finally { + bf.destroySingletons(); + } + } + + public void testWithMBeanExporterListeners() throws Exception { + MockMBeanExporterListener listener1 = new MockMBeanExporterListener(); + MockMBeanExporterListener listener2 = new MockMBeanExporterListener(); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setBeans(getBeanMap()); + exporter.setServer(server); + exporter.setListeners(new MBeanExporterListener[] {listener1, listener2}); + exporter.afterPropertiesSet(); + exporter.destroy(); + + assertListener(listener1); + assertListener(listener2); + } + + public void testExportJdkProxy() throws Exception { + JmxTestBean bean = new JmxTestBean(); + bean.setName("Rob Harrop"); + + ProxyFactory factory = new ProxyFactory(); + factory.setTarget(bean); + factory.addAdvice(new NopInterceptor()); + factory.setInterfaces(new Class[]{IJmxTestBean.class}); + + IJmxTestBean proxy = (IJmxTestBean) factory.getProxy(); + String name = "bean:mmm=whatever"; + + Map beans = new HashMap(); + beans.put(name, proxy); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.registerBeans(); + + ObjectName oname = ObjectName.getInstance(name); + Object nameValue = server.getAttribute(oname, "Name"); + assertEquals("Rob Harrop", nameValue); + } + + public void testSelfNaming() throws Exception { + ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME); + SelfNamingTestBean testBean = new SelfNamingTestBean(); + testBean.setObjectName(objectName); + + Map beans = new HashMap(); + beans.put("foo", testBean); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + + exporter.afterPropertiesSet(); + + ObjectInstance instance = server.getObjectInstance(objectName); + assertNotNull(instance); + } + + public void testRegisterIgnoreExisting() throws Exception { + ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME); + + Person preRegistered = new Person(); + preRegistered.setName("Rob Harrop"); + + server.registerMBean(preRegistered, objectName); + + Person springRegistered = new Person(); + springRegistered.setName("Sally Greenwood"); + + String objectName2 = "spring:test=equalBean"; + + Map beans = new HashMap(); + beans.put(objectName.toString(), springRegistered); + beans.put(objectName2, springRegistered); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setRegistrationBehavior(MBeanExporter.REGISTRATION_IGNORE_EXISTING); + + exporter.afterPropertiesSet(); + + ObjectInstance instance = server.getObjectInstance(objectName); + assertNotNull(instance); + ObjectInstance instance2 = server.getObjectInstance(new ObjectName(objectName2)); + assertNotNull(instance2); + + // should still be the first bean with name Rob Harrop + assertEquals("Rob Harrop", server.getAttribute(objectName, "Name")); + } + + public void testRegisterReplaceExisting() throws Exception { + ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME); + + Person preRegistered = new Person(); + preRegistered.setName("Rob Harrop"); + + server.registerMBean(preRegistered, objectName); + + Person springRegistered = new Person(); + springRegistered.setName("Sally Greenwood"); + + Map beans = new HashMap(); + beans.put(objectName.toString(), springRegistered); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setRegistrationBehavior(MBeanExporter.REGISTRATION_REPLACE_EXISTING); + + exporter.afterPropertiesSet(); + + ObjectInstance instance = server.getObjectInstance(objectName); + assertNotNull(instance); + + // should still be the new bean with name Sally Greenwood + assertEquals("Sally Greenwood", server.getAttribute(objectName, "Name")); + } + + public void testWithExposeClassLoader() throws Exception { + String name = "Rob Harrop"; + String otherName = "Juergen Hoeller"; + + JmxTestBean bean = new JmxTestBean(); + bean.setName(name); + ObjectName objectName = ObjectNameManager.getInstance("spring:type=Test"); + + Map beans = new HashMap(); + beans.put(objectName.toString(), bean); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.setBeans(beans); + exporter.setExposeManagedResourceClassLoader(true); + exporter.afterPropertiesSet(); + + assertIsRegistered("Bean instance not registered", objectName); + + Object result = server.invoke(objectName, "add", + new Object[]{new Integer(2), new Integer(3)}, + new String[]{int.class.getName(), int.class.getName()}); + + assertEquals("Incorrect result return from add", result, new Integer(5)); + assertEquals("Incorrect attribute value", name, server.getAttribute(objectName, "Name")); + + server.setAttribute(objectName, new Attribute("Name", otherName)); + assertEquals("Incorrect updated name.", otherName, bean.getName()); + } + + public void testBonaFideMBeanIsNotExportedWhenAutodetectIsTotallyTurnedOff() throws Exception { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("^&_invalidObjectName_(*", builder.getBeanDefinition()); + String exportedBeanName = "export.me.please"; + factory.registerSingleton(exportedBeanName, new TestBean()); + + MBeanExporter exporter = new MBeanExporter(); + Map beansToExport = new HashMap(); + beansToExport.put(OBJECT_NAME, exportedBeanName); + exporter.setBeans(beansToExport); + exporter.setServer(getServer()); + exporter.setBeanFactory(factory); + exporter.setAutodetectMode(MBeanExporter.AUTODETECT_NONE); + // MBean has a bad ObjectName, so if said MBean is autodetected, an exception will be thrown... + exporter.afterPropertiesSet(); + } + + public void testOnlyBonaFideMBeanIsExportedWhenAutodetectIsMBeanOnly() throws Exception { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); + String exportedBeanName = "spring:type=TestBean"; + factory.registerSingleton(exportedBeanName, new TestBean()); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName)); + exporter.setBeanFactory(factory); + exporter.setAutodetectMode(MBeanExporter.AUTODETECT_MBEAN); + exporter.afterPropertiesSet(); + assertIsRegistered("Bona fide MBean not autodetected in AUTODETECT_MBEAN mode", + ObjectNameManager.getInstance(OBJECT_NAME)); + assertIsNotRegistered("Bean autodetected and (only) AUTODETECT_MBEAN mode is on", + ObjectNameManager.getInstance(exportedBeanName)); + } + + public void testBonaFideMBeanAndRegularBeanExporterWithAutodetectAll() throws Exception { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); + String exportedBeanName = "spring:type=TestBean"; + factory.registerSingleton(exportedBeanName, new TestBean()); + String notToBeExportedBeanName = "spring:type=NotToBeExported"; + factory.registerSingleton(notToBeExportedBeanName, new TestBean()); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName)); + exporter.setBeanFactory(factory); + exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL); + exporter.afterPropertiesSet(); + assertIsRegistered("Bona fide MBean not autodetected in (AUTODETECT_ALL) mode", + ObjectNameManager.getInstance(OBJECT_NAME)); + assertIsRegistered("Bean not autodetected in (AUTODETECT_ALL) mode", + ObjectNameManager.getInstance(exportedBeanName)); + assertIsNotRegistered("Bean autodetected and did not satisfy the autodetect info assembler", + ObjectNameManager.getInstance(notToBeExportedBeanName)); + } + + public void testBonaFideMBeanIsNotExportedWithAutodetectAssembler() throws Exception { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); + String exportedBeanName = "spring:type=TestBean"; + factory.registerSingleton(exportedBeanName, new TestBean()); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName)); + exporter.setBeanFactory(factory); + exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER); + exporter.afterPropertiesSet(); + assertIsNotRegistered("Bona fide MBean was autodetected in AUTODETECT_ASSEMBLER mode - must not have been", + ObjectNameManager.getInstance(OBJECT_NAME)); + assertIsRegistered("Bean not autodetected in AUTODETECT_ASSEMBLER mode", + ObjectNameManager.getInstance(exportedBeanName)); + } + + /** + * Want to ensure that said MBean is not exported twice. + */ + public void testBonaFideMBeanExplicitlyExportedAndAutodetectionIsOn() throws Exception { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + Map beansToExport = new HashMap(); + beansToExport.put(OBJECT_NAME, OBJECT_NAME); + exporter.setBeans(beansToExport); + exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(OBJECT_NAME)); + exporter.setBeanFactory(factory); + exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER); + exporter.afterPropertiesSet(); + assertIsRegistered("Explicitly exported bona fide MBean obviously not exported.", + ObjectNameManager.getInstance(OBJECT_NAME)); + } + + public void testSetAutodetectModeToOutOfRangeNegativeValue() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + exporter.setAutodetectMode(-1); + fail("Must have failed when supplying an invalid negative out-of-range autodetect mode"); + } + catch (IllegalArgumentException expected) {} + } + + public void testSetAutodetectModeToOutOfRangePositiveValue() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + exporter.setAutodetectMode(5); + fail("Must have failed when supplying an invalid positive out-of-range autodetect mode"); + } + catch (IllegalArgumentException expected) {} + } + + public void testSetAutodetectModeNameToNull() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + exporter.setAutodetectModeName(null); + fail("Must have failed when supplying a null autodetect mode name"); + } + catch (IllegalArgumentException expected) {} + } + + public void testSetAutodetectModeNameToAnEmptyString() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + exporter.setAutodetectModeName(""); + fail("Must have failed when supplying an empty autodetect mode name"); + } + catch (IllegalArgumentException expected) {} + } + + public void testSetAutodetectModeNameToAWhitespacedString() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + exporter.setAutodetectModeName(" \t"); + fail("Must have failed when supplying a whitespace-only autodetect mode name"); + } + catch (IllegalArgumentException expected) {} + } + + public void testSetAutodetectModeNameToARubbishValue() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + exporter.setAutodetectModeName("That Hansel is... *sssooo* hot right now!"); + fail("Must have failed when supplying a whitespace-only autodetect mode name"); + } + catch (IllegalArgumentException expected) {} + } + + public void testNotRunningInBeanFactoryAndPassedBeanNameToExport() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + Map beans = new HashMap(); + beans.put(OBJECT_NAME, "beanName"); + exporter.setBeans(beans); + exporter.afterPropertiesSet(); + fail("Expecting exception because MBeanExporter is not running in a BeanFactory and was passed bean name to (lookup and then) export"); + } + catch (MBeanExportException expected) {} + } + + public void testNotRunningInBeanFactoryAndAutodetectionIsOn() throws Exception { + try { + MBeanExporter exporter = new MBeanExporter(); + exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL); + exporter.afterPropertiesSet(); + fail("Expecting exception because MBeanExporter is not running in a BeanFactory and was configured to autodetect beans"); + } + catch (MBeanExportException expected) {} + } + + /** + * SPR-2158 + */ + public void testMBeanIsNotUnregisteredSpuriouslyIfSomeExternalProcessHasUnregisteredMBean() throws Exception { + MBeanExporter exporter = new MBeanExporter(); + exporter.setBeans(getBeanMap()); + exporter.setServer(this.server); + MockMBeanExporterListener listener = new MockMBeanExporterListener(); + exporter.setListeners(new MBeanExporterListener[]{listener}); + exporter.afterPropertiesSet(); + assertIsRegistered("The bean was not registered with the MBeanServer", ObjectNameManager.getInstance(OBJECT_NAME)); + + this.server.unregisterMBean(new ObjectName(OBJECT_NAME)); + exporter.destroy(); + assertEquals("Listener should not have been invoked (MBean previously unregistered by external agent)", 0, listener.getUnregistered().size()); + } + + /** + * SPR-3302 + */ + public void testBeanNameCanBeUsedInNotificationListenersMap() throws Exception { + String beanName = "charlesDexterWard"; + BeanDefinitionBuilder testBean = BeanDefinitionBuilder.rootBeanDefinition(JmxTestBean.class); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(beanName, testBean.getBeanDefinition()); + factory.preInstantiateSingletons(); + Object testBeanInstance = factory.getBean(beanName); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + Map beansToExport = new HashMap(); + beansToExport.put("test:what=ever", testBeanInstance); + exporter.setBeans(beansToExport); + exporter.setBeanFactory(factory); + StubNotificationListener listener = new StubNotificationListener(); + exporter.setNotificationListenerMappings(Collections.singletonMap(beanName, listener)); + + exporter.afterPropertiesSet(); + } + + public void testWildcardCanBeUsedInNotificationListenersMap() throws Exception { + String beanName = "charlesDexterWard"; + BeanDefinitionBuilder testBean = BeanDefinitionBuilder.rootBeanDefinition(JmxTestBean.class); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(beanName, testBean.getBeanDefinition()); + factory.preInstantiateSingletons(); + Object testBeanInstance = factory.getBean(beanName); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + Map beansToExport = new HashMap(); + beansToExport.put("test:what=ever", testBeanInstance); + exporter.setBeans(beansToExport); + exporter.setBeanFactory(factory); + StubNotificationListener listener = new StubNotificationListener(); + exporter.setNotificationListenerMappings(Collections.singletonMap("*", listener)); + + exporter.afterPropertiesSet(); + } + + /* + * SPR-3625 + */ + public void testMBeanIsUnregisteredForRuntimeExceptionDuringInitialization() throws Exception { + BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.rootBeanDefinition(Person.class); + BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.rootBeanDefinition(RuntimeExceptionThrowingConstructorBean.class); + + String objectName1 = "spring:test=bean1"; + String objectName2 = "spring:test=bean2"; + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition(objectName1, builder1.getBeanDefinition()); + factory.registerBeanDefinition(objectName2, builder2.getBeanDefinition()); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(getServer()); + Map beansToExport = new HashMap(); + beansToExport.put(objectName1, objectName1); + beansToExport.put(objectName2, objectName2); + exporter.setBeans(beansToExport); + exporter.setBeanFactory(factory); + + try { + exporter.afterPropertiesSet(); + fail("Must have failed during creation of RuntimeExceptionThrowingConstructorBean"); + } + catch (RuntimeException expected) { + } + + assertIsNotRegistered("Must have unregistered all previously registered MBeans due to RuntimeException", + ObjectNameManager.getInstance(objectName1)); + assertIsNotRegistered("Must have never registered this MBean due to RuntimeException", + ObjectNameManager.getInstance(objectName2)); + } + + + private Map getBeanMap() { + Map map = new HashMap(); + map.put(OBJECT_NAME, new JmxTestBean()); + return map; + } + + private void assertListener(MockMBeanExporterListener listener) throws MalformedObjectNameException { + ObjectName desired = ObjectNameManager.getInstance(OBJECT_NAME); + assertEquals("Incorrect number of registrations", 1, listener.getRegistered().size()); + assertEquals("Incorrect number of unregistrations", 1, listener.getUnregistered().size()); + assertEquals("Incorrect ObjectName in register", desired, listener.getRegistered().get(0)); + assertEquals("Incorrect ObjectName in unregister", desired, listener.getUnregistered().get(0)); + } + + + private static class InvokeDetectAssembler implements MBeanInfoAssembler { + + private boolean invoked = false; + + public ModelMBeanInfo getMBeanInfo(Object managedResource, String beanKey) throws JMException { + invoked = true; + return null; + } + } + + + private static class MockMBeanExporterListener implements MBeanExporterListener { + + private List registered = new ArrayList(); + + private List unregistered = new ArrayList(); + + public void mbeanRegistered(ObjectName objectName) { + registered.add(objectName); + } + + public void mbeanUnregistered(ObjectName objectName) { + unregistered.add(objectName); + } + + public List getRegistered() { + return registered; + } + + public List getUnregistered() { + return unregistered; + } + } + + + private static class SelfNamingTestBean implements SelfNaming { + + private ObjectName objectName; + + public void setObjectName(ObjectName objectName) { + this.objectName = objectName; + } + + public ObjectName getObjectName() throws MalformedObjectNameException { + return this.objectName; + } + } + + + public static interface PersonMBean { + + String getName(); + } + + + public static class Person implements PersonMBean { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + + public static final class StubNotificationListener implements NotificationListener { + + private List notifications = new ArrayList(); + + public void handleNotification(Notification notification, Object handback) { + this.notifications.add(notification); + } + + public List getNotifications() { + return this.notifications; + } + } + + + private static class RuntimeExceptionThrowingConstructorBean { + + public RuntimeExceptionThrowingConstructorBean() { + throw new RuntimeException(); + } + } + + + private static final class NamedBeanAutodetectCapableMBeanInfoAssemblerStub + extends SimpleReflectiveMBeanInfoAssembler + implements AutodetectCapableMBeanInfoAssembler { + + private String namedBean; + + public NamedBeanAutodetectCapableMBeanInfoAssemblerStub(String namedBean) { + this.namedBean = namedBean; + } + + public boolean includeBean(Class beanClass, String beanName) { + return this.namedBean.equals(beanName); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java new file mode 100644 index 00000000000..d38ea2ac74b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java @@ -0,0 +1,482 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export; + +import java.util.HashMap; +import java.util.Map; + +import javax.management.Attribute; +import javax.management.AttributeChangeNotification; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.jmx.AbstractMBeanServerTests; +import org.springframework.jmx.JmxTestBean; +import org.springframework.jmx.access.NotificationListenerRegistrar; +import org.springframework.jmx.export.naming.SelfNaming; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * @author Rob Harrop + * @author Mark Fisher + */ +public class NotificationListenerTests extends AbstractMBeanServerTests { + + public void testRegisterNotificationListenerForMBean() throws Exception { + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + JmxTestBean bean = new JmxTestBean(); + + Map beans = new HashMap(); + beans.put(objectName, bean); + + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + + Map notificationListeners = new HashMap(); + notificationListeners.put(objectName, listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListenerMappings(notificationListeners); + exporter.afterPropertiesSet(); + + // update the attribute + String attributeName = "Name"; + server.setAttribute(objectName, new Attribute(attributeName, "Rob Harrop")); + assertEquals("Listener not notified", 1, listener.getCount(attributeName)); + } + + public void testRegisterNotificationListenerWithWildcard() throws Exception { + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + JmxTestBean bean = new JmxTestBean(); + + Map beans = new HashMap(); + beans.put(objectName, bean); + + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + + Map notificationListeners = new HashMap(); + notificationListeners.put("*", listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListenerMappings(notificationListeners); + exporter.afterPropertiesSet(); + + // update the attribute + String attributeName = "Name"; + server.setAttribute(objectName, new Attribute(attributeName, "Rob Harrop")); + assertEquals("Listener not notified", 1, listener.getCount(attributeName)); + } + + public void testRegisterNotificationListenerWithHandback() throws Exception { + String objectName = "spring:name=Test"; + JmxTestBean bean = new JmxTestBean(); + + Map beans = new HashMap(); + beans.put(objectName, bean); + + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + Object handback = new Object(); + + NotificationListenerBean listenerBean = new NotificationListenerBean(); + listenerBean.setNotificationListener(listener); + listenerBean.setMappedObjectName("spring:name=Test"); + listenerBean.setHandback(handback); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListeners(new NotificationListenerBean[]{listenerBean}); + exporter.afterPropertiesSet(); + + // update the attribute + String attributeName = "Name"; + server.setAttribute(ObjectNameManager.getInstance("spring:name=Test"), new Attribute(attributeName, "Rob Harrop")); + + assertEquals("Listener not notified", 1, listener.getCount(attributeName)); + assertEquals("Handback object not transmitted correctly", handback, listener.getLastHandback(attributeName)); + } + + public void testRegisterNotificationListenerForAllMBeans() throws Exception { + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + JmxTestBean bean = new JmxTestBean(); + + Map beans = new HashMap(); + beans.put(objectName, bean); + + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + + NotificationListenerBean listenerBean = new NotificationListenerBean(); + listenerBean.setNotificationListener(listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListeners(new NotificationListenerBean[]{listenerBean}); + exporter.afterPropertiesSet(); + + // update the attribute + String attributeName = "Name"; + server.setAttribute(objectName, new Attribute(attributeName, "Rob Harrop")); + + assertEquals("Listener not notified", 1, listener.getCount(attributeName)); + } + + public void testRegisterNotificationListenerWithFilter() throws Exception { + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + JmxTestBean bean = new JmxTestBean(); + + Map beans = new HashMap(); + beans.put(objectName, bean); + + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + + NotificationListenerBean listenerBean = new NotificationListenerBean(); + listenerBean.setNotificationListener(listener); + listenerBean.setNotificationFilter(new NotificationFilter() { + public boolean isNotificationEnabled(Notification notification) { + if (notification instanceof AttributeChangeNotification) { + AttributeChangeNotification changeNotification = (AttributeChangeNotification) notification; + return "Name".equals(changeNotification.getAttributeName()); + } + else { + return false; + } + } + }); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListeners(new NotificationListenerBean[]{listenerBean}); + exporter.afterPropertiesSet(); + + // update the attributes + String nameAttribute = "Name"; + String ageAttribute = "Age"; + + server.setAttribute(objectName, new Attribute(nameAttribute, "Rob Harrop")); + server.setAttribute(objectName, new Attribute(ageAttribute, new Integer(90))); + + assertEquals("Listener not notified for Name", 1, listener.getCount(nameAttribute)); + assertEquals("Listener incorrectly notified for Age", 0, listener.getCount(ageAttribute)); + } + + public void testCreationWithNoNotificationListenerSet() { + try { + new NotificationListenerBean().afterPropertiesSet(); + fail("Must have thrown an IllegalArgumentException (no NotificationListener supplied)"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testRegisterNotificationListenerWithBeanNameAndBeanNameInBeansMap() throws Exception { + String beanName = "testBean"; + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + + SelfNamingTestBean testBean = new SelfNamingTestBean(); + testBean.setObjectName(objectName); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerSingleton(beanName, testBean); + + Map beans = new HashMap(); + beans.put(beanName, beanName); + + Map listenerMappings = new HashMap(); + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + listenerMappings.put(beanName, listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListenerMappings(listenerMappings); + exporter.setBeanFactory(factory); + exporter.afterPropertiesSet(); + assertIsRegistered("Should have registered MBean", objectName); + + server.setAttribute(objectName, new Attribute("Age", new Integer(77))); + assertEquals("Listener not notified", 1, listener.getCount("Age")); + } + + public void testRegisterNotificationListenerWithBeanNameAndBeanInstanceInBeansMap() throws Exception { + String beanName = "testBean"; + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + + SelfNamingTestBean testBean = new SelfNamingTestBean(); + testBean.setObjectName(objectName); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerSingleton(beanName, testBean); + + Map beans = new HashMap(); + beans.put(beanName, testBean); + + Map listenerMappings = new HashMap(); + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + listenerMappings.put(beanName, listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListenerMappings(listenerMappings); + exporter.setBeanFactory(factory); + exporter.afterPropertiesSet(); + assertIsRegistered("Should have registered MBean", objectName); + + server.setAttribute(objectName, new Attribute("Age", new Integer(77))); + assertEquals("Listener not notified", 1, listener.getCount("Age")); + } + + public void testRegisterNotificationListenerWithBeanNameBeforeObjectNameMappedToSameBeanInstance() throws Exception { + String beanName = "testBean"; + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + + SelfNamingTestBean testBean = new SelfNamingTestBean(); + testBean.setObjectName(objectName); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerSingleton(beanName, testBean); + + Map beans = new HashMap(); + beans.put(beanName, testBean); + + Map listenerMappings = new HashMap(); + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + listenerMappings.put(beanName, listener); + listenerMappings.put(objectName, listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListenerMappings(listenerMappings); + exporter.setBeanFactory(factory); + exporter.afterPropertiesSet(); + assertIsRegistered("Should have registered MBean", objectName); + + server.setAttribute(objectName, new Attribute("Age", new Integer(77))); + assertEquals("Listener should have been notified exactly once", 1, listener.getCount("Age")); + } + + public void testRegisterNotificationListenerWithObjectNameBeforeBeanNameMappedToSameBeanInstance() throws Exception { + String beanName = "testBean"; + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + + SelfNamingTestBean testBean = new SelfNamingTestBean(); + testBean.setObjectName(objectName); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerSingleton(beanName, testBean); + + Map beans = new HashMap(); + beans.put(beanName, testBean); + + Map listenerMappings = new HashMap(); + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + listenerMappings.put(objectName, listener); + listenerMappings.put(beanName, listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListenerMappings(listenerMappings); + exporter.setBeanFactory(factory); + exporter.afterPropertiesSet(); + assertIsRegistered("Should have registered MBean", objectName); + + server.setAttribute(objectName, new Attribute("Age", new Integer(77))); + assertEquals("Listener should have been notified exactly once", 1, listener.getCount("Age")); + } + + public void testRegisterNotificationListenerWithTwoBeanNamesMappedToDifferentBeanInstances() throws Exception { + String beanName1 = "testBean1"; + String beanName2 = "testBean2"; + + ObjectName objectName1 = ObjectName.getInstance("spring:name=Test1"); + ObjectName objectName2 = ObjectName.getInstance("spring:name=Test2"); + + SelfNamingTestBean testBean1 = new SelfNamingTestBean(); + testBean1.setObjectName(objectName1); + + SelfNamingTestBean testBean2 = new SelfNamingTestBean(); + testBean2.setObjectName(objectName2); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerSingleton(beanName1, testBean1); + factory.registerSingleton(beanName2, testBean2); + + Map beans = new HashMap(); + beans.put(beanName1, testBean1); + beans.put(beanName2, testBean2); + + Map listenerMappings = new HashMap(); + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + listenerMappings.put(beanName1, listener); + listenerMappings.put(beanName2, listener); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.setNotificationListenerMappings(listenerMappings); + exporter.setBeanFactory(factory); + exporter.afterPropertiesSet(); + assertIsRegistered("Should have registered MBean", objectName1); + assertIsRegistered("Should have registered MBean", objectName2); + + server.setAttribute(ObjectNameManager.getInstance(objectName1), new Attribute("Age", new Integer(77))); + assertEquals("Listener not notified for testBean1", 1, listener.getCount("Age")); + + server.setAttribute(ObjectNameManager.getInstance(objectName2), new Attribute("Age", new Integer(33))); + assertEquals("Listener not notified for testBean2", 2, listener.getCount("Age")); + } + + public void testNotificationListenerRegistrar() throws Exception { + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + JmxTestBean bean = new JmxTestBean(); + + Map beans = new HashMap(); + beans.put(objectName, bean); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.afterPropertiesSet(); + + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + + NotificationListenerRegistrar registrar = new NotificationListenerRegistrar(); + registrar.setServer(server); + registrar.setNotificationListener(listener); + registrar.setMappedObjectName(objectName); + registrar.afterPropertiesSet(); + + // update the attribute + String attributeName = "Name"; + server.setAttribute(objectName, new Attribute(attributeName, "Rob Harrop")); + assertEquals("Listener not notified", 1, listener.getCount(attributeName)); + + registrar.destroy(); + + // try to update the attribute again + server.setAttribute(objectName, new Attribute(attributeName, "Rob Harrop")); + assertEquals("Listener notified after destruction", 1, listener.getCount(attributeName)); + } + + public void testNotificationListenerRegistrarWithMultipleNames() throws Exception { + ObjectName objectName = ObjectName.getInstance("spring:name=Test"); + ObjectName objectName2 = ObjectName.getInstance("spring:name=Test2"); + JmxTestBean bean = new JmxTestBean(); + JmxTestBean bean2 = new JmxTestBean(); + + Map beans = new HashMap(); + beans.put(objectName, bean); + beans.put(objectName2, bean2); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setServer(server); + exporter.setBeans(beans); + exporter.afterPropertiesSet(); + + CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener(); + + NotificationListenerRegistrar registrar = new NotificationListenerRegistrar(); + registrar.setServer(server); + registrar.setNotificationListener(listener); + //registrar.setMappedObjectNames(new Object[] {objectName, objectName2}); + registrar.setMappedObjectNames(new String[] {"spring:name=Test", "spring:name=Test2"}); + registrar.afterPropertiesSet(); + + // update the attribute + String attributeName = "Name"; + server.setAttribute(objectName, new Attribute(attributeName, "Rob Harrop")); + assertEquals("Listener not notified", 1, listener.getCount(attributeName)); + + registrar.destroy(); + + // try to update the attribute again + server.setAttribute(objectName, new Attribute(attributeName, "Rob Harrop")); + assertEquals("Listener notified after destruction", 1, listener.getCount(attributeName)); + } + + + private static class CountingAttributeChangeNotificationListener implements NotificationListener { + + private Map attributeCounts = new HashMap(); + + private Map attributeHandbacks = new HashMap(); + + public void handleNotification(Notification notification, Object handback) { + if (notification instanceof AttributeChangeNotification) { + AttributeChangeNotification attNotification = (AttributeChangeNotification) notification; + String attributeName = attNotification.getAttributeName(); + + Integer currentCount = (Integer) this.attributeCounts.get(attributeName); + + if (currentCount != null) { + int count = currentCount.intValue() + 1; + this.attributeCounts.put(attributeName, new Integer(count)); + } + else { + this.attributeCounts.put(attributeName, new Integer(1)); + } + + this.attributeHandbacks.put(attributeName, handback); + } + } + + public int getCount(String attribute) { + Integer count = (Integer) this.attributeCounts.get(attribute); + return (count == null) ? 0 : count.intValue(); + } + + public Object getLastHandback(String attributeName) { + return this.attributeHandbacks.get(attributeName); + } + } + + + public static class SelfNamingTestBean implements SelfNaming { + + private ObjectName objectName; + + private int age; + + public void setObjectName(ObjectName objectName) { + this.objectName = objectName; + } + + public ObjectName getObjectName() throws MalformedObjectNameException { + return this.objectName; + } + + public void setAge(int age) { + this.age = age; + } + + public int getAge() { + return this.age; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java new file mode 100644 index 00000000000..5df30638c20 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java @@ -0,0 +1,206 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ReflectionException; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.jmx.AbstractMBeanServerTests; +import org.springframework.jmx.export.notification.NotificationPublisher; +import org.springframework.jmx.export.notification.NotificationPublisherAware; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * Integration tests for the Spring JMX {@link NotificationPublisher} functionality. + * + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class NotificationPublisherTests extends AbstractMBeanServerTests { + + private CountingNotificationListener listener = new CountingNotificationListener(); + + + public void testSimpleBean() throws Exception { + // start the MBeanExporter + ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherTests.xml"); + this.server.addNotificationListener(ObjectNameManager.getInstance("spring:type=Publisher"), listener, null, null); + + MyNotificationPublisher publisher = (MyNotificationPublisher) ctx.getBean("publisher"); + assertNotNull("NotificationPublisher should not be null", publisher.getNotificationPublisher()); + publisher.sendNotification(); + assertEquals("Notification not sent", 1, listener.count); + } + + public void testSimpleBeanRegisteredManually() throws Exception { + // start the MBeanExporter + ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherTests.xml"); + MBeanExporter exporter = (MBeanExporter) ctx.getBean("exporter"); + MyNotificationPublisher publisher = new MyNotificationPublisher(); + exporter.registerManagedResource(publisher, ObjectNameManager.getInstance("spring:type=Publisher2")); + this.server.addNotificationListener(ObjectNameManager.getInstance("spring:type=Publisher2"), listener, null, null); + + assertNotNull("NotificationPublisher should not be null", publisher.getNotificationPublisher()); + publisher.sendNotification(); + assertEquals("Notification not sent", 1, listener.count); + } + + public void testMBean() throws Exception { + // start the MBeanExporter + ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherTests.xml"); + this.server.addNotificationListener(ObjectNameManager.getInstance("spring:type=PublisherMBean"), listener, null, null); + + MyNotificationPublisherMBean publisher = (MyNotificationPublisherMBean) ctx.getBean("publisherMBean"); + publisher.sendNotification(); + assertEquals("Notification not sent", 1, listener.count); + } + + /* + public void testStandardMBean() throws Exception { + // start the MBeanExporter + ApplicationContext ctx = new ClassPathXmlApplicationContext("org/springframework/jmx/export/notificationPublisherTests.xml"); + this.server.addNotificationListener(ObjectNameManager.getInstance("spring:type=PublisherStandardMBean"), listener, null, null); + + MyNotificationPublisherStandardMBean publisher = (MyNotificationPublisherStandardMBean) ctx.getBean("publisherStandardMBean"); + publisher.sendNotification(); + assertEquals("Notification not sent", 1, listener.count); + } + */ + + public void testLazyInit() throws Exception { + // start the MBeanExporter + ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherLazyTests.xml"); + assertFalse("Should not have instantiated the bean yet", ctx.getBeanFactory().containsSingleton("publisher")); + + // need to touch the MBean proxy + server.getAttribute(ObjectNameManager.getInstance("spring:type=Publisher"), "Name"); + this.server.addNotificationListener(ObjectNameManager.getInstance("spring:type=Publisher"), listener, null, null); + + MyNotificationPublisher publisher = (MyNotificationPublisher) ctx.getBean("publisher"); + assertNotNull("NotificationPublisher should not be null", publisher.getNotificationPublisher()); + publisher.sendNotification(); + assertEquals("Notification not sent", 1, listener.count); + } + + + private static class CountingNotificationListener implements NotificationListener { + + private int count; + + private Notification lastNotification; + + public void handleNotification(Notification notification, Object handback) { + this.lastNotification = notification; + this.count++; + } + + public int getCount() { + return count; + } + + public Notification getLastNotification() { + return lastNotification; + } + } + + + public static class MyNotificationPublisher implements NotificationPublisherAware { + + private NotificationPublisher notificationPublisher; + + public void setNotificationPublisher(NotificationPublisher notificationPublisher) { + this.notificationPublisher = notificationPublisher; + } + + public NotificationPublisher getNotificationPublisher() { + return notificationPublisher; + } + + public void sendNotification() { + this.notificationPublisher.sendNotification(new Notification("test", this, 1)); + } + + public String getName() { + return "Rob Harrop"; + } + } + + + public static class MyNotificationPublisherMBean extends NotificationBroadcasterSupport implements DynamicMBean { + + public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { + return null; + } + + public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { + } + + public AttributeList getAttributes(String[] attributes) { + return null; + } + + public AttributeList setAttributes(AttributeList attributes) { + return null; + } + + public Object invoke(String actionName, Object params[], String signature[]) throws MBeanException, ReflectionException { + return null; + } + + public MBeanInfo getMBeanInfo() { + return new MBeanInfo( + MyNotificationPublisherMBean.class.getName(), "", + new MBeanAttributeInfo[0], + new MBeanConstructorInfo[0], + new MBeanOperationInfo[0], + new MBeanNotificationInfo[0]); + } + + public void sendNotification() { + sendNotification(new Notification("test", this, 1)); + } + } + + + public static class MyNotificationPublisherStandardMBean extends NotificationBroadcasterSupport implements MyMBean { + + public void sendNotification() { + sendNotification(new Notification("test", this, 1)); + } + } + + + public interface MyMBean { + + void sendNotification(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java new file mode 100644 index 00000000000..3f5e82ab58e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export; + +import javax.management.ObjectName; + +import org.springframework.jmx.AbstractJmxTests; +import org.springframework.jmx.IJmxTestBean; + +/** + * @author Rob Harrop + */ +public class PropertyPlaceholderConfigurerTests extends AbstractJmxTests { + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/propertyPlaceholderConfigurer.xml"; + } + + public void testPropertiesReplaced() { + IJmxTestBean bean = (IJmxTestBean) getContext().getBean("testBean"); + + assertEquals("Name is incorrect", "Rob Harrop", bean.getName()); + assertEquals("Age is incorrect", 100, bean.getAge()); + } + + public void testPropertiesCorrectInJmx() throws Exception { + ObjectName oname = new ObjectName("bean:name=proxyTestBean1"); + Object name = getServer().getAttribute(oname, "Name"); + Integer age = (Integer) getServer().getAttribute(oname, "Age"); + + assertEquals("Name is incorrect in JMX", "Rob Harrop", name); + assertEquals("Age is incorrect in JMX", 100, age.intValue()); + } + +} + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/TestDynamicMBean.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/TestDynamicMBean.java new file mode 100644 index 00000000000..a52d6a7e78c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/TestDynamicMBean.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.DynamicMBean; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class TestDynamicMBean implements DynamicMBean { + + public void setFailOnInit(boolean failOnInit) { + if (failOnInit) { + throw new IllegalArgumentException("Failing on initialization"); + } + } + + public Object getAttribute(String attribute) { + if ("Name".equals(attribute)) { + return "Rob Harrop"; + } + return null; + } + + public void setAttribute(Attribute attribute) { + } + + public AttributeList getAttributes(String[] attributes) { + return null; + } + + public AttributeList setAttributes(AttributeList attributes) { + return null; + } + + public Object invoke(String actionName, Object[] params, String[] signature) { + return null; + } + + public MBeanInfo getMBeanInfo() { + MBeanAttributeInfo attr = new MBeanAttributeInfo("name", "java.lang.String", "", true, false, false); + return new MBeanInfo( + TestDynamicMBean.class.getName(), "", + new MBeanAttributeInfo[]{attr}, + new MBeanConstructorInfo[0], + new MBeanOperationInfo[0], + new MBeanNotificationInfo[0]); + } + + public boolean equals(Object obj) { + return (obj instanceof TestDynamicMBean); + } + + public int hashCode() { + return TestDynamicMBean.class.hashCode(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractAutodetectTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractAutodetectTests.java new file mode 100644 index 00000000000..c2da24872bb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractAutodetectTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +import junit.framework.TestCase; + +import org.springframework.jmx.JmxTestBean; + +/** + * @author Rob Harrop + */ +public abstract class AbstractAutodetectTests extends TestCase { + + public void testAutodetect() throws Exception { + JmxTestBean bean = new JmxTestBean(); + + AutodetectCapableMBeanInfoAssembler assembler = getAssembler(); + assertTrue("The bean should be included", assembler.includeBean(bean.getClass(), "testBean")); + } + + protected abstract AutodetectCapableMBeanInfoAssembler getAssembler(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java new file mode 100644 index 00000000000..9a3ba369028 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java @@ -0,0 +1,198 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +import javax.management.Attribute; +import javax.management.Descriptor; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; +import javax.management.modelmbean.ModelMBeanOperationInfo; + +import org.springframework.jmx.AbstractJmxTests; +import org.springframework.jmx.IJmxTestBean; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * @author Rob Harrop + */ +public abstract class AbstractJmxAssemblerTests extends AbstractJmxTests { + + protected static final String AGE_ATTRIBUTE = "Age"; + + protected static final String NAME_ATTRIBUTE = "Name"; + + protected abstract String getObjectName(); + + public void testMBeanRegistration() throws Exception { + // beans are registered at this point - just grab them from the server + ObjectInstance instance = getObjectInstance(); + assertNotNull("Bean should not be null", instance); + } + + public void testRegisterOperations() throws Exception { + IJmxTestBean bean = getBean(); + MBeanInfo inf = getMBeanInfo(); + assertEquals("Incorrect number of operations registered", + getExpectedOperationCount(), inf.getOperations().length); + } + + public void testRegisterAttributes() throws Exception { + IJmxTestBean bean = getBean(); + MBeanInfo inf = getMBeanInfo(); + assertEquals("Incorrect number of attributes registered", + getExpectedAttributeCount(), inf.getAttributes().length); + } + + public void testGetMBeanInfo() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + assertNotNull("MBeanInfo should not be null", info); + } + + public void testGetMBeanAttributeInfo() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + MBeanAttributeInfo[] inf = info.getAttributes(); + assertEquals("Invalid number of Attributes returned", + getExpectedAttributeCount(), inf.length); + + for (int x = 0; x < inf.length; x++) { + assertNotNull("MBeanAttributeInfo should not be null", inf[x]); + assertNotNull( + "Description for MBeanAttributeInfo should not be null", + inf[x].getDescription()); + } + } + + public void testGetMBeanOperationInfo() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + MBeanOperationInfo[] inf = info.getOperations(); + assertEquals("Invalid number of Operations returned", + getExpectedOperationCount(), inf.length); + + for (int x = 0; x < inf.length; x++) { + assertNotNull("MBeanOperationInfo should not be null", inf[x]); + assertNotNull( + "Description for MBeanOperationInfo should not be null", + inf[x].getDescription()); + } + } + + public void testDescriptionNotNull() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + + assertNotNull("The MBean description should not be null", + info.getDescription()); + } + + public void testSetAttribute() throws Exception { + ObjectName objectName = ObjectNameManager.getInstance(getObjectName()); + getServer().setAttribute(objectName, new Attribute(NAME_ATTRIBUTE, "Rob Harrop")); + IJmxTestBean bean = (IJmxTestBean) getContext().getBean("testBean"); + assertEquals("Rob Harrop", bean.getName()); + } + + public void testGetAttribute() throws Exception { + ObjectName objectName = ObjectNameManager.getInstance(getObjectName()); + getBean().setName("John Smith"); + Object val = getServer().getAttribute(objectName, NAME_ATTRIBUTE); + assertEquals("Incorrect result", "John Smith", val); + } + + public void testOperationInvocation() throws Exception{ + ObjectName objectName = ObjectNameManager.getInstance(getObjectName()); + Object result = getServer().invoke(objectName, "add", + new Object[] {new Integer(20), new Integer(30)}, new String[] {"int", "int"}); + assertEquals("Incorrect result", new Integer(50), result); + } + + public void testAttributeInfoHasDescriptors() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + + ModelMBeanAttributeInfo attr = info.getAttribute(NAME_ATTRIBUTE); + Descriptor desc = attr.getDescriptor(); + assertNotNull("getMethod field should not be null", + desc.getFieldValue("getMethod")); + assertNotNull("setMethod field should not be null", + desc.getFieldValue("setMethod")); + assertEquals("getMethod field has incorrect value", "getName", + desc.getFieldValue("getMethod")); + assertEquals("setMethod field has incorrect value", "setName", + desc.getFieldValue("setMethod")); + } + + public void testAttributeHasCorrespondingOperations() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + + ModelMBeanOperationInfo get = info.getOperation("getName"); + assertNotNull("get operation should not be null", get); + assertEquals("get operation should have visibility of four", + (Integer) get.getDescriptor().getFieldValue("visibility"), + new Integer(4)); + assertEquals("get operation should have role \"getter\"", "getter", get.getDescriptor().getFieldValue("role")); + + ModelMBeanOperationInfo set = info.getOperation("setName"); + assertNotNull("set operation should not be null", set); + assertEquals("set operation should have visibility of four", + (Integer) set.getDescriptor().getFieldValue("visibility"), + new Integer(4)); + assertEquals("set operation should have role \"setter\"", "setter", set.getDescriptor().getFieldValue("role")); + } + + public void testNotificationMetadata() throws Exception { + ModelMBeanInfo info = (ModelMBeanInfo) getMBeanInfo(); + MBeanNotificationInfo[] notifications = info.getNotifications(); + assertEquals("Incorrect number of notifications", 1, notifications.length); + assertEquals("Incorrect notification name", "My Notification", notifications[0].getName()); + + String[] notifTypes = notifications[0].getNotifTypes(); + + assertEquals("Incorrect number of notification types", 2, notifTypes.length); + assertEquals("Notification type.foo not found", "type.foo", notifTypes[0]); + assertEquals("Notification type.bar not found", "type.bar", notifTypes[1]); + } + + protected ModelMBeanInfo getMBeanInfoFromAssembler() throws Exception { + IJmxTestBean bean = getBean(); + ModelMBeanInfo info = getAssembler().getMBeanInfo(bean, getObjectName()); + return info; + } + + protected IJmxTestBean getBean() { + Object bean = getContext().getBean("testBean"); + return (IJmxTestBean) bean; + } + + protected MBeanInfo getMBeanInfo() throws Exception { + return getServer().getMBeanInfo(ObjectNameManager.getInstance(getObjectName())); + } + + protected ObjectInstance getObjectInstance() throws Exception { + return getServer().getObjectInstance(ObjectNameManager.getInstance(getObjectName())); + } + + protected abstract int getExpectedOperationCount(); + + protected abstract int getExpectedAttributeCount(); + + protected abstract MBeanInfoAssembler getAssembler() throws Exception; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerAutodetectTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerAutodetectTests.java new file mode 100644 index 00000000000..2a5bfc77a9e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerAutodetectTests.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +import org.springframework.jmx.export.metadata.JmxAttributeSource; + +/** + * @author Rob Harrop + */ +public abstract class AbstractMetadataAssemblerAutodetectTests extends AbstractAutodetectTests { + + protected AutodetectCapableMBeanInfoAssembler getAssembler() { + MetadataMBeanInfoAssembler assembler = new MetadataMBeanInfoAssembler(); + assembler.setAttributeSource(getAttributeSource()); + return assembler; + } + + protected abstract JmxAttributeSource getAttributeSource(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java new file mode 100644 index 00000000000..daa055567ce --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java @@ -0,0 +1,189 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +import java.util.HashMap; +import java.util.Map; + +import javax.management.Descriptor; +import javax.management.MBeanInfo; +import javax.management.MBeanParameterInfo; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; +import javax.management.modelmbean.ModelMBeanOperationInfo; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.interceptor.NopInterceptor; +import org.springframework.jmx.IJmxTestBean; +import org.springframework.jmx.JmxTestBean; +import org.springframework.jmx.export.MBeanExporter; +import org.springframework.jmx.export.metadata.JmxAttributeSource; +import org.springframework.jmx.support.ObjectNameManager; + +/** + * @author Rob Harrop + */ +public abstract class AbstractMetadataAssemblerTests extends AbstractJmxAssemblerTests { + + public void testDescription() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + assertEquals("The descriptions are not the same", "My Managed Bean", + info.getDescription()); + } + + public void testAttributeDescriptionOnSetter() throws Exception { + ModelMBeanInfo inf = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = inf.getAttribute(AGE_ATTRIBUTE); + assertEquals("The description for the age attribute is incorrect", + "The Age Attribute", attr.getDescription()); + } + + public void testAttributeDescriptionOnGetter() throws Exception { + ModelMBeanInfo inf = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = inf.getAttribute(NAME_ATTRIBUTE); + assertEquals("The description for the name attribute is incorrect", + "The Name Attribute", attr.getDescription()); + } + + /** + * Tests the situation where the attribute is only defined on the getter. + */ + public void testReadOnlyAttribute() throws Exception { + ModelMBeanInfo inf = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = inf.getAttribute(AGE_ATTRIBUTE); + assertFalse("The age attribute should not be writable", attr.isWritable()); + } + + public void testReadWriteAttribute() throws Exception { + ModelMBeanInfo inf = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = inf.getAttribute(NAME_ATTRIBUTE); + assertTrue("The name attribute should be writable", attr.isWritable()); + assertTrue("The name attribute should be readable", attr.isReadable()); + } + + /** + * Tests the situation where the property only has a getter. + */ + public void testWithOnlySetter() throws Exception { + ModelMBeanInfo inf = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = inf.getAttribute("NickName"); + assertNotNull("Attribute should not be null", attr); + } + + /** + * Tests the situation where the property only has a setter. + */ + public void testWithOnlyGetter() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute("Superman"); + assertNotNull("Attribute should not be null", attr); + } + + public void testManagedResourceDescriptor() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + Descriptor desc = info.getMBeanDescriptor(); + + assertEquals("Logging should be set to true", "true", desc.getFieldValue("log")); + assertEquals("Log file should be jmx.log", "jmx.log", desc.getFieldValue("logFile")); + assertEquals("Currency Time Limit should be 15", "15", desc.getFieldValue("currencyTimeLimit")); + assertEquals("Persist Policy should be OnUpdate", "OnUpdate", desc.getFieldValue("persistPolicy")); + assertEquals("Persist Period should be 200", "200", desc.getFieldValue("persistPeriod")); + assertEquals("Persist Location should be foo", "./foo", desc.getFieldValue("persistLocation")); + assertEquals("Persist Name should be bar", "bar.jmx", desc.getFieldValue("persistName")); + } + + public void testAttributeDescriptor() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + Descriptor desc = info.getAttribute(NAME_ATTRIBUTE).getDescriptor(); + + assertEquals("Default value should be foo", "foo", desc.getFieldValue("default")); + assertEquals("Currency Time Limit should be 20", "20", desc.getFieldValue("currencyTimeLimit")); + assertEquals("Persist Policy should be OnUpdate", "OnUpdate", desc.getFieldValue("persistPolicy")); + assertEquals("Persist Period should be 300", "300", desc.getFieldValue("persistPeriod")); + } + + public void testOperationDescriptor() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + Descriptor desc = info.getOperation("myOperation").getDescriptor(); + + assertEquals("Currency Time Limit should be 30", "30", desc.getFieldValue("currencyTimeLimit")); + assertEquals("Role should be \"operation\"", "operation", desc.getFieldValue("role")); + } + + public void testOperationParameterMetadata() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanOperationInfo oper = info.getOperation("add"); + MBeanParameterInfo[] params = oper.getSignature(); + + assertEquals("Invalid number of params", 2, params.length); + assertEquals("Incorrect name for x param", "x", params[0].getName()); + assertEquals("Incorrect type for x param", int.class.getName(), params[0].getType()); + + assertEquals("Incorrect name for y param", "y", params[1].getName()); + assertEquals("Incorrect type for y param", int.class.getName(), params[1].getType()); + } + + public void testWithCglibProxy() throws Exception { + IJmxTestBean tb = createJmxTestBean(); + ProxyFactory pf = new ProxyFactory(); + pf.setTarget(tb); + pf.addAdvice(new NopInterceptor()); + Object proxy = pf.getProxy(); + + MetadataMBeanInfoAssembler assembler = (MetadataMBeanInfoAssembler) getAssembler(); + + MBeanExporter exporter = new MBeanExporter(); + exporter.setBeanFactory(getContext()); + exporter.setAssembler(assembler); + + String objectName = "spring:bean=test,proxy=true"; + + Map beans = new HashMap(); + beans.put(objectName, proxy); + exporter.setBeans(beans); + exporter.afterPropertiesSet(); + + MBeanInfo inf = getServer().getMBeanInfo(ObjectNameManager.getInstance(objectName)); + assertEquals("Incorrect number of operations", getExpectedOperationCount(), inf.getOperations().length); + assertEquals("Incorrect number of attributes", getExpectedAttributeCount(), inf.getAttributes().length); + + assertTrue("Not included in autodetection", assembler.includeBean(proxy.getClass(), "some bean name")); + } + + protected abstract String getObjectName(); + + protected int getExpectedAttributeCount() { + return 4; + } + + protected int getExpectedOperationCount() { + return 7; + } + + protected IJmxTestBean createJmxTestBean() { + return new JmxTestBean(); + } + + protected MBeanInfoAssembler getAssembler() { + MetadataMBeanInfoAssembler assembler = new MetadataMBeanInfoAssembler(); + assembler.setAttributeSource(getAttributeSource()); + return assembler; + } + + protected abstract JmxAttributeSource getAttributeSource(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/IAdditionalTestMethods.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/IAdditionalTestMethods.java new file mode 100644 index 00000000000..4c7e41c7472 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/IAdditionalTestMethods.java @@ -0,0 +1,13 @@ + +package org.springframework.jmx.export.assembler; + +/** + * @author Rob Harrop + */ +public interface IAdditionalTestMethods { + + String getNickName(); + + void setNickName(String nickName); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomBase.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomBase.java new file mode 100644 index 00000000000..c78d8193ab6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomBase.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +/** + * @author Juergen Hoeller + */ +public interface ICustomBase { + + int add(int x, int y); + + long myOperation(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomJmxBean.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomJmxBean.java new file mode 100644 index 00000000000..5d3621fe3f9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ICustomJmxBean.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +/** + * @author Rob Harrop + */ +public interface ICustomJmxBean extends ICustomBase { + + String getName(); + + void setName(String name); + + int getAge(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java new file mode 100644 index 00000000000..5977597c1ff --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; + +/** + * @author Rob Harrop + */ +public class InterfaceBasedMBeanInfoAssemblerCustomTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean5"; + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 5; + } + + protected int getExpectedAttributeCount() { + return 2; + } + + protected MBeanInfoAssembler getAssembler() { + InterfaceBasedMBeanInfoAssembler assembler = new InterfaceBasedMBeanInfoAssembler(); + assembler.setManagedInterfaces(new Class[] {ICustomJmxBean.class}); + return assembler; + } + + public void testGetAgeIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE); + + assertTrue(attr.isReadable()); + assertFalse(attr.isWritable()); + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/interfaceAssemblerCustom.xml"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java new file mode 100644 index 00000000000..87693fc924f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.assembler; + +import java.util.Properties; + +import javax.management.MBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; + +/** + * @author Rob Harrop + */ +public class InterfaceBasedMBeanInfoAssemblerMappedTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean4"; + + public void testGetAgeIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE); + + assertTrue("Age is not readable", attr.isReadable()); + assertFalse("Age is not writable", attr.isWritable()); + } + + public void testWithUnknownClass() throws Exception { + try { + InterfaceBasedMBeanInfoAssembler assembler = getWithMapping("com.foo.bar.Unknown"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testWithNonInterface() throws Exception { + try { + InterfaceBasedMBeanInfoAssembler assembler = getWithMapping("JmxTestBean"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testWithFallThrough() throws Exception { + InterfaceBasedMBeanInfoAssembler assembler = + getWithMapping("foobar", "org.springframework.jmx.export.assembler.ICustomJmxBean"); + assembler.setManagedInterfaces(new Class[] {IAdditionalTestMethods.class}); + + ModelMBeanInfo inf = assembler.getMBeanInfo(getBean(), getObjectName()); + MBeanAttributeInfo attr = inf.getAttribute("NickName"); + + assertNickName(attr); + } + + public void testNickNameIsExposed() throws Exception { + ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo(); + MBeanAttributeInfo attr = inf.getAttribute("NickName"); + + assertNickName(attr); + } + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 7; + } + + protected int getExpectedAttributeCount() { + return 3; + } + + protected MBeanInfoAssembler getAssembler() throws Exception { + return getWithMapping( + "org.springframework.jmx.export.assembler.IAdditionalTestMethods, " + + "org.springframework.jmx.export.assembler.ICustomJmxBean"); + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/interfaceAssemblerMapped.xml"; + } + + private InterfaceBasedMBeanInfoAssembler getWithMapping(String mapping) { + return getWithMapping(OBJECT_NAME, mapping); + } + + private InterfaceBasedMBeanInfoAssembler getWithMapping(String name, String mapping) { + InterfaceBasedMBeanInfoAssembler assembler = new InterfaceBasedMBeanInfoAssembler(); + Properties props = new Properties(); + props.setProperty(name, mapping); + assembler.setInterfaceMappings(props); + assembler.afterPropertiesSet(); + return assembler; + } + + private void assertNickName(MBeanAttributeInfo attr) { + assertNotNull("Nick Name should not be null", attr); + assertTrue("Nick Name should be writable", attr.isWritable()); + assertTrue("Nick Name should be readab;e", attr.isReadable()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerTests.java new file mode 100644 index 00000000000..6d8266b4aca --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +/** + * @author Rob Harrop + */ +public class InterfaceBasedMBeanInfoAssemblerTests extends AbstractJmxAssemblerTests { + + protected String getObjectName() { + return "bean:name=testBean4"; + } + + protected int getExpectedOperationCount() { + return 7; + } + + protected int getExpectedAttributeCount() { + return 2; + } + + protected MBeanInfoAssembler getAssembler() { + return new InterfaceBasedMBeanInfoAssembler(); + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/interfaceAssembler.xml"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java new file mode 100644 index 00000000000..73d4fb56f51 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.assembler; + +import java.util.Properties; + +import javax.management.MBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; + +/** + * @author Juergen Hoeller + * @author Rob Harrop + */ +public class MethodExclusionMBeanInfoAssemblerComboTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean4"; + + public void testGetAgeIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE); + assertTrue("Age is not readable", attr.isReadable()); + assertFalse("Age is not writable", attr.isWritable()); + } + + public void testNickNameIsExposed() throws Exception { + ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo(); + MBeanAttributeInfo attr = inf.getAttribute("NickName"); + assertNotNull("Nick Name should not be null", attr); + assertTrue("Nick Name should be writable", attr.isWritable()); + assertTrue("Nick Name should be readable", attr.isReadable()); + } + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 7; + } + + protected int getExpectedAttributeCount() { + return 3; + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/methodExclusionAssemblerCombo.xml"; + } + + protected MBeanInfoAssembler getAssembler() throws Exception { + MethodExclusionMBeanInfoAssembler assembler = new MethodExclusionMBeanInfoAssembler(); + Properties props = new Properties(); + props.setProperty(OBJECT_NAME, "setAge,isSuperman,setSuperman,dontExposeMe"); + assembler.setIgnoredMethodMappings(props); + assembler.setIgnoredMethods(new String[] {"someMethod"}); + return assembler; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java new file mode 100644 index 00000000000..a3f11f9fef6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.assembler; + +import java.util.Properties; + +import javax.management.MBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; + +/** + * @author Rob Harrop + */ +public class MethodExclusionMBeanInfoAssemblerMappedTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean4"; + + public void testGetAgeIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE); + assertTrue("Age is not readable", attr.isReadable()); + assertFalse("Age is not writable", attr.isWritable()); + } + + public void testNickNameIsExposed() throws Exception { + ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo(); + MBeanAttributeInfo attr = inf.getAttribute("NickName"); + assertNotNull("Nick Name should not be null", attr); + assertTrue("Nick Name should be writable", attr.isWritable()); + assertTrue("Nick Name should be readable", attr.isReadable()); + } + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 7; + } + + protected int getExpectedAttributeCount() { + return 3; + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/methodExclusionAssemblerMapped.xml"; + } + + protected MBeanInfoAssembler getAssembler() throws Exception { + MethodExclusionMBeanInfoAssembler assembler = new MethodExclusionMBeanInfoAssembler(); + Properties props = new Properties(); + props.setProperty(OBJECT_NAME, "setAge,isSuperman,setSuperman,dontExposeMe"); + assembler.setIgnoredMethodMappings(props); + return assembler; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java new file mode 100644 index 00000000000..c19ef5969da --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.assembler; + +import java.util.Properties; + +import javax.management.MBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; + +/** + * @author Juergen Hoeller + * @author Rob Harrop + */ +public class MethodExclusionMBeanInfoAssemblerNotMappedTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean4"; + + public void testGetAgeIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE); + assertTrue("Age is not readable", attr.isReadable()); + assertTrue("Age is not writable", attr.isWritable()); + } + + public void testNickNameIsExposed() throws Exception { + ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo(); + MBeanAttributeInfo attr = inf.getAttribute("NickName"); + assertNotNull("Nick Name should not be null", attr); + assertTrue("Nick Name should be writable", attr.isWritable()); + assertTrue("Nick Name should be readable", attr.isReadable()); + } + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 11; + } + + protected int getExpectedAttributeCount() { + return 4; + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/methodExclusionAssemblerNotMapped.xml"; + } + + protected MBeanInfoAssembler getAssembler() throws Exception { + MethodExclusionMBeanInfoAssembler assembler = new MethodExclusionMBeanInfoAssembler(); + Properties props = new Properties(); + props.setProperty("bean:name=testBean5", "setAge,isSuperman,setSuperman,dontExposeMe"); + assembler.setIgnoredMethodMappings(props); + return assembler; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java new file mode 100644 index 00000000000..64c6bb7f395 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.assembler; + +import java.lang.reflect.Method; +import java.util.Properties; + +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; + +import org.springframework.jmx.JmxTestBean; + +/** + * @author Rob Harrop + * @author Rick Evans + */ +public class MethodExclusionMBeanInfoAssemblerTests extends AbstractJmxAssemblerTests { + + private static final String OBJECT_NAME = "bean:name=testBean5"; + + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 9; + } + + protected int getExpectedAttributeCount() { + return 4; + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/methodExclusionAssembler.xml"; + } + + protected MBeanInfoAssembler getAssembler() { + MethodExclusionMBeanInfoAssembler assembler = new MethodExclusionMBeanInfoAssembler(); + assembler.setIgnoredMethods(new String[] {"dontExposeMe", "setSuperman"}); + return assembler; + } + + public void testSupermanIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute("Superman"); + + assertTrue(attr.isReadable()); + assertFalse(attr.isWritable()); + } + + /* + * http://opensource.atlassian.com/projects/spring/browse/SPR-2754 + */ + public void testIsNotIgnoredDoesntIgnoreUnspecifiedBeanMethods() throws Exception { + final String beanKey = "myTestBean"; + MethodExclusionMBeanInfoAssembler assembler = new MethodExclusionMBeanInfoAssembler(); + Properties ignored = new Properties(); + ignored.setProperty(beanKey, "dontExposeMe,setSuperman"); + assembler.setIgnoredMethodMappings(ignored); + Method method = JmxTestBean.class.getMethod("dontExposeMe", null); + assertFalse(assembler.isNotIgnored(method, beanKey)); + // this bean does not have any ignored methods on it, so must obviously not be ignored... + assertTrue(assembler.isNotIgnored(method, "someOtherBeanKey")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java new file mode 100644 index 00000000000..71bbbad39ed --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +import javax.management.MBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; +import java.util.Properties; + +/** + * @author Rob Harrop + */ +public class MethodNameBasedMBeanInfoAssemblerMappedTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean4"; + + public void testGetAgeIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE); + + assertTrue("Age is not readable", attr.isReadable()); + assertFalse("Age is not writable", attr.isWritable()); + } + + public void testWithFallThrough() throws Exception { + MethodNameBasedMBeanInfoAssembler assembler = + getWithMapping("foobar", "add,myOperation,getName,setName,getAge"); + assembler.setManagedMethods(new String[]{"getNickName", "setNickName"}); + + ModelMBeanInfo inf = assembler.getMBeanInfo(getBean(), getObjectName()); + MBeanAttributeInfo attr = inf.getAttribute("NickName"); + + assertNickName(attr); + } + + public void testNickNameIsExposed() throws Exception { + ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo(); + MBeanAttributeInfo attr = inf.getAttribute("NickName"); + + assertNickName(attr); + } + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 7; + } + + protected int getExpectedAttributeCount() { + return 3; + } + + protected MBeanInfoAssembler getAssembler() throws Exception { + return getWithMapping("getNickName,setNickName,add,myOperation,getName,setName,getAge"); + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/methodNameAssemblerMapped.xml"; + } + + private MethodNameBasedMBeanInfoAssembler getWithMapping(String mapping) { + return getWithMapping(OBJECT_NAME, mapping); + } + + private MethodNameBasedMBeanInfoAssembler getWithMapping(String name, String mapping) { + MethodNameBasedMBeanInfoAssembler assembler = new MethodNameBasedMBeanInfoAssembler(); + Properties props = new Properties(); + props.setProperty(name, mapping); + assembler.setMethodMappings(props); + return assembler; + } + + private void assertNickName(MBeanAttributeInfo attr) { + assertNotNull("Nick Name should not be null", attr); + assertTrue("Nick Name should be writable", attr.isWritable()); + assertTrue("Nick Name should be readable", attr.isReadable()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java new file mode 100644 index 00000000000..049c7fde5f7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanInfo; + +/** + * @author Rob Harrop + */ +public class MethodNameBasedMBeanInfoAssemblerTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean5"; + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 5; + } + + protected int getExpectedAttributeCount() { + return 2; + } + + protected MBeanInfoAssembler getAssembler() { + MethodNameBasedMBeanInfoAssembler assembler = new MethodNameBasedMBeanInfoAssembler(); + assembler.setManagedMethods(new String[] {"add", "myOperation", "getName", "setName", "getAge"}); + return assembler; + } + + public void testGetAgeIsReadOnly() throws Exception { + ModelMBeanInfo info = getMBeanInfoFromAssembler(); + ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE); + + assertTrue(attr.isReadable()); + assertFalse(attr.isWritable()); + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/methodNameAssembler.xml"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ReflectiveAssemblerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ReflectiveAssemblerTests.java new file mode 100644 index 00000000000..c231561fc91 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/ReflectiveAssemblerTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.assembler; + + + + +/** + * @author Rob Harrop + */ +public class ReflectiveAssemblerTests extends AbstractJmxAssemblerTests { + + protected static final String OBJECT_NAME = "bean:name=testBean1"; + + protected String getObjectName() { + return OBJECT_NAME; + } + + protected int getExpectedOperationCount() { + return 11; + } + + protected int getExpectedAttributeCount() { + return 4; + } + + protected MBeanInfoAssembler getAssembler() { + return new SimpleReflectiveMBeanInfoAssembler(); + } + + protected String getApplicationContextPath() { + return "org/springframework/jmx/export/assembler/reflectiveAssembler.xml"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssembler.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssembler.xml new file mode 100644 index 00000000000..0e0ca9a6f3a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssembler.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerCustom.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerCustom.xml new file mode 100644 index 00000000000..5246986ac05 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerCustom.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + org.springframework.jmx.export.assembler.ICustomJmxBean + + + + + + + + + + + + + + + TEST + + + 100 + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerMapped.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerMapped.xml new file mode 100644 index 00000000000..1d8df62050b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/interfaceAssemblerMapped.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + org.springframework.jmx.export.assembler.IAdditionalTestMethods, + org.springframework.jmx.export.assembler.ICustomJmxBean + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadata-autodetect.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadata-autodetect.xml new file mode 100644 index 00000000000..c90c5284c21 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadata-autodetect.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadataAssembler.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadataAssembler.xml new file mode 100644 index 00000000000..c43e200a596 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/metadataAssembler.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssembler.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssembler.xml new file mode 100644 index 00000000000..5a4c3585a7f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssembler.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerCombo.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerCombo.xml new file mode 100644 index 00000000000..b2fb2536840 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerCombo.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + setAge,isSuperman,setSuperman,dontExposeMe + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerMapped.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerMapped.xml new file mode 100644 index 00000000000..16f4290a8f3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerMapped.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + setAge,isSuperman,setSuperman,dontExposeMe + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerNotMapped.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerNotMapped.xml new file mode 100644 index 00000000000..7dcf380c525 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodExclusionAssemblerNotMapped.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + setAge,isSuperman,setSuperman,dontExposeMe + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssembler.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssembler.xml new file mode 100644 index 00000000000..20554a2a311 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssembler.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + add,myOperation,getName,setName,getAge + + + + + + + + + + + + + + + TEST + + + 100 + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssemblerMapped.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssemblerMapped.xml new file mode 100644 index 00000000000..98944a99845 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/methodNameAssemblerMapped.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + getNickName,setNickName,add,myOperation,getName,setName,getAge + + + + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/reflectiveAssembler.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/reflectiveAssembler.xml new file mode 100644 index 00000000000..e61a8eb0ad2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/assembler/reflectiveAssembler.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + TEST + + + 100 + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectLazyMBeans.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectLazyMBeans.xml new file mode 100644 index 00000000000..960a57b12cb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectLazyMBeans.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectMBeans.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectMBeans.xml new file mode 100644 index 00000000000..c45205909b9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectMBeans.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectNoMBeans.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectNoMBeans.xml new file mode 100644 index 00000000000..66c6033611c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/autodetectNoMBeans.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/customConfigurer.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/customConfigurer.xml new file mode 100644 index 00000000000..dea76ccada0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/customConfigurer.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + yyyy/MM/dd + + + + + true + + + + + + + + + + 2004/10/12 + + + 2004/11/13 + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/excludedBeans.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/excludedBeans.xml new file mode 100644 index 00000000000..6dc3aba71f9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/excludedBeans.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + true + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/lazyInit.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/lazyInit.xml new file mode 100644 index 00000000000..ddc1fb1da89 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/lazyInit.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/AbstractNamingStrategyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/AbstractNamingStrategyTests.java new file mode 100644 index 00000000000..0007e7ef703 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/AbstractNamingStrategyTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.naming; + +import javax.management.ObjectName; + +import junit.framework.TestCase; + +/** + * @author Rob Harrop + */ +public abstract class AbstractNamingStrategyTests extends TestCase { + + public void testNaming() throws Exception { + ObjectNamingStrategy strat = getStrategy(); + ObjectName objectName = strat.getObjectName(getManagedResource(), getKey()); + assertEquals(objectName.getCanonicalName(), getCorrectObjectName()); + } + + protected abstract ObjectNamingStrategy getStrategy() throws Exception; + + protected abstract Object getManagedResource() throws Exception; + + protected abstract String getKey(); + + protected abstract String getCorrectObjectName(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/IdentityNamingStrategyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/IdentityNamingStrategyTests.java new file mode 100644 index 00000000000..a62755bd0f0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/IdentityNamingStrategyTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.naming; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.springframework.jmx.JmxTestBean; +import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; + +/** + * @author Rob Harrop + */ +public class IdentityNamingStrategyTests extends TestCase { + + public void testNaming() throws MalformedObjectNameException { + JmxTestBean bean = new JmxTestBean(); + IdentityNamingStrategy strategy = new IdentityNamingStrategy(); + ObjectName objectName = strategy.getObjectName(bean, "null"); + assertEquals("Domain is incorrect", bean.getClass().getPackage().getName(), + objectName.getDomain()); + assertEquals("Type property is incorrect", ClassUtils.getShortName(bean.getClass()), + objectName.getKeyProperty(IdentityNamingStrategy.TYPE_KEY)); + assertEquals("HashCode property is incorrect", ObjectUtils.getIdentityHexString(bean), + objectName.getKeyProperty(IdentityNamingStrategy.HASH_CODE_KEY)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/KeyNamingStrategyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/KeyNamingStrategyTests.java new file mode 100644 index 00000000000..9fa33e73ed4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/KeyNamingStrategyTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.naming; + +/** + * @author Rob Harrop + */ +public class KeyNamingStrategyTests extends AbstractNamingStrategyTests { + + private static final String OBJECT_NAME = "spring:name=test"; + + protected ObjectNamingStrategy getStrategy() throws Exception { + return new KeyNamingStrategy(); + } + + protected Object getManagedResource() { + return new Object(); + } + + protected String getKey() { + return OBJECT_NAME; + } + + protected String getCorrectObjectName() { + return OBJECT_NAME; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesFileNamingStrategyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesFileNamingStrategyTests.java new file mode 100644 index 00000000000..9011c372967 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesFileNamingStrategyTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.naming; + +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + */ +public class PropertiesFileNamingStrategyTests extends PropertiesNamingStrategyTests { + + protected ObjectNamingStrategy getStrategy() throws Exception { + KeyNamingStrategy strat = new KeyNamingStrategy(); + strat.setMappingLocation(new ClassPathResource("jmx-names.properties", getClass())); + strat.afterPropertiesSet(); + return strat; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesNamingStrategyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesNamingStrategyTests.java new file mode 100644 index 00000000000..7ce9e2ecde1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/PropertiesNamingStrategyTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.export.naming; + +import java.util.Properties; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class PropertiesNamingStrategyTests extends AbstractNamingStrategyTests { + + private static final String OBJECT_NAME = "bean:name=namingTest"; + + protected ObjectNamingStrategy getStrategy() throws Exception { + KeyNamingStrategy strat = new KeyNamingStrategy(); + Properties mappings = new Properties(); + mappings.setProperty("namingTest", "bean:name=namingTest"); + strat.setMappings(mappings); + strat.afterPropertiesSet(); + return strat; + } + + protected Object getManagedResource() { + return new Object(); + } + + protected String getKey() { + return "namingTest"; + } + + protected String getCorrectObjectName() { + return OBJECT_NAME; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/jmx-names.properties b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/jmx-names.properties new file mode 100644 index 00000000000..9239236b2be --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/naming/jmx-names.properties @@ -0,0 +1 @@ +namingTest = bean:name=namingTest diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notification/ModelMBeanNotificationPublisherTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notification/ModelMBeanNotificationPublisherTests.java new file mode 100644 index 00000000000..486a35df6e0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notification/ModelMBeanNotificationPublisherTests.java @@ -0,0 +1,136 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.notification; + +import javax.management.AttributeChangeNotification; +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import junit.framework.TestCase; + +import org.springframework.jmx.export.SpringModelMBean; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + */ +public final class ModelMBeanNotificationPublisherTests extends TestCase { + + public void testCtorWithNullMBean() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ModelMBeanNotificationPublisher(null, createObjectName(), this); + } + }.runTest(); + } + + public void testCtorWithNullObjectName() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ModelMBeanNotificationPublisher(new SpringModelMBean(), null, this); + } + }.runTest(); + } + + public void testCtorWithNullManagedResource() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ModelMBeanNotificationPublisher(new SpringModelMBean(), createObjectName(), null); + } + }.runTest(); + } + + public void testSendNullNotification() throws Exception { + final NotificationPublisher publisher + = new ModelMBeanNotificationPublisher(new SpringModelMBean(), createObjectName(), this); + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + publisher.sendNotification(null); + } + }.runTest(); + } + + public void testSendVanillaNotification() throws Exception { + StubSpringModelMBean mbean = new StubSpringModelMBean(); + Notification notification = new Notification("network.alarm.router", mbean, 1872); + ObjectName objectName = createObjectName(); + + NotificationPublisher publisher = new ModelMBeanNotificationPublisher(mbean, objectName, mbean); + publisher.sendNotification(notification); + + assertNotNull(mbean.getActualNotification()); + assertSame("The exact same Notification is not being passed through from the publisher to the mbean.", notification, mbean.getActualNotification()); + assertSame("The 'source' property of the Notification is not being set to the ObjectName of the associated MBean.", objectName, mbean.getActualNotification().getSource()); + } + + public void testSendAttributeChangeNotification() throws Exception { + StubSpringModelMBean mbean = new StubSpringModelMBean(); + Notification notification = new AttributeChangeNotification(mbean, 1872, System.currentTimeMillis(), "Shall we break for some tea?", "agree", "java.lang.Boolean", Boolean.FALSE, Boolean.TRUE); + ObjectName objectName = createObjectName(); + + NotificationPublisher publisher = new ModelMBeanNotificationPublisher(mbean, objectName, mbean); + publisher.sendNotification(notification); + + assertNotNull(mbean.getActualNotification()); + assertTrue(mbean.getActualNotification() instanceof AttributeChangeNotification); + assertSame("The exact same Notification is not being passed through from the publisher to the mbean.", notification, mbean.getActualNotification()); + assertSame("The 'source' property of the Notification is not being set to the ObjectName of the associated MBean.", objectName, mbean.getActualNotification().getSource()); + } + + public void testSendAttributeChangeNotificationWhereSourceIsNotTheManagedResource() throws Exception { + StubSpringModelMBean mbean = new StubSpringModelMBean(); + Notification notification = new AttributeChangeNotification(this, 1872, System.currentTimeMillis(), "Shall we break for some tea?", "agree", "java.lang.Boolean", Boolean.FALSE, Boolean.TRUE); + ObjectName objectName = createObjectName(); + + NotificationPublisher publisher = new ModelMBeanNotificationPublisher(mbean, objectName, mbean); + publisher.sendNotification(notification); + + assertNotNull(mbean.getActualNotification()); + assertTrue(mbean.getActualNotification() instanceof AttributeChangeNotification); + assertSame("The exact same Notification is not being passed through from the publisher to the mbean.", notification, mbean.getActualNotification()); + assertSame("The 'source' property of the Notification is *wrongly* being set to the ObjectName of the associated MBean.", this, mbean.getActualNotification().getSource()); + } + + private static ObjectName createObjectName() throws MalformedObjectNameException { + return ObjectName.getInstance("foo:type=bar"); + } + + + private static class StubSpringModelMBean extends SpringModelMBean { + + private Notification actualNotification; + + public StubSpringModelMBean() throws MBeanException, RuntimeOperationsException { + } + + public Notification getActualNotification() { + return this.actualNotification; + } + + public void sendNotification(Notification notification) throws RuntimeOperationsException { + this.actualNotification = notification; + } + + public void sendAttributeChangeNotification(AttributeChangeNotification notification) throws RuntimeOperationsException { + this.actualNotification = notification; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherLazyTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherLazyTests.xml new file mode 100644 index 00000000000..9489f7bfe18 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherLazyTests.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherTests.xml new file mode 100644 index 00000000000..459820c27dc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/notificationPublisherTests.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/propertyPlaceholderConfigurer.xml b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/propertyPlaceholderConfigurer.xml new file mode 100644 index 00000000000..b108c30e01d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/export/propertyPlaceholderConfigurer.xml @@ -0,0 +1,49 @@ + + + + + + + + + Rob Harrop + 100 + myScope + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${testBean.name} + + + ${testBean.age} + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java new file mode 100644 index 00000000000..8525535ef8f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java @@ -0,0 +1,120 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.support; + +import java.io.IOException; +import java.net.MalformedURLException; + +import javax.management.InstanceNotFoundException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.springframework.jmx.AbstractMBeanServerTests; + +/** + * @author Rob Harrop + */ +public class ConnectorServerFactoryBeanTests extends AbstractMBeanServerTests { + + private static final String OBJECT_NAME = "spring:type=connector,name=test"; + + public void testStartupWithLocatedServer() throws Exception { + ConnectorServerFactoryBean bean = new ConnectorServerFactoryBean(); + bean.afterPropertiesSet(); + + try { + checkServerConnection(getServer()); + } + finally { + bean.destroy(); + } + } + + public void testStartupWithSuppliedServer() throws Exception { + //Added a brief snooze here - seems to fix occasional + //java.net.BindException: Address already in use errors + Thread.sleep(1); + + ConnectorServerFactoryBean bean = new ConnectorServerFactoryBean(); + bean.setServer(getServer()); + bean.afterPropertiesSet(); + + try { + checkServerConnection(getServer()); + } + finally { + bean.destroy(); + } + } + + public void testRegisterWithMBeanServer() throws Exception { + //Added a brief snooze here - seems to fix occasional + //java.net.BindException: Address already in use errors + Thread.sleep(1); + ConnectorServerFactoryBean bean = new ConnectorServerFactoryBean(); + bean.setObjectName(OBJECT_NAME); + bean.afterPropertiesSet(); + + try { + // Try to get the connector bean. + ObjectInstance instance = getServer().getObjectInstance(ObjectName.getInstance(OBJECT_NAME)); + assertNotNull("ObjectInstance should not be null", instance); + } + finally { + bean.destroy(); + } + } + + public void testNoRegisterWithMBeanServer() throws Exception { + ConnectorServerFactoryBean bean = new ConnectorServerFactoryBean(); + bean.afterPropertiesSet(); + + try { + // Try to get the connector bean. + getServer().getObjectInstance(ObjectName.getInstance(OBJECT_NAME)); + fail("Instance should not be found"); + } + catch (InstanceNotFoundException ex) { + // expected + } + finally { + bean.destroy(); + } + } + + private void checkServerConnection(MBeanServer hostedServer) throws IOException, MalformedURLException { + // Try to connect using client. + JMXServiceURL serviceURL = new JMXServiceURL(ConnectorServerFactoryBean.DEFAULT_SERVICE_URL); + JMXConnector connector = JMXConnectorFactory.connect(serviceURL); + + assertNotNull("Client Connector should not be null", connector); + + // Get the MBean server connection. + MBeanServerConnection connection = connector.getMBeanServerConnection(); + assertNotNull("MBeanServerConnection should not be null", connection); + + // Test for MBean server equality. + assertEquals("Registered MBean count should be the same", + hostedServer.getMBeanCount(), connection.getMBeanCount()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/JmxUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/JmxUtilsTests.java new file mode 100644 index 00000000000..0bc2bebdd01 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/JmxUtilsTests.java @@ -0,0 +1,243 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.support; + +import java.beans.PropertyDescriptor; + +import javax.management.DynamicMBean; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +import junit.framework.TestCase; + +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.core.JdkVersion; +import org.springframework.jmx.IJmxTestBean; +import org.springframework.jmx.JmxTestBean; +import org.springframework.jmx.export.TestDynamicMBean; +import org.springframework.util.ObjectUtils; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class JmxUtilsTests extends TestCase { + + public void testIsMBeanWithDynamicMBean() throws Exception { + DynamicMBean mbean = new TestDynamicMBean(); + assertTrue("Dynamic MBean not detected correctly", JmxUtils.isMBean(mbean.getClass())); + } + + public void testIsMBeanWithStandardMBeanWrapper() throws Exception { + StandardMBean mbean = new StandardMBean(new JmxTestBean(), IJmxTestBean.class); + assertTrue("Standard MBean not detected correctly", JmxUtils.isMBean(mbean.getClass())); + } + + public void testIsMBeanWithStandardMBeanInherited() throws Exception { + StandardMBean mbean = new StandardMBeanImpl(); + assertTrue("Standard MBean not detected correctly", JmxUtils.isMBean(mbean.getClass())); + } + + public void testNotAnMBean() throws Exception { + assertFalse("Object incorrectly identified as an MBean", JmxUtils.isMBean(Object.class)); + } + + public void testSimpleMBean() throws Exception { + Foo foo = new Foo(); + assertTrue("Simple MBean not detected correctly", JmxUtils.isMBean(foo.getClass())); + } + + public void testSimpleMXBean() throws Exception { + FooX foo = new FooX(); + assertTrue("Simple MXBean not detected correctly", JmxUtils.isMBean(foo.getClass())); + } + + public void testSimpleMBeanThroughInheritance() throws Exception { + Bar bar = new Bar(); + Abc abc = new Abc(); + assertTrue("Simple MBean (through inheritance) not detected correctly", + JmxUtils.isMBean(bar.getClass())); + assertTrue("Simple MBean (through 2 levels of inheritance) not detected correctly", + JmxUtils.isMBean(abc.getClass())); + } + + public void testGetAttributeNameWithStrictCasing() { + PropertyDescriptor pd = new BeanWrapperImpl(AttributeTest.class).getPropertyDescriptor("name"); + String attributeName = JmxUtils.getAttributeName(pd, true); + assertEquals("Incorrect casing on attribute name", "Name", attributeName); + } + + public void testGetAttributeNameWithoutStrictCasing() { + PropertyDescriptor pd = new BeanWrapperImpl(AttributeTest.class).getPropertyDescriptor("name"); + String attributeName = JmxUtils.getAttributeName(pd, false); + assertEquals("Incorrect casing on attribute name", "name", attributeName); + } + + public void testAppendIdentityToObjectName() throws MalformedObjectNameException { + ObjectName objectName = ObjectNameManager.getInstance("spring:type=Test"); + Object managedResource = new Object(); + ObjectName uniqueName = JmxUtils.appendIdentityToObjectName(objectName, managedResource); + + String typeProperty = "type"; + + assertEquals("Domain of transformed name is incorrect", objectName.getDomain(), uniqueName.getDomain()); + assertEquals("Type key is incorrect", objectName.getKeyProperty(typeProperty), uniqueName.getKeyProperty("type")); + assertEquals("Identity key is incorrect", ObjectUtils.getIdentityHexString(managedResource), uniqueName.getKeyProperty(JmxUtils.IDENTITY_OBJECT_NAME_KEY)); + } + + public void testLocatePlatformMBeanServer() { + if(JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + + MBeanServer server = null; + try { + server = JmxUtils.locateMBeanServer(); + } + finally { + if (server != null) { + MBeanServerFactory.releaseMBeanServer(server); + } + } + } + + public void testIsMBean() { + // Correctly returns true for a class + assertTrue(JmxUtils.isMBean(JmxClassTest.class)); + + // Correctly returns false since JmxUtils won't navigate to the extended interface + assertFalse(JmxUtils.isMBean(SpecializedJmxInterfaceTest.class)); + + // Incorrectly returns true since it doesn't detect that this is an interface + assertFalse(JmxUtils.isMBean(JmxInterfaceTest.class)); + } + + + public static class AttributeTest { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + + public static class StandardMBeanImpl extends StandardMBean implements IJmxTestBean { + + public StandardMBeanImpl() throws NotCompliantMBeanException { + super(IJmxTestBean.class); + } + + public int add(int x, int y) { + return 0; + } + + public long myOperation() { + return 0; + } + + public int getAge() { + return 0; + } + + public void setAge(int age) { + } + + public void setName(String name) { + } + + public String getName() { + return null; + } + + public void dontExposeMe() { + } + } + + + public static interface FooMBean { + + String getName(); + } + + + public static class Foo implements FooMBean { + + public String getName() { + return "Rob Harrop"; + } + } + + + public static interface FooMXBean { + + String getName(); + } + + + public static class FooX implements FooMXBean { + + public String getName() { + return "Rob Harrop"; + } + } + + + public static class Bar extends Foo { + + } + + + public static class Abc extends Bar { + + } + + + private static interface JmxInterfaceTestMBean { + + } + + + private static interface JmxInterfaceTest extends JmxInterfaceTestMBean { + + } + + + private static interface SpecializedJmxInterfaceTest extends JmxInterfaceTest { + + } + + + private static interface JmxClassTestMBean { + + } + + + private static class JmxClassTest implements JmxClassTestMBean { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java new file mode 100644 index 00000000000..5c0e2d917e9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.support; + +import java.net.MalformedURLException; + +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +import org.springframework.aop.support.AopUtils; +import org.springframework.jmx.AbstractMBeanServerTests; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class MBeanServerConnectionFactoryBeanTests extends AbstractMBeanServerTests { + + private static final String SERVICE_URL = "service:jmx:jmxmp://localhost:9876"; + + private JMXServiceURL getServiceUrl() throws MalformedURLException { + return new JMXServiceURL(SERVICE_URL); + } + + private JMXConnectorServer getConnectorServer() throws Exception { + return JMXConnectorServerFactory.newJMXConnectorServer(getServiceUrl(), null, getServer()); + } + + public void testValidConnection() throws Exception { + JMXConnectorServer connectorServer = getConnectorServer(); + connectorServer.start(); + + try { + MBeanServerConnectionFactoryBean bean = new MBeanServerConnectionFactoryBean(); + bean.setServiceUrl(SERVICE_URL); + bean.afterPropertiesSet(); + + try { + MBeanServerConnection connection = (MBeanServerConnection) bean.getObject(); + assertNotNull("Connection should not be null", connection); + + // perform simple MBean count test + assertEquals("MBean count should be the same", getServer().getMBeanCount(), connection.getMBeanCount()); + } + finally { + bean.destroy(); + } + } + finally { + connectorServer.stop(); + } + } + + public void testWithNoServiceUrl() throws Exception { + MBeanServerConnectionFactoryBean bean = new MBeanServerConnectionFactoryBean(); + try { + bean.afterPropertiesSet(); + fail("IllegalArgumentException should be raised when no service url is provided"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testWithLazyConnection() throws Exception { + MBeanServerConnectionFactoryBean bean = new MBeanServerConnectionFactoryBean(); + bean.setServiceUrl(SERVICE_URL); + bean.setConnectOnStartup(false); + bean.afterPropertiesSet(); + + MBeanServerConnection connection = (MBeanServerConnection) bean.getObject(); + assertTrue(AopUtils.isAopProxy(connection)); + + JMXConnectorServer connector = null; + try { + connector = getConnectorServer(); + connector.start(); + assertEquals("Incorrect MBean count", getServer().getMBeanCount(), connection.getMBeanCount()); + } + finally { + bean.destroy(); + if (connector != null) { + connector.stop(); + } + } + } + + public void testWithLazyConnectionAndNoAccess() throws Exception { + MBeanServerConnectionFactoryBean bean = new MBeanServerConnectionFactoryBean(); + bean.setServiceUrl(SERVICE_URL); + bean.setConnectOnStartup(false); + bean.afterPropertiesSet(); + + MBeanServerConnection connection = (MBeanServerConnection) bean.getObject(); + assertTrue(AopUtils.isAopProxy(connection)); + bean.destroy(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerFactoryBeanTests.java new file mode 100644 index 00000000000..c12ecf5f8ec --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jmx/support/MBeanServerFactoryBeanTests.java @@ -0,0 +1,121 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.jmx.support; + +import java.util.List; + +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; + +import junit.framework.TestCase; + +/** + * @author Rob Harrop + */ +public class MBeanServerFactoryBeanTests extends TestCase { + + public void testGetObject() throws Exception { + MBeanServerFactoryBean bean = new MBeanServerFactoryBean(); + bean.afterPropertiesSet(); + try { + MBeanServer server = (MBeanServer) bean.getObject(); + assertNotNull("The MBeanServer should not be null", server); + } + finally { + bean.destroy(); + } + } + + public void testDefaultDomain() throws Exception { + MBeanServerFactoryBean bean = new MBeanServerFactoryBean(); + bean.setDefaultDomain("foo"); + bean.afterPropertiesSet(); + try { + MBeanServer server = (MBeanServer) bean.getObject(); + assertEquals("The default domain should be foo", "foo", server.getDefaultDomain()); + } + finally { + bean.destroy(); + } + } + + public void testWithLocateExistingAndExistingServer() { + MBeanServer server = MBeanServerFactory.createMBeanServer(); + try { + MBeanServerFactoryBean bean = new MBeanServerFactoryBean(); + bean.setLocateExistingServerIfPossible(true); + bean.afterPropertiesSet(); + try { + MBeanServer otherServer = (MBeanServer) bean.getObject(); + assertSame("Existing MBeanServer not located", server, otherServer); + } + finally { + bean.destroy(); + } + } + finally { + MBeanServerFactory.releaseMBeanServer(server); + } + } + + public void testWithLocateExistingAndNoExistingServer() { + MBeanServerFactoryBean bean = new MBeanServerFactoryBean(); + bean.setLocateExistingServerIfPossible(true); + bean.afterPropertiesSet(); + try { + assertNotNull("MBeanServer not created", bean.getObject()); + } + finally { + bean.destroy(); + } + } + + public void testCreateMBeanServer() throws Exception { + testCreation(true, "The server should be available in the list"); + } + + public void testNewMBeanServer() throws Exception { + testCreation(false, "The server should not be available in the list"); + } + + private void testCreation(boolean referenceShouldExist, String failMsg) throws Exception { + MBeanServerFactoryBean bean = new MBeanServerFactoryBean(); + bean.setRegisterWithFactory(referenceShouldExist); + bean.afterPropertiesSet(); + + try { + MBeanServer server = (MBeanServer) bean.getObject(); + List servers = MBeanServerFactory.findMBeanServer(null); + + boolean found = false; + for (int x = 0; x < servers.size(); x++) { + if (servers.get(x) == server) { + found = true; + break; + } + } + + if (!(found == referenceShouldExist)) { + fail(failMsg); + } + } + finally { + bean.destroy(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiObjectFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiObjectFactoryBeanTests.java new file mode 100644 index 00000000000..a685cfae906 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiObjectFactoryBeanTests.java @@ -0,0 +1,385 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jndi; + +import javax.naming.Context; +import javax.naming.NamingException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.mock.jndi.ExpectedLookupTemplate; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class JndiObjectFactoryBeanTests extends TestCase { + + public void testNoJndiName() throws NamingException { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + try { + jof.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + } + } + + public void testLookupWithFullNameAndResourceRefTrue() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("java:comp/env/foo", o)); + jof.setJndiName("java:comp/env/foo"); + jof.setResourceRef(true); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() == o); + } + + public void testLookupWithFullNameAndResourceRefFalse() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("java:comp/env/foo", o)); + jof.setJndiName("java:comp/env/foo"); + jof.setResourceRef(false); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() == o); + } + + public void testLookupWithSchemeNameAndResourceRefTrue() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("java:foo", o)); + jof.setJndiName("java:foo"); + jof.setResourceRef(true); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() == o); + } + + public void testLookupWithSchemeNameAndResourceRefFalse() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("java:foo", o)); + jof.setJndiName("java:foo"); + jof.setResourceRef(false); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() == o); + } + + public void testLookupWithShortNameAndResourceRefTrue() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("java:comp/env/foo", o)); + jof.setJndiName("foo"); + jof.setResourceRef(true); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() == o); + } + + public void testLookupWithShortNameAndResourceRefFalse() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("java:comp/env/foo", o)); + jof.setJndiName("foo"); + jof.setResourceRef(false); + try { + jof.afterPropertiesSet(); + fail("Should have thrown NamingException"); + } + catch (NamingException ex) { + // expected + } + } + + public void testLookupWithArbitraryNameAndResourceRefFalse() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", o)); + jof.setJndiName("foo"); + jof.setResourceRef(false); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() == o); + } + + public void testLookupWithExpectedTypeAndMatch() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + String s = ""; + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s)); + jof.setJndiName("foo"); + jof.setExpectedType(String.class); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() == s); + } + + public void testLookupWithExpectedTypeAndNoMatch() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + Object o = new Object(); + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", o)); + jof.setJndiName("foo"); + jof.setExpectedType(String.class); + try { + jof.afterPropertiesSet(); + fail("Should have thrown NamingException"); + } + catch (NamingException ex) { + assertTrue(ex.getMessage().indexOf("java.lang.String") != -1); + } + } + + public void testLookupWithDefaultObject() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + String s = ""; + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s)); + jof.setJndiName("myFoo"); + jof.setExpectedType(String.class); + jof.setDefaultObject("myString"); + jof.afterPropertiesSet(); + assertEquals("myString", jof.getObject()); + } + + public void testLookupWithDefaultObjectAndExpectedType() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + String s = ""; + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s)); + jof.setJndiName("myFoo"); + jof.setExpectedType(String.class); + jof.setDefaultObject("myString"); + jof.afterPropertiesSet(); + assertEquals("myString", jof.getObject()); + } + + public void testLookupWithDefaultObjectAndExpectedTypeNoMatch() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + String s = ""; + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s)); + jof.setJndiName("myFoo"); + jof.setExpectedType(String.class); + jof.setDefaultObject(Boolean.TRUE); + try { + jof.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testLookupWithProxyInterface() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + TestBean tb = new TestBean(); + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", tb)); + jof.setJndiName("foo"); + jof.setProxyInterface(ITestBean.class); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() instanceof ITestBean); + ITestBean proxy = (ITestBean) jof.getObject(); + assertEquals(0, tb.getAge()); + proxy.setAge(99); + assertEquals(99, tb.getAge()); + } + + public void testLookupWithProxyInterfaceAndDefaultObject() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + TestBean tb = new TestBean(); + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", tb)); + jof.setJndiName("myFoo"); + jof.setProxyInterface(ITestBean.class); + jof.setDefaultObject(Boolean.TRUE); + try { + jof.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testLookupWithProxyInterfaceAndLazyLookup() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + final TestBean tb = new TestBean(); + jof.setJndiTemplate(new JndiTemplate() { + public Object lookup(String name) { + if ("foo".equals(name)) { + tb.setName("tb"); + return tb; + } + return null; + } + }); + jof.setJndiName("foo"); + jof.setProxyInterface(ITestBean.class); + jof.setLookupOnStartup(false); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() instanceof ITestBean); + ITestBean proxy = (ITestBean) jof.getObject(); + assertNull(tb.getName()); + assertEquals(0, tb.getAge()); + proxy.setAge(99); + assertEquals("tb", tb.getName()); + assertEquals(99, tb.getAge()); + } + + public void testLookupWithProxyInterfaceWithNotCache() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + final TestBean tb = new TestBean(); + jof.setJndiTemplate(new JndiTemplate() { + public Object lookup(String name) { + if ("foo".equals(name)) { + tb.setName("tb"); + tb.setAge(tb.getAge() + 1); + return tb; + } + return null; + } + }); + jof.setJndiName("foo"); + jof.setProxyInterface(ITestBean.class); + jof.setCache(false); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() instanceof ITestBean); + ITestBean proxy = (ITestBean) jof.getObject(); + assertEquals("tb", tb.getName()); + assertEquals(1, tb.getAge()); + proxy.returnsThis(); + assertEquals(2, tb.getAge()); + proxy.haveBirthday(); + assertEquals(4, tb.getAge()); + } + + public void testLookupWithProxyInterfaceWithLazyLookupAndNotCache() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + final TestBean tb = new TestBean(); + jof.setJndiTemplate(new JndiTemplate() { + public Object lookup(String name) { + if ("foo".equals(name)) { + tb.setName("tb"); + tb.setAge(tb.getAge() + 1); + return tb; + } + return null; + } + }); + jof.setJndiName("foo"); + jof.setProxyInterface(ITestBean.class); + jof.setLookupOnStartup(false); + jof.setCache(false); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() instanceof ITestBean); + ITestBean proxy = (ITestBean) jof.getObject(); + assertNull(tb.getName()); + assertEquals(0, tb.getAge()); + proxy.returnsThis(); + assertEquals("tb", tb.getName()); + assertEquals(1, tb.getAge()); + proxy.returnsThis(); + assertEquals(2, tb.getAge()); + proxy.haveBirthday(); + assertEquals(4, tb.getAge()); + } + + public void testLazyLookupWithoutProxyInterface() throws NamingException { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + jof.setJndiName("foo"); + jof.setLookupOnStartup(false); + try { + jof.afterPropertiesSet(); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testNotCacheWithoutProxyInterface() throws NamingException { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + jof.setJndiName("foo"); + jof.setCache(false); + jof.setLookupOnStartup(false); + try { + jof.afterPropertiesSet(); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testLookupWithProxyInterfaceAndExpectedTypeAndMatch() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + TestBean tb = new TestBean(); + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", tb)); + jof.setJndiName("foo"); + jof.setExpectedType(TestBean.class); + jof.setProxyInterface(ITestBean.class); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() instanceof ITestBean); + ITestBean proxy = (ITestBean) jof.getObject(); + assertEquals(0, tb.getAge()); + proxy.setAge(99); + assertEquals(99, tb.getAge()); + } + + public void testLookupWithProxyInterfaceAndExpectedTypeAndNoMatch() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + TestBean tb = new TestBean(); + jof.setJndiTemplate(new ExpectedLookupTemplate("foo", tb)); + jof.setJndiName("foo"); + jof.setExpectedType(DerivedTestBean.class); + jof.setProxyInterface(ITestBean.class); + try { + jof.afterPropertiesSet(); + fail("Should have thrown NamingException"); + } + catch (NamingException ex) { + assertTrue(ex.getMessage().indexOf("org.springframework.beans.DerivedTestBean") != -1); + } + } + + public void testLookupWithExposeAccessContext() throws Exception { + JndiObjectFactoryBean jof = new JndiObjectFactoryBean(); + TestBean tb = new TestBean(); + MockControl ctxControl = MockControl.createControl(Context.class); + final Context mockCtx = (Context) ctxControl.getMock(); + mockCtx.lookup("foo"); + ctxControl.setReturnValue(tb); + mockCtx.close(); + ctxControl.setVoidCallable(2); + ctxControl.replay(); + jof.setJndiTemplate(new JndiTemplate() { + protected Context createInitialContext() { + return mockCtx; + } + }); + jof.setJndiName("foo"); + jof.setProxyInterface(ITestBean.class); + jof.setExposeAccessContext(true); + jof.afterPropertiesSet(); + assertTrue(jof.getObject() instanceof ITestBean); + ITestBean proxy = (ITestBean) jof.getObject(); + assertEquals(0, tb.getAge()); + proxy.setAge(99); + assertEquals(99, tb.getAge()); + proxy.equals(proxy); + proxy.hashCode(); + proxy.toString(); + ctxControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateEditorTests.java new file mode 100644 index 00000000000..eb4b239cc87 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateEditorTests.java @@ -0,0 +1,56 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jndi; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + */ +public class JndiTemplateEditorTests extends TestCase { + + public void testNullIsIllegalArgument() { + try { + new JndiTemplateEditor().setAsText(null); + fail("Null is illegal"); + } + catch (IllegalArgumentException ex) { + // OK + } + } + + public void testEmptyStringMeansNullEnvironment() { + JndiTemplateEditor je = new JndiTemplateEditor(); + je.setAsText(""); + JndiTemplate jt = (JndiTemplate) je.getValue(); + assertTrue(jt.getEnvironment() == null); + } + + public void testCustomEnvironment() { + JndiTemplateEditor je = new JndiTemplateEditor(); + // These properties are meaningless for JNDI, but we don't worry about that: + // the underlying JNDI implementation will throw exceptions when the user tries + // to look anything up + je.setAsText("jndiInitialSomethingOrOther=org.springframework.myjndi.CompleteRubbish\nfoo=bar"); + JndiTemplate jt = (JndiTemplate) je.getValue(); + assertTrue(jt.getEnvironment().size() == 2); + assertTrue(jt.getEnvironment().getProperty("jndiInitialSomethingOrOther").equals("org.springframework.myjndi.CompleteRubbish")); + assertTrue(jt.getEnvironment().getProperty("foo").equals("bar")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateTests.java new file mode 100644 index 00000000000..6b8fda62af5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jndi/JndiTemplateTests.java @@ -0,0 +1,196 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jndi; + +import javax.naming.Context; +import javax.naming.NameNotFoundException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @since 08.07.2003 + */ +public class JndiTemplateTests extends TestCase { + + public void testLookupSucceeds() throws Exception { + Object o = new Object(); + String name = "foo"; + MockControl mc = MockControl.createControl(Context.class); + final Context mock = (Context) mc.getMock(); + mock.lookup(name); + mc.setReturnValue(o); + mock.close(); + mc.setVoidCallable(1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + protected Context createInitialContext() { + return mock; + } + }; + + Object o2 = jt.lookup(name); + assertEquals(o, o2); + mc.verify(); + } + + public void testLookupFails() throws Exception { + NameNotFoundException ne = new NameNotFoundException(); + String name = "foo"; + MockControl mc = MockControl.createControl(Context.class); + final Context mock = (Context) mc.getMock(); + mock.lookup(name); + mc.setThrowable(ne); + mock.close(); + mc.setVoidCallable(1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + protected Context createInitialContext() { + return mock; + } + }; + + try { + jt.lookup(name); + fail("Should have thrown NamingException"); + } + catch (NameNotFoundException ex) { + // Ok + } + mc.verify(); + } + + public void testLookupReturnsNull() throws Exception { + String name = "foo"; + MockControl mc = MockControl.createControl(Context.class); + final Context mock = (Context) mc.getMock(); + mock.lookup(name); + mc.setReturnValue(null); + mock.close(); + mc.setVoidCallable(1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + protected Context createInitialContext() { + return mock; + } + }; + + try { + jt.lookup(name); + fail("Should have thrown NamingException"); + } + catch (NameNotFoundException ex) { + // Ok + } + mc.verify(); + } + + public void testLookupFailsWithTypeMismatch() throws Exception { + Object o = new Object(); + String name = "foo"; + MockControl mc = MockControl.createControl(Context.class); + final Context mock = (Context) mc.getMock(); + mock.lookup(name); + mc.setReturnValue(o); + mock.close(); + mc.setVoidCallable(1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + protected Context createInitialContext() { + return mock; + } + }; + + try { + jt.lookup(name, String.class); + fail("Should have thrown TypeMismatchNamingException"); + } + catch (TypeMismatchNamingException ex) { + // Ok + } + mc.verify(); + } + + public void testBind() throws Exception { + Object o = new Object(); + String name = "foo"; + MockControl mc = MockControl.createControl(Context.class); + final Context mock = (Context) mc.getMock(); + mock.bind(name, o); + mc.setVoidCallable(1); + mock.close(); + mc.setVoidCallable(1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + protected Context createInitialContext() { + return mock; + } + }; + + jt.bind(name, o); + mc.verify(); + } + + public void testRebind() throws Exception { + Object o = new Object(); + String name = "foo"; + MockControl mc = MockControl.createControl(Context.class); + final Context mock = (Context) mc.getMock(); + mock.rebind(name, o); + mc.setVoidCallable(1); + mock.close(); + mc.setVoidCallable(1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + protected Context createInitialContext() { + return mock; + } + }; + + jt.rebind(name, o); + mc.verify(); + } + + public void testUnbind() throws Exception { + String name = "something"; + MockControl mc = MockControl.createControl(Context.class); + final Context mock = (Context) mc.getMock(); + mock.unbind(name); + mc.setVoidCallable(1); + mock.close(); + mc.setVoidCallable(1); + mc.replay(); + + JndiTemplate jt = new JndiTemplate() { + protected Context createInitialContext() { + return mock; + } + }; + + jt.unbind(name); + mc.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/jndi/SimpleNamingContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/jndi/SimpleNamingContextTests.java new file mode 100644 index 00000000000..d2be1268f97 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/jndi/SimpleNamingContextTests.java @@ -0,0 +1,210 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jndi; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.mock.jndi.SimpleNamingContext; +import org.springframework.mock.jndi.SimpleNamingContextBuilder; + +/** + * @author Juergen Hoeller + */ +public class SimpleNamingContextTests extends TestCase { + + public void testNamingContextBuilder() throws NamingException { + SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); + InitialContextFactory factory = builder.createInitialContextFactory(null); + + DataSource ds = new DriverManagerDataSource(); + builder.bind("java:comp/env/jdbc/myds", ds); + Object obj = new Object(); + builder.bind("myobject", obj); + + Context context1 = factory.getInitialContext(null); + assertTrue("Correct DataSource registered", context1.lookup("java:comp/env/jdbc/myds") == ds); + assertTrue("Correct Object registered", context1.lookup("myobject") == obj); + + Hashtable env2 = new Hashtable(); + env2.put("key1", "value1"); + Context context2 = factory.getInitialContext(env2); + assertTrue("Correct DataSource registered", context2.lookup("java:comp/env/jdbc/myds") == ds); + assertTrue("Correct Object registered", context2.lookup("myobject") == obj); + assertTrue("Correct environment", context2.getEnvironment() != env2); + assertTrue("Correct key1", "value1".equals(context2.getEnvironment().get("key1"))); + + Integer i = new Integer(0); + context1.rebind("myinteger", i); + String s = ""; + context2.bind("mystring", s); + + Context context3 = (Context) context2.lookup(""); + context3.rename("java:comp/env/jdbc/myds", "jdbc/myds"); + context3.unbind("myobject"); + + assertTrue("Correct environment", context3.getEnvironment() != context2.getEnvironment()); + context3.addToEnvironment("key2", "value2"); + assertTrue("key2 added", "value2".equals(context3.getEnvironment().get("key2"))); + context3.removeFromEnvironment("key1"); + assertTrue("key1 removed", context3.getEnvironment().get("key1") == null); + + assertTrue("Correct DataSource registered", context1.lookup("jdbc/myds") == ds); + try { + context1.lookup("myobject"); + fail("Should have thrown NameNotFoundException"); + } + catch (NameNotFoundException ex) { + // expected + } + assertTrue("Correct Integer registered", context1.lookup("myinteger") == i); + assertTrue("Correct String registered", context1.lookup("mystring") == s); + + assertTrue("Correct DataSource registered", context2.lookup("jdbc/myds") == ds); + try { + context2.lookup("myobject"); + fail("Should have thrown NameNotFoundException"); + } + catch (NameNotFoundException ex) { + // expected + } + assertTrue("Correct Integer registered", context2.lookup("myinteger") == i); + assertTrue("Correct String registered", context2.lookup("mystring") == s); + + assertTrue("Correct DataSource registered", context3.lookup("jdbc/myds") == ds); + try { + context3.lookup("myobject"); + fail("Should have thrown NameNotFoundException"); + } + catch (NameNotFoundException ex) { + // expected + } + assertTrue("Correct Integer registered", context3.lookup("myinteger") == i); + assertTrue("Correct String registered", context3.lookup("mystring") == s); + + Map bindingMap = new HashMap(); + NamingEnumeration bindingEnum = context3.listBindings(""); + while (bindingEnum.hasMoreElements()) { + Binding binding = (Binding) bindingEnum.nextElement(); + bindingMap.put(binding.getName(), binding); + } + assertTrue("Correct jdbc subcontext", ((Binding) bindingMap.get("jdbc")).getObject() instanceof Context); + assertTrue("Correct jdbc subcontext", SimpleNamingContext.class.getName().equals(((Binding) bindingMap.get("jdbc")).getClassName())); + + Context jdbcContext = (Context) context3.lookup("jdbc"); + jdbcContext.bind("mydsX", ds); + Map subBindingMap = new HashMap(); + NamingEnumeration subBindingEnum = jdbcContext.listBindings(""); + while (subBindingEnum.hasMoreElements()) { + Binding binding = (Binding) subBindingEnum.nextElement(); + subBindingMap.put(binding.getName(), binding); + } + + assertTrue("Correct DataSource registered", ds.equals(((Binding) subBindingMap.get("myds")).getObject())); + assertTrue("Correct DataSource registered", DriverManagerDataSource.class.getName().equals(((Binding) subBindingMap.get("myds")).getClassName())); + assertTrue("Correct DataSource registered", ds.equals(((Binding) subBindingMap.get("mydsX")).getObject())); + assertTrue("Correct DataSource registered", DriverManagerDataSource.class.getName().equals(((Binding) subBindingMap.get("mydsX")).getClassName())); + assertTrue("Correct Integer registered", i.equals(((Binding) bindingMap.get("myinteger")).getObject())); + assertTrue("Correct Integer registered", Integer.class.getName().equals(((Binding) bindingMap.get("myinteger")).getClassName())); + assertTrue("Correct String registered", s.equals(((Binding) bindingMap.get("mystring")).getObject())); + assertTrue("Correct String registered", String.class.getName().equals(((Binding) bindingMap.get("mystring")).getClassName())); + + context1.createSubcontext("jdbc").bind("sub/subds", ds); + + Map pairMap = new HashMap(); + NamingEnumeration pairEnum = context2.list("jdbc"); + while (pairEnum.hasMore()) { + NameClassPair pair = (NameClassPair) pairEnum.next(); + pairMap.put(pair.getName(), pair.getClassName()); + } + assertTrue("Correct sub subcontext", SimpleNamingContext.class.getName().equals(pairMap.get("sub"))); + + Context subContext = (Context) context2.lookup("jdbc/sub"); + Map subPairMap = new HashMap(); + NamingEnumeration subPairEnum = subContext.list(""); + while (subPairEnum.hasMoreElements()) { + NameClassPair pair = (NameClassPair) subPairEnum.next(); + subPairMap.put(pair.getName(), pair.getClassName()); + } + + assertTrue("Correct DataSource registered", DriverManagerDataSource.class.getName().equals(subPairMap.get("subds"))); + assertTrue("Correct DataSource registered", DriverManagerDataSource.class.getName().equals(pairMap.get("myds"))); + assertTrue("Correct DataSource registered", DriverManagerDataSource.class.getName().equals(pairMap.get("mydsX"))); + + pairMap.clear(); + pairEnum = context1.list("jdbc/"); + while (pairEnum.hasMore()) { + NameClassPair pair = (NameClassPair) pairEnum.next(); + pairMap.put(pair.getName(), pair.getClassName()); + } + assertTrue("Correct DataSource registered", DriverManagerDataSource.class.getName().equals(pairMap.get("myds"))); + assertTrue("Correct DataSource registered", DriverManagerDataSource.class.getName().equals(pairMap.get("mydsX"))); + } + + /** + * Demonstrates how emptyActivatedContextBuilder() method can be + * used repeatedly, and how it affects creating a new InitialContext() + */ + public void testCreateInitialContext() throws Exception { + SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + String name = "foo"; + Object o = new Object(); + builder.bind(name, o); + // Check it affects JNDI + Context ctx = new InitialContext(); + assertTrue(ctx.lookup(name) == o); + // Check it returns mutable contexts + ctx.unbind(name); + try { + ctx = new InitialContext(); + ctx.lookup(name); + fail("Should have thrown NamingException"); + } + catch (NamingException ex) { + // expected + } + + // Check the same call will work again, but the context is empty + builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + try { + ctx = new InitialContext(); + ctx.lookup(name); + fail("Should have thrown NamingException"); + } + catch (NamingException ex) { + // expected + } + Object o2 = new Object(); + builder.bind(name, o2); + assertEquals(ctx.lookup(name), o2); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mail/SimpleMailMessageTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mail/SimpleMailMessageTests.java new file mode 100644 index 00000000000..30b6d02710a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mail/SimpleMailMessageTests.java @@ -0,0 +1,170 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mail; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; + +/** + * @author Dmitriy Kopylenko + * @author Juergen Hoeller + * @author Rick Evans + * @since 10.09.2003 + */ +public final class SimpleMailMessageTests extends TestCase { + + public void testSimpleMessageCopyCtor() { + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom("me@mail.org"); + message.setTo("you@mail.org"); + + SimpleMailMessage messageCopy = new SimpleMailMessage(message); + assertEquals("me@mail.org", messageCopy.getFrom()); + assertEquals("you@mail.org", messageCopy.getTo()[0]); + + message.setReplyTo("reply@mail.org"); + message.setCc(new String[]{"he@mail.org", "she@mail.org"}); + message.setBcc(new String[]{"us@mail.org", "them@mail.org"}); + Date sentDate = new Date(); + message.setSentDate(sentDate); + message.setSubject("my subject"); + message.setText("my text"); + + assertEquals("me@mail.org", message.getFrom()); + assertEquals("reply@mail.org", message.getReplyTo()); + assertEquals("you@mail.org", message.getTo()[0]); + List ccs = Arrays.asList(message.getCc()); + assertTrue(ccs.contains("he@mail.org")); + assertTrue(ccs.contains("she@mail.org")); + List bccs = Arrays.asList(message.getBcc()); + assertTrue(bccs.contains("us@mail.org")); + assertTrue(bccs.contains("them@mail.org")); + assertEquals(sentDate, message.getSentDate()); + assertEquals("my subject", message.getSubject()); + assertEquals("my text", message.getText()); + + messageCopy = new SimpleMailMessage(message); + assertEquals("me@mail.org", messageCopy.getFrom()); + assertEquals("reply@mail.org", messageCopy.getReplyTo()); + assertEquals("you@mail.org", messageCopy.getTo()[0]); + ccs = Arrays.asList(messageCopy.getCc()); + assertTrue(ccs.contains("he@mail.org")); + assertTrue(ccs.contains("she@mail.org")); + bccs = Arrays.asList(message.getBcc()); + assertTrue(bccs.contains("us@mail.org")); + assertTrue(bccs.contains("them@mail.org")); + assertEquals(sentDate, messageCopy.getSentDate()); + assertEquals("my subject", messageCopy.getSubject()); + assertEquals("my text", messageCopy.getText()); + } + + public void testDeepCopyOfStringArrayTypedFieldsOnCopyCtor() throws Exception { + + SimpleMailMessage original = new SimpleMailMessage(); + original.setTo(new String[]{"fiona@mail.org", "apple@mail.org"}); + original.setCc(new String[]{"he@mail.org", "she@mail.org"}); + original.setBcc(new String[]{"us@mail.org", "them@mail.org"}); + + SimpleMailMessage copy = new SimpleMailMessage(original); + + original.getTo()[0] = "mmm@mmm.org"; + original.getCc()[0] = "mmm@mmm.org"; + original.getBcc()[0] = "mmm@mmm.org"; + + assertEquals("fiona@mail.org", copy.getTo()[0]); + assertEquals("he@mail.org", copy.getCc()[0]); + assertEquals("us@mail.org", copy.getBcc()[0]); + } + + /** + * Tests that two equal SimpleMailMessages have equal hash codes. + */ + public final void testHashCode() { + SimpleMailMessage message1 = new SimpleMailMessage(); + message1.setFrom("from@somewhere"); + message1.setReplyTo("replyTo@somewhere"); + message1.setTo("to@somewhere"); + message1.setCc("cc@somewhere"); + message1.setBcc("bcc@somewhere"); + message1.setSentDate(new Date()); + message1.setSubject("subject"); + message1.setText("text"); + + // Copy the message + SimpleMailMessage message2 = new SimpleMailMessage(message1); + + assertEquals(message1, message2); + assertEquals(message1.hashCode(), message2.hashCode()); + } + + public final void testEqualsObject() { + SimpleMailMessage message1; + SimpleMailMessage message2; + + // Same object is equal + message1 = new SimpleMailMessage(); + message2 = message1; + assertTrue(message1.equals(message2)); + + // Null object is not equal + message1 = new SimpleMailMessage(); + message2 = null; + assertTrue(!(message1.equals(message2))); + + // Different class is not equal + assertTrue(!(message1.equals(new Object()))); + + // Equal values are equal + message1 = new SimpleMailMessage(); + message2 = new SimpleMailMessage(); + assertTrue(message1.equals(message2)); + + message1 = new SimpleMailMessage(); + message1.setFrom("from@somewhere"); + message1.setReplyTo("replyTo@somewhere"); + message1.setTo("to@somewhere"); + message1.setCc("cc@somewhere"); + message1.setBcc("bcc@somewhere"); + message1.setSentDate(new Date()); + message1.setSubject("subject"); + message1.setText("text"); + message2 = new SimpleMailMessage(message1); + assertTrue(message1.equals(message2)); + } + + public void testCopyCtorChokesOnNullOriginalMessage() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new SimpleMailMessage(null); + } + }.runTest(); + } + + public void testCopyToChokesOnNullTargetMessage() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new SimpleMailMessage().copyTo(null); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMapTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMapTests.java new file mode 100644 index 00000000000..4c5e108bea1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMapTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mail.javamail; + +import java.io.File; + +import junit.framework.TestCase; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class ConfigurableMimeFileTypeMapTests extends TestCase { + + public void testAgainstDefaultConfiguration() throws Exception { + ConfigurableMimeFileTypeMap ftm = new ConfigurableMimeFileTypeMap(); + ftm.afterPropertiesSet(); + + assertEquals("Invalid content type for HTM", "text/html", ftm.getContentType("foobar.HTM")); + assertEquals("Invalid content type for html", "text/html", ftm.getContentType("foobar.html")); + assertEquals("Invalid content type for c++", "text/plain", ftm.getContentType("foobar.c++")); + assertEquals("Invalid content type for svf", "image/vnd.svf", ftm.getContentType("foobar.svf")); + assertEquals("Invalid content type for dsf", "image/x-mgx-dsf", ftm.getContentType("foobar.dsf")); + assertEquals("Invalid default content type", "application/octet-stream", ftm.getContentType("foobar.foo")); + } + + public void testAgainstDefaultConfigurationWithFilePath() throws Exception { + ConfigurableMimeFileTypeMap ftm = new ConfigurableMimeFileTypeMap(); + assertEquals("Invalid content type for HTM", "text/html", ftm.getContentType(new File("/tmp/foobar.HTM"))); + } + + public void testWithAdditionalMappings() throws Exception { + ConfigurableMimeFileTypeMap ftm = new ConfigurableMimeFileTypeMap(); + ftm.setMappings(new String[] {"foo/bar HTM foo", "foo/cpp c++"}); + ftm.afterPropertiesSet(); + + assertEquals("Invalid content type for HTM - override didn't work", "foo/bar", ftm.getContentType("foobar.HTM")); + assertEquals("Invalid content type for c++ - override didn't work", "foo/cpp", ftm.getContentType("foobar.c++")); + assertEquals("Invalid content type for foo - new mapping didn't work", "foo/bar", ftm.getContentType("bar.foo")); + } + + public void testWithCustomMappingLocation() throws Exception { + Resource resource = new ClassPathResource("test.mime.types", getClass()); + + ConfigurableMimeFileTypeMap ftm = new ConfigurableMimeFileTypeMap(); + ftm.setMappingLocation(resource); + ftm.afterPropertiesSet(); + + assertEquals("Invalid content type for foo", "text/foo", ftm.getContentType("foobar.foo")); + assertEquals("Invalid content type for bar", "text/bar", ftm.getContentType("foobar.bar")); + assertEquals("Invalid content type for fimg", "image/foo", ftm.getContentType("foobar.fimg")); + assertEquals("Invalid content type for bimg", "image/bar", ftm.getContentType("foobar.bimg")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/InternetAddressEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/InternetAddressEditorTests.java new file mode 100644 index 00000000000..3233099baca --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/InternetAddressEditorTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mail.javamail; + +import junit.framework.TestCase; + +/** + * @author Brian Hanafee + * @since 09.07.2005 + */ +public class InternetAddressEditorTests extends TestCase { + + private static final String EMPTY = ""; + private static final String SIMPLE = "nobody@nowhere.com"; + private static final String BAD = "("; + + private InternetAddressEditor editor; + + protected void setUp() { + editor = new InternetAddressEditor(); + } + + public void testUninitialized() { + assertEquals("Uninitialized editor did not return empty value string", EMPTY, editor.getAsText()); + } + + public void testSetNull() { + editor.setAsText(null); + assertEquals("Setting null did not result in empty value string", EMPTY, editor.getAsText()); + } + + public void testSetEmpty() { + editor.setAsText(EMPTY); + assertEquals("Setting empty string did not result in empty value string", EMPTY, editor.getAsText()); + } + + public void testAllWhitespace() { + editor.setAsText(" "); + assertEquals("All whitespace was not recognized", EMPTY, editor.getAsText()); + } + + public void testSimpleGoodAddess() { + editor.setAsText(SIMPLE); + assertEquals("Simple email address failed", SIMPLE, editor.getAsText()); + } + + public void testExcessWhitespace() { + editor.setAsText(" " + SIMPLE + " "); + assertEquals("Whitespace was not stripped", SIMPLE, editor.getAsText()); + } + + public void testSimpleBadAddress() { + try { + editor.setAsText(BAD); + fail("Should have failed on \"" + BAD + "\", instead got " + editor.getAsText()); + } + catch (IllegalArgumentException e) { + // Passed the test + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/JavaMailSenderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/JavaMailSenderTests.java new file mode 100644 index 00000000000..befbe54e56c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/JavaMailSenderTests.java @@ -0,0 +1,536 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mail.javamail; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +import javax.activation.FileTypeMap; +import javax.mail.Address; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.NoSuchProviderException; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.URLName; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; + +import junit.framework.TestCase; + +import org.springframework.mail.MailParseException; +import org.springframework.mail.MailSendException; +import org.springframework.mail.SimpleMailMessage; + +/** + * @author Juergen Hoeller + * @since 09.10.2004 + */ +public class JavaMailSenderTests extends TestCase { + + public void testJavaMailSenderWithSimpleMessage() throws MessagingException, IOException { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setPort(30); + sender.setUsername("username"); + sender.setPassword("password"); + + SimpleMailMessage simpleMessage = new SimpleMailMessage(); + simpleMessage.setFrom("me@mail.org"); + simpleMessage.setReplyTo("reply@mail.org"); + simpleMessage.setTo("you@mail.org"); + simpleMessage.setCc(new String[] {"he@mail.org", "she@mail.org"}); + simpleMessage.setBcc(new String[] {"us@mail.org", "them@mail.org"}); + Date sentDate = new Date(2004, 1, 1); + simpleMessage.setSentDate(sentDate); + simpleMessage.setSubject("my subject"); + simpleMessage.setText("my text"); + sender.send(simpleMessage); + + assertEquals("host", sender.transport.getConnectedHost()); + assertEquals(30, sender.transport.getConnectedPort()); + assertEquals("username", sender.transport.getConnectedUsername()); + assertEquals("password", sender.transport.getConnectedPassword()); + assertTrue(sender.transport.isCloseCalled()); + + assertEquals(1, sender.transport.getSentMessages().size()); + MimeMessage sentMessage = sender.transport.getSentMessage(0); + List froms = Arrays.asList(sentMessage.getFrom()); + assertEquals(1, froms.size()); + assertEquals("me@mail.org", ((InternetAddress) froms.get(0)).getAddress()); + List replyTos = Arrays.asList(sentMessage.getReplyTo()); + assertEquals("reply@mail.org", ((InternetAddress) replyTos.get(0)).getAddress()); + List tos = Arrays.asList(sentMessage.getRecipients(Message.RecipientType.TO)); + assertEquals(1, tos.size()); + assertEquals("you@mail.org", ((InternetAddress) tos.get(0)).getAddress()); + List ccs = Arrays.asList(sentMessage.getRecipients(Message.RecipientType.CC)); + assertEquals(2, ccs.size()); + assertEquals("he@mail.org", ((InternetAddress) ccs.get(0)).getAddress()); + assertEquals("she@mail.org", ((InternetAddress) ccs.get(1)).getAddress()); + List bccs = Arrays.asList(sentMessage.getRecipients(Message.RecipientType.BCC)); + assertEquals(2, bccs.size()); + assertEquals("us@mail.org", ((InternetAddress) bccs.get(0)).getAddress()); + assertEquals("them@mail.org", ((InternetAddress) bccs.get(1)).getAddress()); + assertEquals(sentDate.getTime(), sentMessage.getSentDate().getTime()); + assertEquals("my subject", sentMessage.getSubject()); + assertEquals("my text", sentMessage.getContent()); + } + + public void testJavaMailSenderWithSimpleMessages() throws MessagingException, IOException { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + SimpleMailMessage simpleMessage1 = new SimpleMailMessage(); + simpleMessage1.setTo("he@mail.org"); + SimpleMailMessage simpleMessage2 = new SimpleMailMessage(); + simpleMessage2.setTo("she@mail.org"); + sender.send(new SimpleMailMessage[] {simpleMessage1, simpleMessage2}); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + + assertEquals(2, sender.transport.getSentMessages().size()); + MimeMessage sentMessage1 = sender.transport.getSentMessage(0); + List tos1 = Arrays.asList(sentMessage1.getRecipients(Message.RecipientType.TO)); + assertEquals(1, tos1.size()); + assertEquals("he@mail.org", ((InternetAddress) tos1.get(0)).getAddress()); + MimeMessage sentMessage2 = sender.transport.getSentMessage(1); + List tos2 = Arrays.asList(sentMessage2.getRecipients(Message.RecipientType.TO)); + assertEquals(1, tos2.size()); + assertEquals("she@mail.org", ((InternetAddress) tos2.get(0)).getAddress()); + } + + public void testJavaMailSenderWithMimeMessage() throws MessagingException { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + MimeMessage mimeMessage = sender.createMimeMessage(); + mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("you@mail.org")); + sender.send(mimeMessage); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(mimeMessage, sender.transport.getSentMessage(0)); + } + + public void testJavaMailSenderWithMimeMessages() throws MessagingException { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + MimeMessage mimeMessage1 = sender.createMimeMessage(); + mimeMessage1.setRecipient(Message.RecipientType.TO, new InternetAddress("he@mail.org")); + MimeMessage mimeMessage2 = sender.createMimeMessage(); + mimeMessage2.setRecipient(Message.RecipientType.TO, new InternetAddress("she@mail.org")); + sender.send(new MimeMessage[] {mimeMessage1, mimeMessage2}); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(2, sender.transport.getSentMessages().size()); + assertEquals(mimeMessage1, sender.transport.getSentMessage(0)); + assertEquals(mimeMessage2, sender.transport.getSentMessage(1)); + } + + public void testJavaMailSenderWithMimeMessagePreparator() { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + final List messages = new ArrayList(); + + MimeMessagePreparator preparator = new MimeMessagePreparator() { + public void prepare(MimeMessage mimeMessage) throws MessagingException { + mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("you@mail.org")); + messages.add(mimeMessage); + } + }; + sender.send(preparator); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(messages.get(0), sender.transport.getSentMessage(0)); + } + + public void testJavaMailSenderWithMimeMessagePreparators() { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + final List messages = new ArrayList(); + + MimeMessagePreparator preparator1 = new MimeMessagePreparator() { + public void prepare(MimeMessage mimeMessage) throws MessagingException { + mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("he@mail.org")); + messages.add(mimeMessage); + } + }; + MimeMessagePreparator preparator2 = new MimeMessagePreparator() { + public void prepare(MimeMessage mimeMessage) throws MessagingException { + mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("she@mail.org")); + messages.add(mimeMessage); + } + }; + sender.send(new MimeMessagePreparator[] {preparator1, preparator2}); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(2, sender.transport.getSentMessages().size()); + assertEquals(messages.get(0), sender.transport.getSentMessage(0)); + assertEquals(messages.get(1), sender.transport.getSentMessage(1)); + } + + public void testJavaMailSenderWithMimeMessageHelper() throws MessagingException { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + MimeMessageHelper message = new MimeMessageHelper(sender.createMimeMessage()); + assertNull(message.getEncoding()); + assertTrue(message.getFileTypeMap() instanceof ConfigurableMimeFileTypeMap); + + message.setTo("you@mail.org"); + sender.send(message.getMimeMessage()); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(message.getMimeMessage(), sender.transport.getSentMessage(0)); + } + + public void testJavaMailSenderWithMimeMessageHelperAndSpecificEncoding() throws MessagingException { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + MimeMessageHelper message = new MimeMessageHelper(sender.createMimeMessage(), "UTF-8"); + assertEquals("UTF-8", message.getEncoding()); + FileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap(); + message.setFileTypeMap(fileTypeMap); + assertEquals(fileTypeMap, message.getFileTypeMap()); + + message.setTo("you@mail.org"); + sender.send(message.getMimeMessage()); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(message.getMimeMessage(), sender.transport.getSentMessage(0)); + } + + public void testJavaMailSenderWithMimeMessageHelperAndDefaultEncoding() throws MessagingException { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + sender.setDefaultEncoding("UTF-8"); + + FileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap(); + sender.setDefaultFileTypeMap(fileTypeMap); + MimeMessageHelper message = new MimeMessageHelper(sender.createMimeMessage()); + assertEquals("UTF-8", message.getEncoding()); + assertEquals(fileTypeMap, message.getFileTypeMap()); + + message.setTo("you@mail.org"); + sender.send(message.getMimeMessage()); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(message.getMimeMessage(), sender.transport.getSentMessage(0)); + } + + public void testJavaMailSenderWithParseExceptionOnSimpleMessage() { + MockJavaMailSender sender = new MockJavaMailSender(); + SimpleMailMessage simpleMessage = new SimpleMailMessage(); + simpleMessage.setFrom(""); + try { + sender.send(simpleMessage); + } + catch (MailParseException ex) { + // expected + assertTrue(ex.getCause() instanceof AddressException); + } + } + + public void testJavaMailSenderWithParseExceptionOnMimeMessagePreparator() { + MockJavaMailSender sender = new MockJavaMailSender(); + MimeMessagePreparator preparator = new MimeMessagePreparator() { + public void prepare(MimeMessage mimeMessage) throws MessagingException { + mimeMessage.setFrom(new InternetAddress("")); + } + }; + try { + sender.send(preparator); + } + catch (MailParseException ex) { + // expected + assertTrue(ex.getCause() instanceof AddressException); + } + } + + public void testJavaMailSenderWithCustomSession() throws MessagingException { + final Session session = Session.getInstance(new Properties()); + MockJavaMailSender sender = new MockJavaMailSender() { + protected Transport getTransport(Session sess) throws NoSuchProviderException { + assertEquals(session, sess); + return super.getTransport(sess); + } + }; + sender.setSession(session); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + MimeMessage mimeMessage = sender.createMimeMessage(); + mimeMessage.setSubject("custom"); + mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("you@mail.org")); + mimeMessage.setSentDate(new Date(2005, 3, 1)); + sender.send(mimeMessage); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(mimeMessage, sender.transport.getSentMessage(0)); + } + + public void testJavaMailProperties() throws MessagingException { + Properties props = new Properties(); + props.setProperty("bogusKey", "bogusValue"); + MockJavaMailSender sender = new MockJavaMailSender() { + protected Transport getTransport(Session sess) throws NoSuchProviderException { + assertEquals("bogusValue", sess.getProperty("bogusKey")); + return super.getTransport(sess); + } + }; + sender.setJavaMailProperties(props); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + MimeMessage mimeMessage = sender.createMimeMessage(); + mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("you@mail.org")); + sender.send(mimeMessage); + + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(mimeMessage, sender.transport.getSentMessage(0)); + } + + public void testFailedMailServerConnect() throws Exception { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost(null); + sender.setUsername("username"); + sender.setPassword("password"); + SimpleMailMessage simpleMessage1 = new SimpleMailMessage(); + try { + sender.send(simpleMessage1); + fail("Should have thrown MailSendException"); + } + catch (MailSendException ex) { + // expected + assertTrue(ex.getFailedMessages() != null); + assertTrue(ex.getFailedMessages().isEmpty()); + } + } + + public void testFailedSimpleMessage() throws Exception { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + SimpleMailMessage simpleMessage1 = new SimpleMailMessage(); + simpleMessage1.setTo("he@mail.org"); + simpleMessage1.setSubject("fail"); + SimpleMailMessage simpleMessage2 = new SimpleMailMessage(); + simpleMessage2.setTo("she@mail.org"); + + try { + sender.send(new SimpleMailMessage[] {simpleMessage1, simpleMessage2}); + } + catch (MailSendException ex) { + System.out.println(ex); + ex.printStackTrace(); + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(new InternetAddress("she@mail.org"), sender.transport.getSentMessage(0).getAllRecipients()[0]); + assertEquals(1, ex.getFailedMessages().size()); + assertEquals(simpleMessage1, ex.getFailedMessages().keySet().iterator().next()); + Object subEx = ex.getFailedMessages().values().iterator().next(); + assertTrue(subEx instanceof MessagingException); + assertEquals("failed", ((MessagingException) subEx).getMessage()); + } + } + + public void testFailedMimeMessage() throws Exception { + MockJavaMailSender sender = new MockJavaMailSender(); + sender.setHost("host"); + sender.setUsername("username"); + sender.setPassword("password"); + + MimeMessage mimeMessage1 = sender.createMimeMessage(); + mimeMessage1.setRecipient(Message.RecipientType.TO, new InternetAddress("he@mail.org")); + mimeMessage1.setSubject("fail"); + MimeMessage mimeMessage2 = sender.createMimeMessage(); + mimeMessage2.setRecipient(Message.RecipientType.TO, new InternetAddress("she@mail.org")); + + try { + sender.send(new MimeMessage[] {mimeMessage1, mimeMessage2}); + } + catch (MailSendException ex) { + ex.printStackTrace(); + assertEquals(sender.transport.getConnectedHost(), "host"); + assertEquals(sender.transport.getConnectedUsername(), "username"); + assertEquals(sender.transport.getConnectedPassword(), "password"); + assertTrue(sender.transport.isCloseCalled()); + assertEquals(1, sender.transport.getSentMessages().size()); + assertEquals(mimeMessage2, sender.transport.getSentMessage(0)); + assertEquals(1, ex.getFailedMessages().size()); + assertEquals(mimeMessage1, ex.getFailedMessages().keySet().iterator().next()); + Object subEx = ex.getFailedMessages().values().iterator().next(); + assertTrue(subEx instanceof MessagingException); + assertEquals("failed", ((MessagingException) subEx).getMessage()); + } + } + + + private static class MockJavaMailSender extends JavaMailSenderImpl { + + private MockTransport transport; + + protected Transport getTransport(Session session) throws NoSuchProviderException { + this.transport = new MockTransport(session, null); + return transport; + } + } + + + private static class MockTransport extends Transport { + + private String connectedHost = null; + private int connectedPort = -2; + private String connectedUsername = null; + private String connectedPassword = null; + private boolean closeCalled = false; + private List sentMessages = new ArrayList(); + + public MockTransport(Session session, URLName urlName) { + super(session, urlName); + } + + public String getConnectedHost() { + return connectedHost; + } + + public int getConnectedPort() { + return connectedPort; + } + + public String getConnectedUsername() { + return connectedUsername; + } + + public String getConnectedPassword() { + return connectedPassword; + } + + public boolean isCloseCalled() { + return closeCalled; + } + + public List getSentMessages() { + return sentMessages; + } + + public MimeMessage getSentMessage(int index) { + return (MimeMessage) this.sentMessages.get(index); + } + + public void connect(String host, int port, String username, String password) throws MessagingException { + if (host == null) { + throw new MessagingException("no host"); + } + this.connectedHost = host; + this.connectedPort = port; + this.connectedUsername = username; + this.connectedPassword = password; + } + + public synchronized void close() throws MessagingException { + this.closeCalled = true; + } + + public void sendMessage(Message message, Address[] addresses) throws MessagingException { + if ("fail".equals(message.getSubject())) { + throw new MessagingException("failed"); + } + List addr1 = Arrays.asList(message.getAllRecipients()); + List addr2 = Arrays.asList(addresses); + if (!addr1.equals(addr2)) { + throw new MessagingException("addresses not correct"); + } + if (message.getSentDate() == null) { + throw new MessagingException("No sentDate specified"); + } + if (message.getSubject() != null && message.getSubject().indexOf("custom") != -1) { + assertEquals(new Date(2005, 3, 1), message.getSentDate()); + } + this.sentMessages.add(message); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/test.mime.types b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/test.mime.types new file mode 100644 index 00000000000..f54f4d7f211 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mail/javamail/test.mime.types @@ -0,0 +1,4 @@ +text/foo foo +text/bar bar +image/foo fimg +image/bar bimg \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mock/easymock/AbstractScalarMockTemplate.java b/org.springframework.testsuite/src/test/java/org/springframework/mock/easymock/AbstractScalarMockTemplate.java new file mode 100644 index 00000000000..aaba654bb56 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mock/easymock/AbstractScalarMockTemplate.java @@ -0,0 +1,128 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.easymock; + +import org.easymock.MockControl; + +/** + * Makes those tests that require a single (scalar) EasyMock mock + * control and object easier to author. + * + * @author Rick Evans + * @since 2.0 + */ +public abstract class AbstractScalarMockTemplate { + + private static final int NORMAL = 0; + private static final int NICE = 1; + private static final int STRICT = 2; + + + private Class mockInterface; + + private int mode = NORMAL; + + + /** + * Creates a new instance of the {@link AbstractScalarMockTemplate} class. + */ + protected AbstractScalarMockTemplate() { + } + + /** + * Creates a new instance of the {@link AbstractScalarMockTemplate} class. + * @param mockInterface the interface that is to be mocked + */ + protected AbstractScalarMockTemplate(Class mockInterface) { + this.mockInterface = mockInterface; + } + + /** + * Creates a new instance of the {@link AbstractScalarMockTemplate} class. + * @param mockInterface the interface that is to be mocked + * @param nice true if a "nice" mock control is to be created; + * false if a "strict" control is to be created + */ + protected AbstractScalarMockTemplate(Class mockInterface, boolean nice) { + this.mockInterface = mockInterface; + this.mode = nice ? NICE : STRICT; + } + + + /** + * Sets the interface that is to be mocked. + * @param mockInterface the interface that is to be mocked + */ + public void setMockInterface(Class mockInterface) { + this.mockInterface = mockInterface; + } + + /** + * Gets the interface that is to be mocked. + * @return the interface that is to be mocked + */ + public Class getMockInterface() { + return mockInterface; + } + + + /** + * Setup any expectations for the test. + *

The default implementation is a no-op; i.e. no expectations are set. + * @param mockControl the EasyMock {@link org.easymock.MockControl} for the mocked object + * @param mockObject the mocked object + * @throws Exception if calling methods on the supplied mockObject + * that are declared as throwing one more exceptions (just here to satisfy the compiler really). + */ + public void setupExpectations(MockControl mockControl, Object mockObject) throws Exception { + } + + /** + * Do the EasyMock-driven test. + *

This is the driving template method, and should not typically need to overriden. + * @throws Exception if an exception is thrown during testing + */ + public void test() throws Exception { + MockControl mockControl = createMockControl(); + Object mockObject = mockControl.getMock(); + setupExpectations(mockControl, mockObject); + mockControl.replay(); + doTest(mockObject); + mockControl.verify(); + } + + /** + * Do the actual test using the supplied mock. + * @param mockObject the mocked object + * @throws Exception if an exception is thrown during the test logic + */ + public abstract void doTest(Object mockObject) throws Exception; + + + /** + * Create a {@link org.easymock.MockControl} for the mocked interface. + * @return a {@link org.easymock.MockControl} for the mocked interface + */ + protected MockControl createMockControl() { + return this.mode == NORMAL + ? MockControl.createControl(this.getMockInterface()) + : this.mode == NICE + ? MockControl.createNiceControl(this.getMockInterface()) + : MockControl.createStrictControl(this.getMockInterface()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequestTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequestTests.java new file mode 100644 index 00000000000..0f6d11ad00c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequestTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + * @author Mark Fisher + */ +public class MockHttpServletRequestTests extends TestCase { + + public void testHttpHeaderNameCasingIsPreserved() throws Exception { + String headerName = "Header1"; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(headerName, "value1"); + Enumeration requestHeaders = request.getHeaderNames(); + assertNotNull(requestHeaders); + assertEquals("HTTP header casing not being preserved", headerName, requestHeaders.nextElement()); + } + + public void testSetMultipleParameters() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter("key1", "value1"); + request.setParameter("key2", "value2"); + Map params = new HashMap(2); + params.put("key1", "newValue1"); + params.put("key3", new String[] { "value3A", "value3B" }); + request.setParameters(params); + String[] values1 = request.getParameterValues("key1"); + assertEquals(1, values1.length); + assertEquals("newValue1", request.getParameter("key1")); + assertEquals("value2", request.getParameter("key2")); + String[] values3 = request.getParameterValues("key3"); + assertEquals(2, values3.length); + assertEquals("value3A", values3[0]); + assertEquals("value3B", values3[1]); + } + + public void testAddMultipleParameters() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter("key1", "value1"); + request.setParameter("key2", "value2"); + Map params = new HashMap(2); + params.put("key1", "newValue1"); + params.put("key3", new String[] { "value3A", "value3B" }); + request.addParameters(params); + String[] values1 = request.getParameterValues("key1"); + assertEquals(2, values1.length); + assertEquals("value1", values1[0]); + assertEquals("newValue1", values1[1]); + assertEquals("value2", request.getParameter("key2")); + String[] values3 = request.getParameterValues("key3"); + assertEquals(2, values3.length); + assertEquals("value3A", values3[0]); + assertEquals("value3B", values3[1]); + } + + public void testRemoveAllParameters() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter("key1", "value1"); + Map params = new HashMap(2); + params.put("key2", "value2"); + params.put("key3", new String[] { "value3A", "value3B" }); + request.addParameters(params); + assertEquals(3, request.getParameterMap().size()); + request.removeAllParameters(); + assertEquals(0, request.getParameterMap().size()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java new file mode 100644 index 00000000000..e2b31f07ed7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java @@ -0,0 +1,130 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.web.util.WebUtils; + +/** + * @author Juergen Hoeller + * @author Rick Evans + * @since 19.02.2006 + */ +public class MockHttpServletResponseTests extends TestCase { + + public void testSetContentTypeWithNoEncoding() { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.setContentType("test/plain"); + assertEquals("Character encoding should be the default", + WebUtils.DEFAULT_CHARACTER_ENCODING, response.getCharacterEncoding()); + } + + public void testSetContentTypeWithUTF8() { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.setContentType("test/plain; charset=UTF-8"); + assertEquals("Character encoding should be 'UTF-8'", "UTF-8", response.getCharacterEncoding()); + } + + public void testHttpHeaderNameCasingIsPreserved() throws Exception { + final String headerName = "Header1"; + + MockHttpServletResponse response = new MockHttpServletResponse(); + response.addHeader(headerName, "value1"); + Set responseHeaders = response.getHeaderNames(); + assertNotNull(responseHeaders); + assertEquals(1, responseHeaders.size()); + assertEquals("HTTP header casing not being preserved", headerName, responseHeaders.iterator().next()); + } + + public void testServletOutputStreamCommittedWhenBufferSizeExceeded() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + assertFalse(response.isCommitted()); + response.getOutputStream().write('X'); + assertFalse(response.isCommitted()); + int size = response.getBufferSize(); + response.getOutputStream().write(new byte[size]); + assertTrue(response.isCommitted()); + assertEquals(size + 1, response.getContentAsByteArray().length); + } + + public void testServletOutputStreamCommittedOnFlushBuffer() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + assertFalse(response.isCommitted()); + response.getOutputStream().write('X'); + assertFalse(response.isCommitted()); + response.flushBuffer(); + assertTrue(response.isCommitted()); + assertEquals(1, response.getContentAsByteArray().length); + } + + public void testServletWriterCommittedWhenBufferSizeExceeded() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + assertFalse(response.isCommitted()); + response.getWriter().write("X"); + assertFalse(response.isCommitted()); + int size = response.getBufferSize(); + char[] data = new char[size]; + Arrays.fill(data, 'p'); + response.getWriter().write(data); + assertTrue(response.isCommitted()); + assertEquals(size + 1, response.getContentAsByteArray().length); + } + + public void testServletOutputStreamCommittedOnOutputStreamFlush() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + assertFalse(response.isCommitted()); + response.getOutputStream().write('X'); + assertFalse(response.isCommitted()); + response.getOutputStream().flush(); + assertTrue(response.isCommitted()); + assertEquals(1, response.getContentAsByteArray().length); + } + + public void testServletWriterCommittedOnWriterFlush() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + assertFalse(response.isCommitted()); + response.getWriter().write("X"); + assertFalse(response.isCommitted()); + response.getWriter().flush(); + assertTrue(response.isCommitted()); + assertEquals(1, response.getContentAsByteArray().length); + } + + public void testServletWriterAutoFlushedForString() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.getWriter().write("X"); + assertEquals("X", response.getContentAsString()); + } + + public void testServletWriterAutoFlushedForChar() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.getWriter().write('X'); + assertEquals("X", response.getContentAsString()); + } + + public void testServletWriterAutoFlushedForCharArray() throws IOException { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.getWriter().write("XY".toCharArray()); + assertEquals("XY", response.getContentAsString()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockPageContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockPageContextTests.java new file mode 100644 index 00000000000..33cde3e8724 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockPageContextTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import junit.framework.TestCase; + +import javax.servlet.jsp.PageContext; + +/** + * Unit tests for the MockPageContext class. + * + * @author Rick Evans + */ +public final class MockPageContextTests extends TestCase { + + public void testSetAttributeWithNoScopeUsesPageScope() throws Exception { + String key = "foo"; + String value = "bar"; + + MockPageContext ctx = new MockPageContext(); + ctx.setAttribute(key, value); + assertEquals(value, ctx.getAttribute(key, PageContext.PAGE_SCOPE)); + assertNull(ctx.getAttribute(key, PageContext.APPLICATION_SCOPE)); + assertNull(ctx.getAttribute(key, PageContext.REQUEST_SCOPE)); + assertNull(ctx.getAttribute(key, PageContext.SESSION_SCOPE)); + } + + public void testRemoveAttributeWithNoScopeSpecifiedRemovesValueFromAllScopes() throws Exception { + String key = "foo"; + String value = "bar"; + + MockPageContext ctx = new MockPageContext(); + ctx.setAttribute(key, value, PageContext.APPLICATION_SCOPE); + ctx.removeAttribute(key); + + assertNull(ctx.getAttribute(key, PageContext.PAGE_SCOPE)); + assertNull(ctx.getAttribute(key, PageContext.APPLICATION_SCOPE)); + assertNull(ctx.getAttribute(key, PageContext.REQUEST_SCOPE)); + assertNull(ctx.getAttribute(key, PageContext.SESSION_SCOPE)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockServletContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockServletContextTests.java new file mode 100644 index 00000000000..370845a0676 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockServletContextTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.util.Set; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + * @since 19.02.2006 + */ +public class MockServletContextTests extends TestCase { + + public void testListFiles() { + MockServletContext sc = new MockServletContext("org/springframework/mock"); + Set paths = sc.getResourcePaths("/web"); + assertNotNull(paths); + assertTrue(paths.contains("/web/MockServletContextTests.class")); + } + + public void testListSubdirectories() { + MockServletContext sc = new MockServletContext("org/springframework/mock"); + Set paths = sc.getResourcePaths("/"); + assertNotNull(paths); + assertTrue(paths.contains("/web/")); + } + + public void testListNonDirectory() { + MockServletContext sc = new MockServletContext("org/springframework/mock"); + Set paths = sc.getResourcePaths("/web/MockServletContextTests.class"); + assertNull(paths); + } + + public void testListInvalidPath() { + MockServletContext sc = new MockServletContext("org/springframework/mock"); + Set paths = sc.getResourcePaths("/web/invalid"); + assertNull(paths); + } + + public void testGetContext() { + MockServletContext sc = new MockServletContext(); + MockServletContext sc2 = new MockServletContext(); + sc.setContextPath("/"); + sc.registerContext("/second", sc2); + assertSame(sc, sc.getContext("/")); + assertSame(sc2, sc.getContext("/second")); + } + + public void testGetMimeType() { + MockServletContext sc = new MockServletContext(); + assertEquals("text/html", sc.getMimeType("test.html")); + assertEquals("image/gif", sc.getMimeType("test.gif")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateInterceptorTests.java new file mode 100644 index 00000000000..517a945f723 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateInterceptorTests.java @@ -0,0 +1,603 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Method; +import java.sql.SQLException; + +import junit.framework.TestCase; +import org.aopalliance.intercept.Interceptor; +import org.aopalliance.intercept.Invocation; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; +import org.hibernate.SessionFactory; +import org.hibernate.classic.Session; +import org.hibernate.exception.ConstraintViolationException; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class HibernateInterceptorTests extends TestCase { + + public void testInterceptorWithNewSession() throws HibernateException { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithNewSessionAndFlushNever() throws HibernateException { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setFlushModeName("FLUSH_NEVER"); + interceptor.setSessionFactory(sf); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithNewSessionAndFilter() throws HibernateException { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + interceptor.setFilterName("myFilter"); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBound() { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFlushEager() throws HibernateException { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setFlushMode(HibernateInterceptor.FLUSH_EAGER); + interceptor.setSessionFactory(sf); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFlushEagerSwitch() throws HibernateException { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setFlushMode(HibernateInterceptor.FLUSH_EAGER); + interceptor.setSessionFactory(sf); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFlushCommit() { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.setFlushMode(FlushMode.COMMIT); + sessionControl.setVoidCallable(1); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + interceptor.setFlushMode(HibernateInterceptor.FLUSH_COMMIT); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFlushAlways() { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.setFlushMode(FlushMode.ALWAYS); + sessionControl.setVoidCallable(1); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + interceptor.setFlushMode(HibernateInterceptor.FLUSH_ALWAYS); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFilter() { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.disableFilter("myFilter"); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + interceptor.setFilterName("myFilter"); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBoundAndFilters() { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.enableFilter("yourFilter"); + sessionControl.setReturnValue(null, 1); + session.disableFilter("myFilter"); + sessionControl.setVoidCallable(1); + session.disableFilter("yourFilter"); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + interceptor.setFilterNames(new String[] {"myFilter", "yourFilter"}); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithFlushFailure() throws Throwable { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + SQLException sqlEx = new SQLException("argh", "27"); + session.flush(); + ConstraintViolationException jdbcEx = new ConstraintViolationException("", sqlEx, null); + sessionControl.setThrowable(jdbcEx, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + try { + interceptor.invoke(new TestInvocation(sf)); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(jdbcEx, ex.getCause()); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithThreadBoundEmptyHolder() { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + SessionHolder holder = new SessionHolder("key", session); + holder.removeSession("key"); + TransactionSynchronizationManager.bindResource(sf, holder); + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithEntityInterceptor() throws HibernateException { + MockControl interceptorControl = MockControl.createControl(org.hibernate.Interceptor.class); + org.hibernate.Interceptor entityInterceptor = (org.hibernate.Interceptor) interceptorControl.getMock(); + interceptorControl.replay(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(entityInterceptor); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + interceptor.setEntityInterceptor(entityInterceptor); + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + interceptorControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithEntityInterceptorBeanName() throws HibernateException { + MockControl interceptorControl = MockControl.createControl(org.hibernate.Interceptor.class); + org.hibernate.Interceptor entityInterceptor = (org.hibernate.Interceptor) interceptorControl.getMock(); + interceptorControl.replay(); + MockControl interceptor2Control = MockControl.createControl(org.hibernate.Interceptor.class); + org.hibernate.Interceptor entityInterceptor2 = (org.hibernate.Interceptor) interceptor2Control.getMock(); + interceptor2Control.replay(); + + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(entityInterceptor); + sfControl.setReturnValue(session, 1); + sf.openSession(entityInterceptor2); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 2); + session.flush(); + sessionControl.setVoidCallable(2); + session.close(); + sessionControl.setReturnValue(null, 2); + sfControl.replay(); + sessionControl.replay(); + + MockControl beanFactoryControl = MockControl.createControl(BeanFactory.class); + BeanFactory beanFactory = (BeanFactory) beanFactoryControl.getMock(); + beanFactory.getBean("entityInterceptor", org.hibernate.Interceptor.class); + beanFactoryControl.setReturnValue(entityInterceptor, 1); + beanFactory.getBean("entityInterceptor", org.hibernate.Interceptor.class); + beanFactoryControl.setReturnValue(entityInterceptor2, 1); + beanFactoryControl.replay(); + + HibernateInterceptor interceptor = new HibernateInterceptor(); + interceptor.setSessionFactory(sf); + interceptor.setEntityInterceptorBeanName("entityInterceptor"); + interceptor.setBeanFactory(beanFactory); + for (int i = 0; i < 2; i++) { + try { + interceptor.invoke(new TestInvocation(sf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + } + + interceptorControl.verify(); + interceptor2Control.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + + + private static class TestInvocation implements MethodInvocation { + + private SessionFactory sessionFactory; + + public TestInvocation(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + public Object proceed() throws Throwable { + if (!TransactionSynchronizationManager.hasResource(this.sessionFactory)) { + throw new IllegalStateException("Session not bound"); + } + return null; + } + + public int getCurrentInterceptorIndex() { + return 0; + } + + public int getNumberOfInterceptors() { + return 0; + } + + public Interceptor getInterceptor(int i) { + return null; + } + + public Method getMethod() { + return null; + } + + public AccessibleObject getStaticPart() { + return null; + } + + public Object getArgument(int i) { + return null; + } + + public Object[] getArguments() { + return null; + } + + public void setArgument(int i, Object handler) { + } + + public int getArgumentCount() { + return 0; + } + + public Object getThis() { + return null; + } + + public Object getProxy() { + return null; + } + + public Invocation cloneInstance() { + return null; + } + + public void release() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateJtaTransactionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateJtaTransactionTests.java new file mode 100644 index 00000000000..134a4f2f7db --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateJtaTransactionTests.java @@ -0,0 +1,1824 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3; + +import java.util.ArrayList; +import java.util.List; + +import javax.transaction.RollbackException; +import javax.transaction.Status; +import javax.transaction.Synchronization; +import javax.transaction.SystemException; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; +import org.hibernate.Query; +import org.hibernate.SessionFactory; +import org.hibernate.classic.Session; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; + +import org.springframework.dao.DataAccessException; +import org.springframework.transaction.MockJtaTransaction; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.UnexpectedRollbackException; +import org.springframework.transaction.jta.JtaTransactionManager; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class HibernateJtaTransactionTests extends TestCase { + + public void testJtaTransactionCommit() throws Exception { + doTestJtaTransactionCommit(Status.STATUS_NO_TRANSACTION, false); + } + + public void testJtaTransactionCommitWithReadOnly() throws Exception { + doTestJtaTransactionCommit(Status.STATUS_NO_TRANSACTION, true); + } + + public void testJtaTransactionCommitWithExisting() throws Exception { + doTestJtaTransactionCommit(Status.STATUS_ACTIVE, false); + } + + public void testJtaTransactionCommitWithExistingAndReadOnly() throws Exception { + doTestJtaTransactionCommit(Status.STATUS_ACTIVE, true); + } + + private void doTestJtaTransactionCommit(int status, final boolean readOnly) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + final MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + ut.getStatus(); + utControl.setReturnValue(status, 1); + if (status == Status.STATUS_NO_TRANSACTION) { + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + utControl.setVoidCallable(1); + } + else { + ut.getStatus(); + utControl.setReturnValue(status, 1); + } + + final List list = new ArrayList(); + list.add("test"); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + if (readOnly) { + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + } + query.list(); + queryControl.setReturnValue(list, 1); + + utControl.replay(); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setReadOnly(readOnly); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + ht = new HibernateTemplate(sf); + List htl = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + return sess.createQuery("some query string").list(); + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + sessionControl.verify(); + queryControl.verify(); + sessionControl.reset(); + if (!readOnly) { + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + } + session.close(); + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + return htl; + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + + assertTrue("Correct result list", result == list); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaTransactionCommitWithJtaTm() throws Exception { + doTestJtaTransactionCommitWithJtaTm(Status.STATUS_NO_TRANSACTION); + } + + public void testJtaTransactionCommitWithJtaTmAndExisting() throws Exception { + doTestJtaTransactionCommitWithJtaTm(Status.STATUS_ACTIVE); + } + + private void doTestJtaTransactionCommitWithJtaTm(int status) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(status, 2); + if (status == Status.STATUS_NO_TRANSACTION) { + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.commit(); + utControl.setVoidCallable(1); + } + + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 1); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + + utControl.replay(); + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + List htl = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + htl = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + sessionControl.verify(); + sessionControl.reset(); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + return htl; + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + + assertTrue("Correct result list", result == l); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaTransactionWithFlushFailure() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + sfControl.replay(); + sessionControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + final List l = new ArrayList(); + l.add("test"); + final HibernateException flushEx = new HibernateException("flush failure"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + List htl = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + htl = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + sessionControl.verify(); + sessionControl.reset(); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setThrowable(flushEx); + session.close(); + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + return htl; + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + } + catch (DataAccessException ex) { + // expected + assertTrue(flushEx == ex.getCause()); + } + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaTransactionRollback() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + sfControl.replay(); + sessionControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + HibernateTemplate ht = new HibernateTemplate(sf); + List htl = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return l; + } + }); + status.setRollbackOnly(); + sessionControl.verify(); + sessionControl.reset(); + session.close(); + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + return htl; + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + utControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaTransactionCommitWithPreBound() throws Exception { + doTestJtaTransactionCommitWithPreBound(false, false, false); + } + + public void testJtaTransactionCommitWithPreBoundAndReadOnly() throws Exception { + doTestJtaTransactionCommitWithPreBound(false, false, true); + } + + public void testJtaTransactionCommitWithPreBoundAndFlushModeNever() throws Exception { + doTestJtaTransactionCommitWithPreBound(false, true, false); + } + + public void testJtaTransactionCommitWithPreBoundAndFlushModeNeverAndReadOnly() throws Exception { + doTestJtaTransactionCommitWithPreBound(false, true, true); + } + + public void testJtaTransactionCommitWithJtaTmAndPreBound() throws Exception { + doTestJtaTransactionCommitWithPreBound(true, false, false); + } + + public void testJtaTransactionCommitWithJtaTmAndPreBoundAndReadOnly() throws Exception { + doTestJtaTransactionCommitWithPreBound(true, false, true); + } + + public void testJtaTransactionCommitWithJtaTmAndPreBoundAndFlushModeNever() throws Exception { + doTestJtaTransactionCommitWithPreBound(true, true, false); + } + + public void testJtaTransactionCommitWithJtaTmAndPreBoundAndFlushModeNeverAndReadOnly() throws Exception { + doTestJtaTransactionCommitWithPreBound(true, true, true); + } + + protected void doTestJtaTransactionCommitWithPreBound( + boolean jtaTm, final boolean flushNever, final boolean readOnly) throws Exception { + + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + if (jtaTm) { + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + } + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(ExtendedSession.class); + final ExtendedSession session = (ExtendedSession) sessionControl.getMock(); + sf.getTransactionManager(); + sfControl.setReturnValue((jtaTm ? tm : null), 1); + session.isOpen(); + sessionControl.setReturnValue(true, 5); + session.getFlushMode(); + if (flushNever) { + sessionControl.setReturnValue(FlushMode.NEVER, 1); + if (!readOnly) { + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + } + } + else { + sessionControl.setReturnValue(FlushMode.AUTO, 1); + } + + utControl.replay(); + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setReadOnly(readOnly); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + List htl = null; + for (int i = 0; i < 5; i++) { + htl = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + } + sessionControl.verify(); + sessionControl.reset(); + if (!readOnly) { + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + if (flushNever) { + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + } + } + session.afterTransactionCompletion(true, null); + sessionControl.setVoidCallable(1); + session.disconnect(); + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + return htl; + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + + assertTrue("Correct result list", result == l); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + utControl.verify(); + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaTransactionRollbackWithPreBound() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_MARKED_ROLLBACK, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + RollbackException rex = new RollbackException(); + ut.commit(); + utControl.setThrowable(rex, 1); + utControl.replay(); + + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 5); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + sfControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + JtaTransactionManager ptm = new JtaTransactionManager(ut); + final TransactionTemplate tt = new TransactionTemplate(ptm); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + status.setRollbackOnly(); + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + } + sessionControl.verify(); + sessionControl.reset(); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.disconnect(); + sessionControl.setReturnValue(null, 1); + session.clear(); + sessionControl.setVoidCallable(1); + sessionControl.replay(); + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + } + }); + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + assertEquals(rex, ex.getCause()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + + utControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaTransactionCommitWithRequiresNew() throws Exception { + doTestJtaTransactionWithRequiresNew(false); + } + + public void testJtaTransactionRollbackWithRequiresNew() throws Exception { + doTestJtaTransactionWithRequiresNew(true); + } + + protected void doTestJtaTransactionWithRequiresNew(final boolean rollback) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl tx1Control = MockControl.createControl(javax.transaction.Transaction.class); + javax.transaction.Transaction tx1 = (javax.transaction.Transaction) tx1Control.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl session1Control = MockControl.createControl(Session.class); + final Session session1 = (Session) session1Control.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.begin(); + utControl.setVoidCallable(2); + tm.suspend(); + tmControl.setReturnValue(tx1, 1); + tm.resume(tx1); + tmControl.setVoidCallable(1); + if (rollback) { + ut.rollback(); + } + else { + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + } + utControl.setVoidCallable(2); + + sf.openSession(); + sfControl.setReturnValue(session1, 1); + sf.openSession(); + sfControl.setReturnValue(session2, 1); + session1.getSessionFactory(); + session1Control.setReturnValue(sf, 1); + session2.getSessionFactory(); + session2Control.setReturnValue(sf, 1); + session1.isOpen(); + session1Control.setReturnValue(true, 1); + session2.isOpen(); + session2Control.setReturnValue(true, 1); + session2.getFlushMode(); + session2Control.setReturnValue(FlushMode.AUTO, 1); + if (!rollback) { + session1.getFlushMode(); + session1Control.setReturnValue(FlushMode.AUTO, 1); + session2.getFlushMode(); + session2Control.setReturnValue(FlushMode.AUTO, 1); + session1.flush(); + session1Control.setVoidCallable(1); + session2.flush(); + session2Control.setVoidCallable(2); + } + session1.disconnect(); + session1Control.setReturnValue(null, 1); + session1.close(); + session1Control.setReturnValue(null, 1); + session2.close(); + session2Control.setReturnValue(null, 1); + + utControl.replay(); + tmControl.replay(); + sfControl.replay(); + session1Control.replay(); + session2Control.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(); + ptm.setUserTransaction(ut); + ptm.setTransactionManager(tm); + final TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + org.hibernate.Session outerSession = SessionFactoryUtils.getSession(sf, false); + assertSame(session1, outerSession); + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + org.hibernate.Session innerSession = SessionFactoryUtils.getSession(sf, false); + assertSame(session2, innerSession); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session innerSession) { + if (rollback) { + throw new HibernateException(""); + } + return null; + } + }); + } + }); + return null; + } + finally { + assertTrue("Same thread session as before", outerSession == SessionFactoryUtils.getSession(sf, false)); + } + } + }); + if (rollback) { + fail("Should have thrown DataAccessException"); + } + } + catch (DataAccessException ex) { + if (!rollback) { + throw ex; + } + } + finally { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + } + + utControl.verify(); + tmControl.verify(); + sfControl.verify(); + session1Control.verify(); + session2Control.verify(); + } + + public void testJtaTransactionWithRequiresNewAndSuspendException() throws Exception { + doTestJtaTransactionWithRequiresNewAndException(true); + } + + public void testJtaTransactionWithRequiresNewAndBeginException() throws Exception { + doTestJtaTransactionWithRequiresNewAndException(false); + } + + protected void doTestJtaTransactionWithRequiresNewAndException(boolean suspendException) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(javax.transaction.Transaction.class); + javax.transaction.Transaction tx = (javax.transaction.Transaction) txControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl session1Control = MockControl.createControl(Session.class); + final Session session1 = (Session) session1Control.getMock(); + + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + if (suspendException) { + tm.suspend(); + tmControl.setThrowable(new SystemException(), 1); + } + else { + tm.suspend(); + tmControl.setReturnValue(tx, 1); + ut.begin(); + utControl.setThrowable(new SystemException(), 1); + tm.resume(tx); + tmControl.setVoidCallable(1); + } + ut.rollback(); + utControl.setVoidCallable(1); + + sf.openSession(); + sfControl.setReturnValue(session1, 1); + session1.getSessionFactory(); + session1Control.setReturnValue(sf, 1); + session1.disconnect(); + session1Control.setReturnValue(null, 1); + session1.close(); + session1Control.setReturnValue(null, 1); + + utControl.replay(); + tmControl.replay(); + sfControl.replay(); + session1Control.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(); + ptm.setUserTransaction(ut); + ptm.setTransactionManager(tm); + final TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + org.hibernate.Session outerSession = SessionFactoryUtils.getSession(sf, false); + assertSame(session1, outerSession); + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return null; + } + }); + return null; + } + }); + fail("Should have thrown TransactionException"); + } + catch (TransactionException ex) { + // expected + } + finally { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + } + + utControl.verify(); + tmControl.verify(); + sfControl.verify(); + session1Control.verify(); + } + + public void testJtaTransactionCommitWithRequiresNewAndJtaTm() throws Exception { + doTestJtaTransactionWithRequiresNewAndJtaTm(false); + } + + public void testJtaTransactionRollbackWithRequiresNewAndJtaTm() throws Exception { + doTestJtaTransactionWithRequiresNewAndJtaTm(true); + } + + protected void doTestJtaTransactionWithRequiresNewAndJtaTm(final boolean rollback) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl tx1Control = MockControl.createControl(javax.transaction.Transaction.class); + javax.transaction.Transaction tx1 = (javax.transaction.Transaction) tx1Control.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + MockControl session1Control = MockControl.createControl(Session.class); + final Session session1 = (Session) session1Control.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + + MockJtaTransaction transaction1 = new MockJtaTransaction(); + MockJtaTransaction transaction2 = new MockJtaTransaction(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.begin(); + utControl.setVoidCallable(2); + tm.getTransaction(); + tmControl.setReturnValue(transaction1, 1); + tm.suspend(); + tmControl.setReturnValue(tx1, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction2, 1); + tm.resume(tx1); + tmControl.setVoidCallable(1); + if (rollback) { + ut.rollback(); + } + else { + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + } + utControl.setVoidCallable(2); + + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 2); + sf.openSession(); + sfControl.setReturnValue(session1, 1); + sf.openSession(); + sfControl.setReturnValue(session2, 1); + session1.isOpen(); + session1Control.setReturnValue(true, 1); + session2.isOpen(); + session2Control.setReturnValue(true, 1); + session2.getFlushMode(); + session2Control.setReturnValue(FlushMode.AUTO, 1); + if (!rollback) { + session1.getFlushMode(); + session1Control.setReturnValue(FlushMode.AUTO, 1); + session2.getFlushMode(); + session2Control.setReturnValue(FlushMode.AUTO, 1); + session1.flush(); + session1Control.setVoidCallable(1); + session2.flush(); + session2Control.setVoidCallable(2); + } + session1.disconnect(); + session1Control.setReturnValue(null, 1); + session1.close(); + session1Control.setReturnValue(null, 1); + session2.close(); + session2Control.setReturnValue(null, 1); + + utControl.replay(); + tmControl.replay(); + sfControl.replay(); + session1Control.replay(); + session2Control.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(); + ptm.setUserTransaction(ut); + ptm.setTransactionManager(tm); + final TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + org.hibernate.Session outerSession = SessionFactoryUtils.getSession(sf, false); + assertSame(session1, outerSession); + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + org.hibernate.Session innerSession = SessionFactoryUtils.getSession(sf, false); + assertSame(session2, innerSession); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session innerSession) { + if (rollback) { + throw new HibernateException(""); + } + return null; + } + }); + } + }); + return null; + } + finally { + assertTrue("Same thread session as before", outerSession == SessionFactoryUtils.getSession(sf, false)); + } + } + }); + if (rollback) { + fail("Should have thrown DataAccessException"); + } + } + catch (DataAccessException ex) { + if (!rollback) { + throw ex; + } + } + finally { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + } + + utControl.verify(); + tmControl.verify(); + sfControl.verify(); + session1Control.verify(); + session2Control.verify(); + } + + public void testTransactionWithPropagationSupports() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + JtaTransactionManager tm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return null; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + return null; + } + }); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + } + + public void testTransactionWithPropagationSupportsAndInnerTransaction() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 3); + session.flush(); + sessionControl.setVoidCallable(3); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + JtaTransactionManager tm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + final TransactionTemplate tt2 = new TransactionTemplate(tm); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return null; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + tt2.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + //assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + return null; + } + }); + } + }); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaSessionSynchronization() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 6); + session.isOpen(); + sessionControl.setReturnValue(true, 4); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization != null); + synchronization.beforeCompletion(); + synchronization.afterCompletion(Status.STATUS_COMMITTED); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaSessionSynchronizationWithRollback() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 6); + session.isOpen(); + sessionControl.setReturnValue(true, 4); + session.close(); + sessionControl.setReturnValue(null, 1); + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization != null); + synchronization.afterCompletion(Status.STATUS_ROLLEDBACK); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaSessionSynchronizationWithRollbackByOtherThread() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 7); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 2); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 7); + session.isOpen(); + sessionControl.setReturnValue(true, 8); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 2); + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + final HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + final Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization != null); + Thread thread = new Thread() { + public void run() { + synchronization.afterCompletion(Status.STATUS_ROLLEDBACK); + } + }; + thread.start(); + thread.join(); + + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + TransactionTemplate tt = new TransactionTemplate(new JtaTransactionManager(tm)); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + tt.setReadOnly(true); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + } + }); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaSessionSynchronizationWithFlushFailure() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + tm.setRollbackOnly(); + tmControl.setVoidCallable(1); + + final HibernateException flushEx = new HibernateException("flush failure"); + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 6); + session.isOpen(); + sessionControl.setReturnValue(true, 4); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setThrowable(flushEx, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization != null); + try { + synchronization.beforeCompletion(); + fail("Should have thrown HibernateSystemException"); + } + catch (HibernateSystemException ex) { + assertSame(flushEx, ex.getCause()); + } + synchronization.afterCompletion(Status.STATUS_ROLLEDBACK); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaSessionSynchronizationWithSuspendedTransaction() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction1 = new MockJtaTransaction(); + MockJtaTransaction transaction2 = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction1, 2); + tm.getTransaction(); + tmControl.setReturnValue(transaction2, 3); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl session1Control = MockControl.createControl(Session.class); + final Session session1 = (Session) session1Control.getMock(); + final MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + sf.openSession(); + sfControl.setReturnValue(session1, 1); + sf.openSession(); + sfControl.setReturnValue(session2, 1); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 5); + session1.getFlushMode(); + session1Control.setReturnValue(FlushMode.AUTO, 1); + session2.getFlushMode(); + session2Control.setReturnValue(FlushMode.AUTO, 1); + session1.flush(); + session1Control.setVoidCallable(1); + session2.flush(); + session2Control.setVoidCallable(1); + session1.close(); + session1Control.setReturnValue(null, 1); + session2.close(); + session2Control.setReturnValue(null, 1); + + tmControl.replay(); + sfControl.replay(); + session1Control.replay(); + session2Control.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session1, sess); + return null; + } + }); + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session2, sess); + return null; + } + }); + + Synchronization synchronization2 = transaction2.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization2 != null); + synchronization2.beforeCompletion(); + synchronization2.afterCompletion(Status.STATUS_COMMITTED); + + Synchronization synchronization1 = transaction1.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization1 != null); + synchronization1.beforeCompletion(); + synchronization1.afterCompletion(Status.STATUS_COMMITTED); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + sfControl.verify(); + session1Control.verify(); + session2Control.verify(); + } + + public void testJtaSessionSynchronizationWithNonSessionFactoryImplementor() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl sfiControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sfi = (SessionFactoryImplementor) sfiControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sfi, 6); + sfi.getTransactionManager(); + sfiControl.setReturnValue(tm, 6); + session.isOpen(); + sessionControl.setReturnValue(true, 4); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + sfiControl.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA Synchronization registered", synchronization != null); + synchronization.beforeCompletion(); + synchronization.afterCompletion(Status.STATUS_COMMITTED); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + sfiControl.verify(); + } + + public void testJtaSessionSynchronizationWithSpringTransactionLaterOn() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 6); + session.isOpen(); + sessionControl.setReturnValue(true, 4); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + + utControl.replay(); + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + final HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 2; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + TransactionTemplate tt = new TransactionTemplate(new JtaTransactionManager(ut)); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + for (int i = 2; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + } + }); + + Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization != null); + synchronization.beforeCompletion(); + synchronization.afterCompletion(Status.STATUS_COMMITTED); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaSessionSynchronizationWithPreBound() throws Exception { + doTestJtaSessionSynchronizationWithPreBound(false); + } + + public void testJtaJtaSessionSynchronizationWithPreBoundAndFlushNever() throws Exception { + doTestJtaSessionSynchronizationWithPreBound(true); + } + + private void doTestJtaSessionSynchronizationWithPreBound(boolean flushNever) throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 6); + session.isOpen(); + sessionControl.setReturnValue(true, 5); + session.getFlushMode(); + if (flushNever) { + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + } + else { + sessionControl.setReturnValue(FlushMode.AUTO, 1); + } + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + sessionControl.verify(); + sessionControl.reset(); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + if (flushNever) { + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + } + session.disconnect(); + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + + Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization != null); + synchronization.beforeCompletion(); + synchronization.afterCompletion(Status.STATUS_COMMITTED); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + public void testJtaSessionSynchronizationWithRemoteTransaction() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + for (int j = 0; j < 2; j++) { + tmControl.reset(); + sfControl.reset(); + sessionControl.reset(); + + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 6); + session.isOpen(); + sessionControl.setReturnValue(true, 4); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + if (j == 0) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + } + else { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + } + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + for (int i = 0; i < 5; i++) { + ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return null; + } + }); + } + + final Synchronization synchronization = transaction.getSynchronization(); + assertTrue("JTA synchronization registered", synchronization != null); + + // Call synchronization in a new thread, to simulate a synchronization + // triggered by a new remote call from a remote transaction coordinator. + Thread synch = new Thread() { + public void run() { + synchronization.beforeCompletion(); + synchronization.afterCompletion(Status.STATUS_COMMITTED); + } + }; + synch.start(); + synch.join(); + + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Thread session holder empty", sessionHolder.isEmpty()); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + sfControl.verify(); + sessionControl.verify(); + } + + TransactionSynchronizationManager.unbindResource(sf); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + + + /** + * Interface that combines Hibernate's Session and SessionImplementor interface. + * Necessary for creating a mock that implements both interfaces. + * Note: Hibernate 3.1's SessionImplementor interface does not extend Session anymore. + */ + public static interface ExtendedSession extends Session, SessionImplementor { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTemplateTests.java new file mode 100644 index 00000000000..2bd94fe8961 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTemplateTests.java @@ -0,0 +1,2587 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3; + +import java.lang.reflect.Proxy; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.hibernate.Criteria; +import org.hibernate.Filter; +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.JDBCException; +import org.hibernate.LockMode; +import org.hibernate.NonUniqueResultException; +import org.hibernate.ObjectDeletedException; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.PersistentObjectException; +import org.hibernate.PropertyValueException; +import org.hibernate.Query; +import org.hibernate.QueryException; +import org.hibernate.ReplicationMode; +import org.hibernate.SessionFactory; +import org.hibernate.StaleObjectStateException; +import org.hibernate.StaleStateException; +import org.hibernate.TransientObjectException; +import org.hibernate.UnresolvableObjectException; +import org.hibernate.WrongClassException; +import org.hibernate.classic.Session; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.DataException; +import org.hibernate.exception.GenericJDBCException; +import org.hibernate.exception.JDBCConnectionException; +import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.SQLGrammarException; + +import org.springframework.beans.TestBean; +import org.springframework.dao.CannotAcquireLockException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class HibernateTemplateTests extends TestCase { + + private MockControl sfControl; + private SessionFactory sf; + private MockControl sessionControl; + private Session session; + + protected void setUp() { + sfControl = MockControl.createControl(SessionFactory.class); + sf = (SessionFactory) sfControl.getMock(); + sessionControl = MockControl.createControl(Session.class); + session = (Session) sessionControl.getMock(); + } + + public void testExecuteWithNewSession() throws HibernateException { + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + assertTrue("Correct allowCreate default", ht.isAllowCreate()); + assertTrue("Correct flushMode default", ht.getFlushMode() == HibernateTemplate.FLUSH_AUTO); + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + public void testExecuteWithNewSessionAndFlushNever() throws HibernateException { + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_NEVER); + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + public void testExecuteWithNewSessionAndFilter() throws HibernateException { + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFilterName("myFilter"); + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + public void testExecuteWithNewSessionAndFilters() throws HibernateException { + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.enableFilter("yourFilter"); + sessionControl.setReturnValue(null, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFilterNames(new String[] {"myFilter", "yourFilter"}); + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + public void testExecuteWithNotAllowCreate() { + sf.getCurrentSession(); + sfControl.setThrowable(new HibernateException("")); + sfControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(); + ht.setSessionFactory(sf); + ht.setAllowCreate(false); + try { + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return null; + } + }); + fail("Should have thrown DataAccessException"); + } + catch (DataAccessResourceFailureException ex) { + // expected + } + } + + public void testExecuteWithNotAllowCreateAndThreadBound() { + sf.getCurrentSession(); + sfControl.setReturnValue(session); + sfControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setAllowCreate(false); + + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + public void testExecuteWithThreadBoundAndFlushEager() throws HibernateException { + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.flush(); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushModeName("FLUSH_EAGER"); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + } + + public void testExecuteWithThreadBoundAndFilter() { + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.disableFilter("myFilter"); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFilterName("myFilter"); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + } + + public void testExecuteWithThreadBoundAndFilters() { + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.enableFilter("yourFilter"); + sessionControl.setReturnValue(null, 1); + session.disableFilter("myFilter"); + sessionControl.setVoidCallable(1); + session.disableFilter("yourFilter"); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFilterNames(new String[] {"myFilter", "yourFilter"}); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + } + + public void testExecuteWithThreadBoundAndParameterizedFilter() { + MockControl filterControl = MockControl.createControl(Filter.class); + Filter filter = (Filter) filterControl.getMock(); + + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getEnabledFilter("myFilter"); + sessionControl.setReturnValue(null, 1); + session.enableFilter("myFilter"); + sessionControl.setReturnValue(filter, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setAllowCreate(false); + ht.setFilterName("myFilter"); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + final List l = new ArrayList(); + l.add("test"); + Filter f = ht.enableFilter("myFilter"); + assertTrue("Correct filter", f == filter); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + } + + public void testExecuteWithThreadBoundAndParameterizedExistingFilter() { + MockControl filterControl = MockControl.createControl(Filter.class); + Filter filter = (Filter) filterControl.getMock(); + + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getEnabledFilter("myFilter"); + sessionControl.setReturnValue(filter, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setAllowCreate(false); + ht.setFilterName("myFilter"); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + final List l = new ArrayList(); + l.add("test"); + Filter f = ht.enableFilter("myFilter"); + assertTrue("Correct filter", f == filter); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + } + + public void testExecuteWithThreadBoundAndNewSession() throws HibernateException { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + Session session2 = (Session) session2Control.getMock(); + + session2.connection(); + session2Control.setReturnValue(con, 1); + sf.openSession(con); + sfControl.setReturnValue(session, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + session2Control.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setAlwaysUseNewSession(true); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session2)); + try { + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + } + + public void testExecuteWithThreadBoundAndNewSessionAndEntityInterceptor() throws HibernateException { + MockControl interceptorControl = MockControl.createControl(org.hibernate.Interceptor.class); + Interceptor entityInterceptor = (Interceptor) interceptorControl.getMock(); + + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + Session session2 = (Session) session2Control.getMock(); + + session2.connection(); + session2Control.setReturnValue(con, 1); + sf.openSession(con, entityInterceptor); + sfControl.setReturnValue(session, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + session2Control.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setAlwaysUseNewSession(true); + ht.setEntityInterceptor(entityInterceptor); + + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session2)); + try { + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + } + } + + public void testExecuteWithEntityInterceptor() throws HibernateException { + MockControl interceptorControl = MockControl.createControl(org.hibernate.Interceptor.class); + Interceptor entityInterceptor = (Interceptor) interceptorControl.getMock(); + + sf.openSession(entityInterceptor); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setEntityInterceptor(entityInterceptor); + final List l = new ArrayList(); + l.add("test"); + List result = ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + public void testExecuteWithCacheQueries() throws HibernateException { + MockControl query1Control = MockControl.createControl(Query.class); + Query query1 = (Query) query1Control.getMock(); + MockControl query2Control = MockControl.createControl(Query.class); + Query query2 = (Query) query2Control.getMock(); + MockControl criteriaControl = MockControl.createControl(Criteria.class); + Criteria criteria = (Criteria) criteriaControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query"); + sessionControl.setReturnValue(query1); + query1.setCacheable(true); + query1Control.setReturnValue(query1, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query2); + query2.setCacheable(true); + query2Control.setReturnValue(query2, 1); + session.createCriteria(TestBean.class); + sessionControl.setReturnValue(criteria, 1); + criteria.setCacheable(true); + criteriaControl.setReturnValue(criteria, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + query1Control.replay(); + query2Control.replay(); + criteriaControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertNotSame(session, sess); + assertTrue(Proxy.isProxyClass(sess.getClass())); + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + // should be ignored + sess.close(); + return null; + } + }); + + query1Control.verify(); + query2Control.verify(); + criteriaControl.verify(); + } + + public void testExecuteWithCacheQueriesAndCacheRegion() throws HibernateException { + MockControl query1Control = MockControl.createControl(Query.class); + Query query1 = (Query) query1Control.getMock(); + MockControl query2Control = MockControl.createControl(Query.class); + Query query2 = (Query) query2Control.getMock(); + MockControl criteriaControl = MockControl.createControl(Criteria.class); + Criteria criteria = (Criteria) criteriaControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query"); + sessionControl.setReturnValue(query1); + query1.setCacheable(true); + query1Control.setReturnValue(query1, 1); + query1.setCacheRegion("myRegion"); + query1Control.setReturnValue(query1, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query2); + query2.setCacheable(true); + query2Control.setReturnValue(query2, 1); + query2.setCacheRegion("myRegion"); + query2Control.setReturnValue(query2, 1); + session.createCriteria(TestBean.class); + sessionControl.setReturnValue(criteria, 1); + criteria.setCacheable(true); + criteriaControl.setReturnValue(criteria, 1); + criteria.setCacheRegion("myRegion"); + criteriaControl.setReturnValue(criteria, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + query1Control.replay(); + query2Control.replay(); + criteriaControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + ht.setQueryCacheRegion("myRegion"); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertNotSame(session, sess); + assertTrue(Proxy.isProxyClass(sess.getClass())); + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + // should be ignored + sess.close(); + return null; + } + }); + + query1Control.verify(); + query2Control.verify(); + criteriaControl.verify(); + } + + public void testExecuteWithCacheQueriesAndCacheRegionAndNativeSession() throws HibernateException { + MockControl query1Control = MockControl.createControl(Query.class); + Query query1 = (Query) query1Control.getMock(); + MockControl query2Control = MockControl.createControl(Query.class); + Query query2 = (Query) query2Control.getMock(); + MockControl criteriaControl = MockControl.createControl(Criteria.class); + Criteria criteria = (Criteria) criteriaControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query"); + sessionControl.setReturnValue(query1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query2); + session.createCriteria(TestBean.class); + sessionControl.setReturnValue(criteria, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + query1Control.replay(); + query2Control.replay(); + criteriaControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + ht.setCacheQueries(true); + ht.setQueryCacheRegion("myRegion"); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertSame(session, sess); + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + return null; + } + }); + + query1Control.verify(); + query2Control.verify(); + criteriaControl.verify(); + } + + public void testExecuteWithFetchSizeAndMaxResults() throws HibernateException { + MockControl query1Control = MockControl.createControl(Query.class); + Query query1 = (Query) query1Control.getMock(); + MockControl query2Control = MockControl.createControl(Query.class); + Query query2 = (Query) query2Control.getMock(); + MockControl criteriaControl = MockControl.createControl(Criteria.class); + Criteria criteria = (Criteria) criteriaControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query"); + sessionControl.setReturnValue(query1); + query1.setFetchSize(10); + query1Control.setReturnValue(query1, 1); + query1.setMaxResults(20); + query1Control.setReturnValue(query1, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query2); + query2.setFetchSize(10); + query2Control.setReturnValue(query2, 1); + query2.setMaxResults(20); + query2Control.setReturnValue(query2, 1); + session.createCriteria(TestBean.class); + sessionControl.setReturnValue(criteria, 1); + criteria.setFetchSize(10); + criteriaControl.setReturnValue(criteria, 1); + criteria.setMaxResults(20); + criteriaControl.setReturnValue(criteria, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + query1Control.replay(); + query2Control.replay(); + criteriaControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFetchSize(10); + ht.setMaxResults(20); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + return null; + } + }); + + query1Control.verify(); + query2Control.verify(); + criteriaControl.verify(); + } + + public void testGet() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.get(TestBean.class, ""); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.get(TestBean.class, ""); + assertTrue("Correct result", result == tb); + } + + public void testGetWithLockMode() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.get(TestBean.class, "", LockMode.UPGRADE_NOWAIT); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.get(TestBean.class, "", LockMode.UPGRADE_NOWAIT); + assertTrue("Correct result", result == tb); + } + + public void testGetWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.get("myEntity", ""); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.get("myEntity", ""); + assertTrue("Correct result", result == tb); + } + + public void testGetWithEntityNameAndLockMode() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.get("myEntity", "", LockMode.UPGRADE_NOWAIT); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.get("myEntity", "", LockMode.UPGRADE_NOWAIT); + assertTrue("Correct result", result == tb); + } + + public void testLoad() throws HibernateException { + TestBean tb = new TestBean(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.load(TestBean.class, ""); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.load(TestBean.class, ""); + assertTrue("Correct result", result == tb); + } + + public void testLoadWithNotFound() throws HibernateException { + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.load(TestBean.class, "id"); + ObjectNotFoundException onfex = new ObjectNotFoundException("id", TestBean.class.getName()); + sessionControl.setThrowable(onfex); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + try { + ht.load(TestBean.class, "id"); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(onfex, ex.getCause()); + } + } + + public void testLoadWithLockMode() throws HibernateException { + TestBean tb = new TestBean(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.load(TestBean.class, "", LockMode.UPGRADE); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.load(TestBean.class, "", LockMode.UPGRADE); + assertTrue("Correct result", result == tb); + } + + public void testLoadWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.load("myEntity", ""); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.load("myEntity", ""); + assertTrue("Correct result", result == tb); + } + + public void testLoadWithEntityNameLockMode() throws HibernateException { + TestBean tb = new TestBean(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.load("myEntity", "", LockMode.UPGRADE); + sessionControl.setReturnValue(tb, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Object result = ht.load("myEntity", "", LockMode.UPGRADE); + assertTrue("Correct result", result == tb); + } + + public void testLoadWithObject() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.load(tb, ""); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.load(tb, ""); + } + + public void testLoadAll() throws HibernateException { + MockControl criteriaControl = MockControl.createControl(Criteria.class); + Criteria criteria = (Criteria) criteriaControl.getMock(); + List list = new ArrayList(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createCriteria(TestBean.class); + sessionControl.setReturnValue(criteria, 1); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + criteriaControl.setReturnValue(criteria); + criteria.list(); + criteriaControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + criteriaControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.loadAll(TestBean.class); + assertTrue("Correct result", result == list); + + criteriaControl.verify(); + } + + public void testLoadAllWithCacheable() throws HibernateException { + MockControl criteriaControl = MockControl.createControl(Criteria.class); + Criteria criteria = (Criteria) criteriaControl.getMock(); + List list = new ArrayList(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createCriteria(TestBean.class); + sessionControl.setReturnValue(criteria, 1); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + criteriaControl.setReturnValue(criteria); + criteria.setCacheable(true); + criteriaControl.setReturnValue(criteria, 1); + criteria.list(); + criteriaControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + criteriaControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + List result = ht.loadAll(TestBean.class); + assertTrue("Correct result", result == list); + + criteriaControl.verify(); + } + + public void testLoadAllWithCacheableAndCacheRegion() throws HibernateException { + MockControl criteriaControl = MockControl.createControl(Criteria.class); + Criteria criteria = (Criteria) criteriaControl.getMock(); + List list = new ArrayList(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createCriteria(TestBean.class); + sessionControl.setReturnValue(criteria, 1); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + criteriaControl.setReturnValue(criteria); + criteria.setCacheable(true); + criteriaControl.setReturnValue(criteria, 1); + criteria.setCacheRegion("myCacheRegion"); + criteriaControl.setReturnValue(criteria, 1); + criteria.list(); + criteriaControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + criteriaControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + ht.setQueryCacheRegion("myCacheRegion"); + List result = ht.loadAll(TestBean.class); + assertTrue("Correct result", result == list); + + criteriaControl.verify(); + } + + public void testRefresh() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.refresh(tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.refresh(tb); + } + + public void testContains() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.contains(tb); + sessionControl.setReturnValue(true, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + assertTrue(ht.contains(tb)); + } + + public void testEvict() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.evict(tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.evict(tb); + } + + public void testLock() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.lock(tb, LockMode.WRITE); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.lock(tb, LockMode.WRITE); + } + + public void testLockWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.lock("myEntity", tb, LockMode.WRITE); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.lock("myEntity", tb, LockMode.WRITE); + } + + public void testSave() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.save(tb); + sessionControl.setReturnValue(new Integer(0), 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + assertEquals("Correct return value", ht.save(tb), new Integer(0)); + } + + public void testSaveWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.save("myEntity", tb); + sessionControl.setReturnValue(new Integer(0), 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + assertEquals("Correct return value", ht.save("myEntity", tb), new Integer(0)); + } + + public void testUpdate() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.update(tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.update(tb); + } + + public void testUpdateWithLockMode() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.update(tb); + sessionControl.setVoidCallable(1); + session.lock(tb, LockMode.UPGRADE); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.update(tb, LockMode.UPGRADE); + } + + public void testUpdateWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.update("myEntity", tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.update("myEntity", tb); + } + + public void testUpdateWithEntityNameAndLockMode() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.update("myEntity", tb); + sessionControl.setVoidCallable(1); + session.lock(tb, LockMode.UPGRADE); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.update("myEntity", tb, LockMode.UPGRADE); + } + + public void testSaveOrUpdate() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.saveOrUpdate(tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.saveOrUpdate(tb); + } + + public void testSaveOrUpdateWithFlushModeNever() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + try { + ht.saveOrUpdate(tb); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + } + + public void testSaveOrUpdateWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.saveOrUpdate("myEntity", tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.saveOrUpdate("myEntity", tb); + } + + public void testSaveOrUpdateAll() throws HibernateException { + TestBean tb1 = new TestBean(); + TestBean tb2 = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.saveOrUpdate(tb1); + sessionControl.setVoidCallable(1); + session.saveOrUpdate(tb2); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List tbs = new ArrayList(); + tbs.add(tb1); + tbs.add(tb2); + ht.saveOrUpdateAll(tbs); + } + + public void testReplicate() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.replicate(tb, ReplicationMode.LATEST_VERSION); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.replicate(tb, ReplicationMode.LATEST_VERSION); + } + + public void testReplicateWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.replicate("myEntity", tb, ReplicationMode.LATEST_VERSION); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.replicate("myEntity", tb, ReplicationMode.LATEST_VERSION); + } + + public void testPersist() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.persist(tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.persist(tb); + } + + public void testPersistWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.persist("myEntity", tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.persist("myEntity", tb); + } + + public void testMerge() throws HibernateException { + TestBean tb = new TestBean(); + TestBean tbMerged = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.merge(tb); + sessionControl.setReturnValue(tbMerged, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + assertSame(tbMerged, ht.merge(tb)); + } + + public void testMergeWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + TestBean tbMerged = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.merge("myEntity", tb); + sessionControl.setReturnValue(tbMerged, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + assertSame(tbMerged, ht.merge("myEntity", tb)); + } + + public void testDelete() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.delete(tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.delete(tb); + } + + public void testDeleteWithLockMode() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.lock(tb, LockMode.UPGRADE); + sessionControl.setVoidCallable(1); + session.delete(tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.delete(tb, LockMode.UPGRADE); + } + + public void testDeleteWithEntityName() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.delete("myEntity", tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.delete("myEntity", tb); + } + + public void testDeleteWithEntityNameAndLockMode() throws HibernateException { + TestBean tb = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.lock("myEntity", tb, LockMode.UPGRADE); + sessionControl.setVoidCallable(1); + session.delete("myEntity", tb); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.delete("myEntity", tb, LockMode.UPGRADE); + } + + public void testDeleteAll() throws HibernateException { + TestBean tb1 = new TestBean(); + TestBean tb2 = new TestBean(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO); + session.delete(tb1); + sessionControl.setVoidCallable(1); + session.delete(tb2); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List tbs = new ArrayList(); + tbs.add(tb1); + tbs.add(tb2); + ht.deleteAll(tbs); + } + + public void testFlush() throws HibernateException { + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_NEVER); + ht.flush(); + } + + public void testClear() throws HibernateException { + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.clear(); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.clear(); + } + + public void testFind() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.find("some query string"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindWithParameter() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue"); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.find("some query string", "myvalue"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindWithParameters() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue1"); + queryControl.setReturnValue(query, 1); + query.setParameter(1, new Integer(2)); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.find("some query string", new Object[] {"myvalue1", new Integer(2)}); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindWithNamedParameter() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter("myparam", "myvalue"); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedParam("some query string", "myparam", "myvalue"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindWithNamedParameters() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter("myparam1", "myvalue1"); + queryControl.setReturnValue(query, 1); + query.setParameter("myparam2", new Integer(2)); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedParam("some query string", + new String[] {"myparam1", "myparam2"}, + new Object[] {"myvalue1", new Integer(2)}); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByValueBean() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + TestBean tb = new TestBean(); + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setProperties(tb); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByValueBean("some query string", tb); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByNamedQuery() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedQuery("some query name"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByNamedQueryWithParameter() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue"); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedQuery("some query name", "myvalue"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByNamedQueryWithParameters() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue1"); + queryControl.setReturnValue(query, 1); + query.setParameter(1, new Integer(2)); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedQuery("some query name", new Object[] {"myvalue1", new Integer(2)}); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByNamedQueryWithNamedParameter() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.setParameter("myparam", "myvalue"); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedQueryAndNamedParam("some query name", "myparam", "myvalue"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByNamedQueryWithNamedParameters() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.setParameter("myparam1", "myvalue1"); + queryControl.setReturnValue(query, 1); + query.setParameter("myparam2", new Integer(2)); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedQueryAndNamedParam("some query name", + new String[] {"myparam1", "myparam2"}, + new Object[] {"myvalue1", new Integer(2)}); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByNamedQueryAndValueBean() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + TestBean tb = new TestBean(); + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.setProperties(tb); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + List result = ht.findByNamedQueryAndValueBean("some query name", tb); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindWithCacheable() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setCacheable(true); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + List result = ht.find("some query string"); + assertTrue("Correct list", result == list); + sfControl.verify(); + } + + public void testFindWithCacheableAndCacheRegion() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setCacheable(true); + queryControl.setReturnValue(query, 1); + query.setCacheRegion("myCacheRegion"); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + ht.setQueryCacheRegion("myCacheRegion"); + List result = ht.find("some query string"); + assertTrue("Correct list", result == list); + sfControl.verify(); + } + + public void testFindByNamedQueryWithCacheable() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.setCacheable(true); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + List result = ht.findByNamedQuery("some query name"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testFindByNamedQueryWithCacheableAndCacheRegion() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + List list = new ArrayList(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getNamedQuery("some query name"); + sessionControl.setReturnValue(query, 1); + query.setCacheable(true); + queryControl.setReturnValue(query, 1); + query.setCacheRegion("myCacheRegion"); + queryControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setCacheQueries(true); + ht.setQueryCacheRegion("myCacheRegion"); + List result = ht.findByNamedQuery("some query name"); + assertTrue("Correct list", result == list); + queryControl.verify(); + } + + public void testIterate() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + Iterator it = Collections.EMPTY_LIST.iterator(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.iterate(); + queryControl.setReturnValue(it, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Iterator result = ht.iterate("some query string"); + assertTrue("Correct list", result == it); + queryControl.verify(); + } + + public void testIterateWithParameter() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + Iterator it = Collections.EMPTY_LIST.iterator(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue"); + queryControl.setReturnValue(query, 1); + query.iterate(); + queryControl.setReturnValue(it, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Iterator result = ht.iterate("some query string", "myvalue"); + assertTrue("Correct list", result == it); + queryControl.verify(); + } + + public void testIterateWithParameters() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + Iterator it = Collections.EMPTY_LIST.iterator(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue1"); + queryControl.setReturnValue(query, 1); + query.setParameter(1, new Integer(2)); + queryControl.setReturnValue(query, 1); + query.iterate(); + queryControl.setReturnValue(it, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + Iterator result = ht.iterate("some query string", + new Object[] {"myvalue1", new Integer(2)}); + assertTrue("Correct list", result == it); + sfControl.verify(); + } + + public void testBulkUpdate() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.executeUpdate(); + queryControl.setReturnValue(5, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + int result = ht.bulkUpdate("some query string"); + assertTrue("Correct list", result == 5); + queryControl.verify(); + } + + public void testBulkUpdateWithParameter() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue"); + queryControl.setReturnValue(query, 1); + query.executeUpdate(); + queryControl.setReturnValue(5, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + int result = ht.bulkUpdate("some query string", "myvalue"); + assertTrue("Correct list", result == 5); + queryControl.verify(); + } + + public void testBulkUpdateWithParameters() throws HibernateException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.setParameter(0, "myvalue1"); + queryControl.setReturnValue(query, 1); + query.setParameter(1, new Integer(2)); + queryControl.setReturnValue(query, 1); + query.executeUpdate(); + queryControl.setReturnValue(5, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + queryControl.replay(); + + HibernateTemplate ht = new HibernateTemplate(sf); + int result = ht.bulkUpdate("some query string", + new Object[] {"myvalue1", new Integer(2)}); + assertTrue("Correct list", result == 5); + queryControl.verify(); + } + + public void testExceptions() throws HibernateException { + SQLException sqlEx = new SQLException("argh", "27"); + + final JDBCConnectionException jcex = new JDBCConnectionException("mymsg", sqlEx); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw jcex; + } + }); + fail("Should have thrown DataAccessResourceFailureException"); + } + catch (DataAccessResourceFailureException ex) { + // expected + assertEquals(jcex, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + final SQLGrammarException sgex = new SQLGrammarException("mymsg", sqlEx); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw sgex; + } + }); + fail("Should have thrown InvalidDataAccessResourceUsageException"); + } + catch (InvalidDataAccessResourceUsageException ex) { + // expected + assertEquals(sgex, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + final LockAcquisitionException laex = new LockAcquisitionException("mymsg", sqlEx); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw laex; + } + }); + fail("Should have thrown CannotAcquireLockException"); + } + catch (CannotAcquireLockException ex) { + // expected + assertEquals(laex, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + final ConstraintViolationException cvex = new ConstraintViolationException("mymsg", sqlEx, "myconstraint"); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw cvex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(cvex, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + final DataException dex = new DataException("mymsg", sqlEx); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw dex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(dex, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + final JDBCException jdex = new JDBCException("mymsg", sqlEx); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw jdex; + } + }); + fail("Should have thrown HibernateJdbcException"); + } + catch (HibernateJdbcException ex) { + // expected + assertEquals(jdex, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + final PropertyValueException pvex = new PropertyValueException("mymsg", "myentity", "myproperty"); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw pvex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(pvex, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw new PersistentObjectException(""); + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw new TransientObjectException(""); + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + + final ObjectDeletedException odex = new ObjectDeletedException("msg", "id", TestBean.class.getName()); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw odex; + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + assertEquals(odex, ex.getCause()); + } + + final QueryException qex = new QueryException("msg"); + qex.setQueryString("query"); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw qex; + } + }); + fail("Should have thrown InvalidDataAccessResourceUsageException"); + } + catch (HibernateQueryException ex) { + // expected + assertEquals(qex, ex.getCause()); + assertEquals("query", ex.getQueryString()); + } + + final UnresolvableObjectException uoex = new UnresolvableObjectException("id", TestBean.class.getName()); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw uoex; + } + }); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(uoex, ex.getCause()); + } + + final ObjectNotFoundException onfe = new ObjectNotFoundException("id", TestBean.class.getName()); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw onfe; + } + }); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(onfe, ex.getCause()); + } + + final WrongClassException wcex = new WrongClassException("msg", "id", TestBean.class.getName()); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw wcex; + } + }); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(wcex, ex.getCause()); + } + + final NonUniqueResultException nuex = new NonUniqueResultException(2); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw nuex; + } + }); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(-1, ex.getActualSize()); + } + + final StaleObjectStateException sosex = new StaleObjectStateException(TestBean.class.getName(), "id"); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw sosex; + } + }); + fail("Should have thrown HibernateOptimisticLockingFailureException"); + } + catch (HibernateOptimisticLockingFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(sosex, ex.getCause()); + } + + final StaleStateException ssex = new StaleStateException("msg"); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw ssex; + } + }); + fail("Should have thrown HibernateOptimisticLockingFailureException"); + } + catch (HibernateOptimisticLockingFailureException ex) { + // expected + assertNull(ex.getPersistentClassName()); + assertNull(ex.getIdentifier()); + assertEquals(ssex, ex.getCause()); + } + + final HibernateException hex = new HibernateException("msg"); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw hex; + } + }); + fail("Should have thrown HibernateSystemException"); + } + catch (HibernateSystemException ex) { + // expected + assertEquals(hex, ex.getCause()); + } + } + + public void testFallbackExceptionTranslation() throws HibernateException { + SQLException sqlEx = new SQLException("argh", "27"); + + final GenericJDBCException gjex = new GenericJDBCException("mymsg", sqlEx); + try { + createTemplate().execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + throw gjex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(sqlEx, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + } + + private HibernateTemplate createTemplate() throws HibernateException { + sfControl.reset(); + sessionControl.reset(); + sf.openSession(); + sfControl.setReturnValue(session); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + return new HibernateTemplate(sf); + } + + protected void tearDown() { + try { + sfControl.verify(); + sessionControl.verify(); + } + catch (IllegalStateException ex) { + // ignore: test method didn't call replay + } + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java new file mode 100644 index 00000000000..300061e0205 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java @@ -0,0 +1,1789 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.sql.Savepoint; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import javax.sql.DataSource; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.Query; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cache.NoCacheProvider; +import org.hibernate.cfg.Configuration; +import org.hibernate.classic.Session; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.GenericJDBCException; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.jdbc.datasource.ConnectionHolder; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; +import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; +import org.springframework.transaction.CannotCreateTransactionException; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.UnexpectedRollbackException; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class HibernateTransactionManagerTests extends TestCase { + + public void testTransactionCommit() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + final List list = new ArrayList(); + list.add("test"); + con.getTransactionIsolation(); + conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED); + con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); + conControl.setVoidCallable(1); + con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getTransaction(); + sessionControl.setReturnValue(tx, 1); + tx.setTimeout(10); + txControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + session.connection(); + sessionControl.setReturnValue(con, 3); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + tx.commit(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + + dsControl.replay(); + conControl.replay(); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + queryControl.replay(); + + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { + protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + return sf; + } + }; + lsfb.afterPropertiesSet(); + final SessionFactory sfProxy = (SessionFactory) lsfb.getObject(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setJdbcExceptionTranslator(new SQLStateSQLExceptionTranslator()); + tm.setSessionFactory(sfProxy); + tm.setDataSource(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + HibernateTemplate ht = new HibernateTemplate(sfProxy); + return ht.find("some query string"); + } + }); + assertTrue("Correct result list", result == list); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + dsControl.verify(); + conControl.verify(); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + queryControl.verify(); + } + + public void testTransactionRollback() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + tx.rollback(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sf); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + throw new RuntimeException("application exception"); + } + }); + } + }); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException ex) { + // expected + } + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + } + + public void testTransactionRollbackOnly() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + tx.rollback(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sf); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return null; + } + }); + status.setRollbackOnly(); + return null; + } + }); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + } + + public void testTransactionCommitWithEarlyFlush() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + final List list = new ArrayList(); + list.add("test"); + con.getTransactionIsolation(); + conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED); + con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); + conControl.setVoidCallable(1); + con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + conControl.setVoidCallable(1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getTransaction(); + sessionControl.setReturnValue(tx, 1); + tx.setTimeout(10); + txControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + session.connection(); + sessionControl.setReturnValue(con, 3); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + tx.commit(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + + dsControl.replay(); + conControl.replay(); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + queryControl.replay(); + + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { + protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + return sf; + } + }; + lsfb.afterPropertiesSet(); + final SessionFactory sfProxy = (SessionFactory) lsfb.getObject(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setJdbcExceptionTranslator(new SQLStateSQLExceptionTranslator()); + tm.setSessionFactory(sfProxy); + tm.setDataSource(ds); + tm.setEarlyFlushBeforeCommit(true); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + HibernateTemplate ht = new HibernateTemplate(sfProxy); + return ht.find("some query string"); + } + }); + assertTrue("Correct result list", result == list); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + dsControl.verify(); + conControl.verify(); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + queryControl.verify(); + } + + public void testParticipatingTransactionWithCommit() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.flush(); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + tx.commit(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { + protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + return sf; + } + }; + lsfb.afterPropertiesSet(); + final SessionFactory sfProxy = (SessionFactory) lsfb.getObject(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy); + final TransactionTemplate tt = new TransactionTemplate(tm); + final List l = new ArrayList(); + l.add("test"); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + HibernateTemplate ht = new HibernateTemplate(sfProxy); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return l; + } + }); + } + }); + } + }); + assertTrue("Correct result list", result == l); + + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithRollback() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + tx.rollback(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sf); + final TransactionTemplate tt = new TransactionTemplate(tm); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + throw new RuntimeException("application exception"); + } + }); + } + }); + } + }); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException ex) { + // expected + } + + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithRollbackOnly() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + tx.rollback(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sf); + final TransactionTemplate tt = new TransactionTemplate(tm); + final List l = new ArrayList(); + l.add("test"); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + HibernateTemplate ht = new HibernateTemplate(sf); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return l; + } + }); + status.setRollbackOnly(); + return null; + } + }); + } + }); + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + } + + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithWithRequiresNew() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl session1Control = MockControl.createControl(Session.class); + Session session1 = (Session) session1Control.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + Session session2 = (Session) session2Control.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session1, 1); + sf.openSession(); + sfControl.setReturnValue(session2, 1); + session1.beginTransaction(); + session1Control.setReturnValue(tx, 1); + session1.isOpen(); + session1Control.setReturnValue(true, 1); + session2.beginTransaction(); + session2Control.setReturnValue(tx, 1); + session2.isOpen(); + session2Control.setReturnValue(true, 1); + session2.getFlushMode(); + session2Control.setReturnValue(FlushMode.AUTO, 1); + session2.flush(); + session2Control.setVoidCallable(1); + session1.close(); + session1Control.setReturnValue(null, 1); + session2.close(); + session2Control.setReturnValue(null, 1); + tx.commit(); + txControl.setVoidCallable(2); + session1.isConnected(); + session1Control.setReturnValue(true, 1); + session1.connection(); + session1Control.setReturnValue(con, 2); + session2.isConnected(); + session2Control.setReturnValue(true, 1); + session2.connection(); + session2Control.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 2); + + sfControl.replay(); + session1Control.replay(); + session2Control.replay(); + conControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sf); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + final SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + assertTrue("Not enclosing session", session != holder.getSession()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + return null; + } + }); + } + }); + assertTrue("Same thread session as before", + holder.getSession() == SessionFactoryUtils.getSession(sf, false)); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + sfControl.verify(); + session1Control.verify(); + session2Control.verify(); + conControl.verify(); + txControl.verify(); + } + + public void testParticipatingTransactionWithWithNotSupported() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 2); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.AUTO, 2); + session.flush(); + sessionControl.setVoidCallable(2); + session.close(); + sessionControl.setReturnValue(null, 2); + tx.commit(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + + sfControl.replay(); + sessionControl.replay(); + conControl.replay(); + txControl.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(sf); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return null; + } + }); + } + }); + assertTrue("Same thread session as before", + holder.getSession() == SessionFactoryUtils.getSession(sf, false)); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + } + + public void testTransactionWithPropagationSupports() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + session.flush(); + sessionControl.setVoidCallable(1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { + protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + return sf; + } + }; + lsfb.afterPropertiesSet(); + final SessionFactory sfProxy = (SessionFactory) lsfb.getObject(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + HibernateTemplate ht = new HibernateTemplate(sfProxy); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + return null; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sfProxy)); + return null; + } + }); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + sfControl.verify(); + sessionControl.verify(); + } + + public void testTransactionWithPropagationSupportsAndInnerTransaction() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl session1Control = MockControl.createControl(Session.class); + final Session session1 = (Session) session1Control.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session1, 1); + session1.getSessionFactory(); + session1Control.setReturnValue(sf, 1); + session1.getFlushMode(); + session1Control.setReturnValue(FlushMode.AUTO, 2); + session1.flush(); + session1Control.setVoidCallable(2); + session1.disconnect(); + session1Control.setReturnValue(null, 1); + session1.close(); + session1Control.setReturnValue(null, 1); + + sf.openSession(); + sfControl.setReturnValue(session2, 1); + session2.beginTransaction(); + session2Control.setReturnValue(tx, 1); + session2.connection(); + session2Control.setReturnValue(con, 2); + session2.getFlushMode(); + session2Control.setReturnValue(FlushMode.AUTO, 1); + session2.flush(); + session2Control.setVoidCallable(1); + session2.isOpen(); + session2Control.setReturnValue(true, 1); + tx.commit(); + txControl.setVoidCallable(1); + session2.isConnected(); + session2Control.setReturnValue(true, 1); + session2.close(); + session2Control.setReturnValue(null, 1); + sfControl.replay(); + session1Control.replay(); + session2Control.replay(); + txControl.replay(); + + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { + protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + return sf; + } + }; + lsfb.afterPropertiesSet(); + final SessionFactory sfProxy = (SessionFactory) lsfb.getObject(); + + PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + final TransactionTemplate tt2 = new TransactionTemplate(tm); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); + + final HibernateTemplate ht = new HibernateTemplate(sfProxy); + ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); + ht.setExposeNativeSession(true); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + assertSame(session1, session); + return null; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sfProxy)); + tt2.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) { + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertSame(session2, session); + return null; + } + }); + } + }); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + sfControl.verify(); + session1Control.verify(); + session2Control.verify(); + txControl.verify(); + } + + public void testTransactionCommitWithEntityInterceptor() throws Exception { + MockControl interceptorControl = MockControl.createControl(org.hibernate.Interceptor.class); + Interceptor entityInterceptor = (Interceptor) interceptorControl.getMock(); + interceptorControl.replay(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(entityInterceptor); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + tx.commit(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + conControl.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(sf); + tm.setEntityInterceptor(entityInterceptor); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + interceptorControl.verify(); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + conControl.verify(); + } + + public void testTransactionCommitWithEntityInterceptorBeanName() throws Exception { + MockControl interceptorControl = MockControl.createControl(org.hibernate.Interceptor.class); + Interceptor entityInterceptor = (Interceptor) interceptorControl.getMock(); + interceptorControl.replay(); + MockControl interceptor2Control = MockControl.createControl(org.hibernate.Interceptor.class); + Interceptor entityInterceptor2 = (Interceptor) interceptor2Control.getMock(); + interceptor2Control.replay(); + + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(entityInterceptor); + sfControl.setReturnValue(session, 1); + sf.openSession(entityInterceptor2); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 2); + session.isOpen(); + sessionControl.setReturnValue(true, 2); + session.close(); + sessionControl.setReturnValue(null, 2); + tx.commit(); + txControl.setVoidCallable(2); + session.isConnected(); + sessionControl.setReturnValue(true, 2); + session.connection(); + sessionControl.setReturnValue(con, 4); + con.isReadOnly(); + conControl.setReturnValue(false, 2); + + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + conControl.replay(); + + MockControl beanFactoryControl = MockControl.createControl(BeanFactory.class); + BeanFactory beanFactory = (BeanFactory) beanFactoryControl.getMock(); + beanFactory.getBean("entityInterceptor", Interceptor.class); + beanFactoryControl.setReturnValue(entityInterceptor, 1); + beanFactory.getBean("entityInterceptor", Interceptor.class); + beanFactoryControl.setReturnValue(entityInterceptor2, 1); + beanFactoryControl.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(sf); + tm.setEntityInterceptorBeanName("entityInterceptor"); + tm.setBeanFactory(beanFactory); + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + for (int i = 0; i < 2; i++) { + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return null; + } + }); + } + }); + } + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + interceptorControl.verify(); + interceptor2Control.verify(); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + conControl.verify(); + beanFactoryControl.verify(); + } + + public void testTransactionCommitWithReadOnly() throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + final List list = new ArrayList(); + list.add("test"); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.setReadOnly(true); + conControl.setVoidCallable(1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + tx.commit(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + con.isReadOnly(); + conControl.setReturnValue(true, 1); + con.setReadOnly(false); + conControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + + conControl.replay(); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + queryControl.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(sf); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setReadOnly(true); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.find("some query string"); + } + }); + assertTrue("Correct result list", result == list); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + conControl.verify(); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + queryControl.verify(); + } + + public void testTransactionCommitWithFlushFailure() throws Exception { + doTestTransactionCommitWithFlushFailure(false); + } + + public void testTransactionCommitWithFlushFailureAndFallbackTranslation() throws Exception { + doTestTransactionCommitWithFlushFailure(true); + } + + private void doTestTransactionCommitWithFlushFailure(boolean fallbackTranslation) throws Exception { + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + tx.commit(); + SQLException sqlEx = new SQLException("argh", "27"); + Exception rootCause = null; + if (fallbackTranslation) { + GenericJDBCException jdbcEx = new GenericJDBCException("mymsg", sqlEx); + txControl.setThrowable(jdbcEx, 1); + rootCause = sqlEx; + } + else { + ConstraintViolationException jdbcEx = new ConstraintViolationException("mymsg", sqlEx, null); + txControl.setThrowable(jdbcEx, 1); + rootCause = jdbcEx; + } + session.close(); + sessionControl.setReturnValue(null, 1); + tx.rollback(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.connection(); + sessionControl.setReturnValue(con, 2); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + conControl.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(sf); + TransactionTemplate tt = new TransactionTemplate(tm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session session) throws HibernateException { + return l; + } + }); + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(rootCause, ex.getCause()); + assertTrue(ex.getMessage().indexOf("mymsg") != -1); + } + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + conControl.verify(); + } + + public void testTransactionCommitWithPreBound() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.connection(); + sessionControl.setReturnValue(con, 3); + con.getTransactionIsolation(); + conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED); + con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); + conControl.setVoidCallable(1); + con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + conControl.setVoidCallable(1); + tx.commit(); + txControl.setVoidCallable(1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + session.disconnect(); + sessionControl.setReturnValue(null, 1); + + dsControl.replay(); + conControl.replay(); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setSessionFactory(sf); + tm.setDataSource(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread transaction", sessionHolder.getTransaction() != null); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + return ht.executeFind(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertEquals(session, sess); + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null); + TransactionSynchronizationManager.unbindResource(sf); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + dsControl.verify(); + conControl.verify(); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + } + + public void testTransactionRollbackWithPreBound() throws Exception { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl tx1Control = MockControl.createControl(Transaction.class); + final Transaction tx1 = (Transaction) tx1Control.getMock(); + MockControl tx2Control = MockControl.createControl(Transaction.class); + final Transaction tx2 = (Transaction) tx2Control.getMock(); + + session.beginTransaction(); + sessionControl.setReturnValue(tx1, 1); + tx1.rollback(); + tx1Control.setVoidCallable(1); + session.clear(); + sessionControl.setVoidCallable(1); + session.beginTransaction(); + sessionControl.setReturnValue(tx2, 1); + tx2.commit(); + tx2Control.setVoidCallable(1); + + session.isOpen(); + sessionControl.setReturnValue(true, 2); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 2); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(2); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(2); + session.isConnected(); + sessionControl.setReturnValue(true, 2); + session.connection(); + sessionControl.setReturnValue(con, 6); + con.isReadOnly(); + conControl.setReturnValue(false, 2); + session.disconnect(); + sessionControl.setReturnValue(null, 2); + + dsControl.replay(); + conControl.replay(); + sfControl.replay(); + sessionControl.replay(); + tx1Control.replay(); + tx2Control.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setSessionFactory(sf); + tm.setDataSource(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + + try { + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertEquals(tx1, sessionHolder.getTransaction()); + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + status.setRollbackOnly(); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertEquals(session, sess); + return null; + } + }); + } + }); + } + }); + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + } + + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null); + assertTrue("Not marked rollback-only", !sessionHolder.isRollbackOnly()); + + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertEquals(tx2, sessionHolder.getTransaction()); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setExposeNativeSession(true); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertEquals(session, sess); + return null; + } + }); + } + }); + + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null); + TransactionSynchronizationManager.unbindResource(sf); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + dsControl.verify(); + conControl.verify(); + sfControl.verify(); + sessionControl.verify(); + tx1Control.verify(); + tx2Control.verify(); + } + + public void testTransactionRollbackWithHibernateManagedSession() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl tx1Control = MockControl.createControl(Transaction.class); + final Transaction tx1 = (Transaction) tx1Control.getMock(); + MockControl tx2Control = MockControl.createControl(Transaction.class); + final Transaction tx2 = (Transaction) tx2Control.getMock(); + + sf.getCurrentSession(); + sfControl.setReturnValue(session, 2); + session.isOpen(); + sessionControl.setReturnValue(true, 2); + session.getTransaction(); + sessionControl.setReturnValue(tx1, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx1, 1); + tx1.isActive(); + tx1Control.setReturnValue(false, 1); + tx1.rollback(); + tx1Control.setVoidCallable(1); + session.getTransaction(); + sessionControl.setReturnValue(tx2, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx2, 1); + tx2.isActive(); + tx2Control.setReturnValue(false, 1); + tx2.commit(); + tx2Control.setVoidCallable(1); + + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 2); + session.setFlushMode(FlushMode.AUTO); + sessionControl.setVoidCallable(2); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(2); + + sfControl.replay(); + sessionControl.replay(); + tx1Control.replay(); + tx2Control.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setSessionFactory(sf); + tm.setPrepareConnection(false); + tm.setHibernateManagedSession(true); + final TransactionTemplate tt = new TransactionTemplate(tm); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + try { + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + status.setRollbackOnly(); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setAllowCreate(false); + ht.setExposeNativeSession(true); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertEquals(session, sess); + return null; + } + }); + } + }); + } + }); + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + } + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + tt.execute(new TransactionCallbackWithoutResult() { + public void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + HibernateTemplate ht = new HibernateTemplate(sf); + ht.setAllowCreate(false); + ht.setExposeNativeSession(true); + ht.execute(new HibernateCallback() { + public Object doInHibernate(org.hibernate.Session sess) throws HibernateException { + assertEquals(session, sess); + return null; + } + }); + } + }); + + sfControl.verify(); + sessionControl.verify(); + tx1Control.verify(); + tx2Control.verify(); + } + + public void testExistingTransactionWithPropagationNestedAndRollback() throws Exception { + doTestExistingTransactionWithPropagationNestedAndRollback(false); + } + + public void testExistingTransactionWithManualSavepointAndRollback() throws Exception { + doTestExistingTransactionWithPropagationNestedAndRollback(true); + } + + private void doTestExistingTransactionWithPropagationNestedAndRollback(final boolean manualSavepoint) + throws Exception { + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); + MockControl spControl = MockControl.createControl(Savepoint.class); + Savepoint sp = (Savepoint) spControl.getMock(); + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + final List list = new ArrayList(); + list.add("test"); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.beginTransaction(); + sessionControl.setReturnValue(tx, 1); + session.connection(); + sessionControl.setReturnValue(con, 3); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + md.supportsSavepoints(); + mdControl.setReturnValue(true, 1); + con.getMetaData(); + conControl.setReturnValue(md, 1); + con.setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1); + conControl.setReturnValue(sp, 1); + con.rollback(sp); + conControl.setVoidCallable(1); + session.createQuery("some query string"); + sessionControl.setReturnValue(query, 1); + query.list(); + queryControl.setReturnValue(list, 1); + session.isConnected(); + sessionControl.setReturnValue(true, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + tx.commit(); + txControl.setVoidCallable(1); + + dsControl.replay(); + conControl.replay(); + mdControl.replay(); + spControl.replay(); + sfControl.replay(); + sessionControl.replay(); + txControl.replay(); + queryControl.replay(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setJdbcExceptionTranslator(new SQLStateSQLExceptionTranslator()); + tm.setNestedTransactionAllowed(true); + tm.setSessionFactory(sf); + tm.setDataSource(ds); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + if (manualSavepoint) { + Object savepoint = status.createSavepoint(); + status.rollbackToSavepoint(savepoint); + } + else { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + status.setRollbackOnly(); + } + }); + } + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.find("some query string"); + } + }); + assertTrue("Correct result list", result == list); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + dsControl.verify(); + conControl.verify(); + mdControl.verify(); + spControl.verify(); + sfControl.verify(); + sessionControl.verify(); + txControl.verify(); + queryControl.verify(); + } + + public void testTransactionCommitWithNonExistingDatabase() throws Exception { + final DriverManagerDataSource ds = new DriverManagerDataSource(); + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean(); + lsfb.setDataSource(ds); + Properties props = new Properties(); + props.setProperty("hibernate.dialect", HSQLDialect.class.getName()); + props.setProperty("hibernate.cache.provider_class", NoCacheProvider.class.getName()); + lsfb.setHibernateProperties(props); + lsfb.afterPropertiesSet(); + final SessionFactory sf = (SessionFactory) lsfb.getObject(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setSessionFactory(sf); + tm.afterPropertiesSet(); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.find("from java.lang.Object"); + } + }); + fail("Should have thrown CannotCreateTransactionException"); + } + catch (CannotCreateTransactionException ex) { + // expected + } + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + public void testTransactionCommitWithPreBoundSessionAndNonExistingDatabase() throws Exception { + final DriverManagerDataSource ds = new DriverManagerDataSource(); + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean(); + lsfb.setDataSource(ds); + Properties props = new Properties(); + props.setProperty("hibernate.dialect", HSQLDialect.class.getName()); + props.setProperty("hibernate.cache.provider_class", NoCacheProvider.class.getName()); + lsfb.setHibernateProperties(props); + lsfb.afterPropertiesSet(); + final SessionFactory sf = (SessionFactory) lsfb.getObject(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setSessionFactory(sf); + tm.afterPropertiesSet(); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Session session = sf.openSession(); + TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.find("from java.lang.Object"); + } + }); + fail("Should have thrown CannotCreateTransactionException"); + } + catch (CannotCreateTransactionException ex) { + // expected + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertFalse(holder.isSynchronizedWithTransaction()); + } + finally { + TransactionSynchronizationManager.unbindResource(sf); + session.close(); + } + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + public void testTransactionCommitWithNonExistingDatabaseAndLazyConnection() throws Exception { + DriverManagerDataSource dsTarget = new DriverManagerDataSource(); + final LazyConnectionDataSourceProxy ds = new LazyConnectionDataSourceProxy(); + ds.setTargetDataSource(dsTarget); + ds.setDefaultAutoCommit(true); + ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + //ds.setDefaultTransactionIsolationName("TRANSACTION_READ_COMMITTED"); + + LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean(); + lsfb.setDataSource(ds); + Properties props = new Properties(); + props.setProperty("hibernate.dialect", HSQLDialect.class.getName()); + props.setProperty("hibernate.cache.provider_class", NoCacheProvider.class.getName()); + lsfb.setHibernateProperties(props); + lsfb.afterPropertiesSet(); + final SessionFactory sf = (SessionFactory) lsfb.getObject(); + + HibernateTransactionManager tm = new HibernateTransactionManager(); + tm.setSessionFactory(sf); + tm.afterPropertiesSet(); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + HibernateTemplate ht = new HibernateTemplate(sf); + return ht.find("from java.lang.Object"); + } + }); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java new file mode 100644 index 00000000000..73286384b03 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java @@ -0,0 +1,588 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.transaction.TransactionManager; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.SessionFactory; +import org.hibernate.cache.CacheProvider; +import org.hibernate.cache.NoCacheProvider; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.cfg.ImprovedNamingStrategy; +import org.hibernate.cfg.Mappings; +import org.hibernate.cfg.NamingStrategy; +import org.hibernate.connection.UserSuppliedConnectionProvider; +import org.hibernate.engine.FilterDefinition; +import org.hibernate.event.MergeEvent; +import org.hibernate.event.MergeEventListener; +import org.hibernate.mapping.TypeDef; + +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class LocalSessionFactoryBeanTests extends TestCase { + + public void testLocalSessionFactoryBeanWithDataSource() throws Exception { + final DriverManagerDataSource ds = new DriverManagerDataSource(); + final List invocations = new ArrayList(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration addInputStream(InputStream is) { + try { + is.close(); + } + catch (IOException ex) { + } + invocations.add("addResource"); + return this; + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + assertEquals(LocalDataSourceConnectionProvider.class.getName(), + config.getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + invocations.add("newSessionFactory"); + return null; + } + }; + sfb.setDataSource(ds); + sfb.afterPropertiesSet(); + assertTrue(sfb.getConfiguration() != null); + assertEquals("newSessionFactory", invocations.get(0)); + } + + public void testLocalSessionFactoryBeanWithCacheProvider() throws Exception { + final CacheProvider cacheProvider = new NoCacheProvider(); + final List invocations = new ArrayList(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration addInputStream(InputStream is) { + try { + is.close(); + } + catch (IOException ex) { + } + invocations.add("addResource"); + return this; + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + assertEquals(LocalCacheProviderProxy.class.getName(), + config.getProperty(Environment.CACHE_PROVIDER)); + assertSame(cacheProvider, LocalSessionFactoryBean.getConfigTimeCacheProvider()); + invocations.add("newSessionFactory"); + return null; + } + }; + sfb.setCacheProvider(cacheProvider); + sfb.afterPropertiesSet(); + assertTrue(sfb.getConfiguration() != null); + assertEquals("newSessionFactory", invocations.get(0)); + } + + public void testLocalSessionFactoryBeanWithTransactionAwareDataSource() throws Exception { + final DriverManagerDataSource ds = new DriverManagerDataSource(); + final List invocations = new ArrayList(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration addInputStream(InputStream is) { + try { + is.close(); + } + catch (IOException ex) { + } + invocations.add("addResource"); + return this; + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + assertEquals(TransactionAwareDataSourceConnectionProvider.class.getName(), + config.getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + invocations.add("newSessionFactory"); + return null; + } + }; + sfb.setDataSource(ds); + sfb.setUseTransactionAwareDataSource(true); + sfb.afterPropertiesSet(); + assertTrue(sfb.getConfiguration() != null); + assertEquals("newSessionFactory", invocations.get(0)); + } + + public void testLocalSessionFactoryBeanWithDataSourceAndMappingResources() throws Exception { + final DriverManagerDataSource ds = new DriverManagerDataSource(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + final TransactionManager tm = (TransactionManager) tmControl.getMock(); + final List invocations = new ArrayList(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration addInputStream(InputStream is) { + try { + is.close(); + } + catch (IOException ex) { + } + invocations.add("addResource"); + return this; + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + assertEquals(LocalJtaDataSourceConnectionProvider.class.getName(), + config.getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + assertEquals(LocalTransactionManagerLookup.class.getName(), + config.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY)); + assertEquals(tm, LocalSessionFactoryBean.getConfigTimeTransactionManager()); + invocations.add("newSessionFactory"); + return null; + } + }; + sfb.setMappingResources(new String[]{ + "/org/springframework/beans/factory/xml/test.xml", + "/org/springframework/beans/factory/xml/child.xml"}); + sfb.setDataSource(ds); + sfb.setJtaTransactionManager(tm); + sfb.afterPropertiesSet(); + assertTrue(sfb.getConfiguration() != null); + assertEquals("addResource", invocations.get(0)); + assertEquals("addResource", invocations.get(1)); + assertEquals("newSessionFactory", invocations.get(2)); + } + + public void testLocalSessionFactoryBeanWithDataSourceAndMappingJarLocations() throws Exception { + final DriverManagerDataSource ds = new DriverManagerDataSource(); + final Set invocations = new HashSet(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration addJar(File file) { + invocations.add("addResource " + file.getPath()); + return this; + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + assertEquals(LocalDataSourceConnectionProvider.class.getName(), + config.getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + invocations.add("newSessionFactory"); + return null; + } + }; + sfb.setMappingJarLocations(new Resource[]{ + new FileSystemResource("mapping.hbm.jar"), new FileSystemResource("mapping2.hbm.jar")}); + sfb.setDataSource(ds); + sfb.afterPropertiesSet(); + assertTrue(sfb.getConfiguration() != null); + assertTrue(invocations.contains("addResource mapping.hbm.jar")); + assertTrue(invocations.contains("addResource mapping2.hbm.jar")); + assertTrue(invocations.contains("newSessionFactory")); + } + + public void testLocalSessionFactoryBeanWithDataSourceAndProperties() throws Exception { + final DriverManagerDataSource ds = new DriverManagerDataSource(); + final Set invocations = new HashSet(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration addInputStream(InputStream is) { + try { + is.close(); + } + catch (IOException ex) { + } + invocations.add("addResource"); + return this; + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + assertEquals(LocalDataSourceConnectionProvider.class.getName(), + config.getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + assertEquals("myValue", config.getProperty("myProperty")); + invocations.add("newSessionFactory"); + return null; + } + }; + sfb.setMappingLocations(new Resource[]{ + new ClassPathResource("/org/springframework/beans/factory/xml/test.xml")}); + sfb.setDataSource(ds); + Properties prop = new Properties(); + prop.setProperty(Environment.CONNECTION_PROVIDER, "myClass"); + prop.setProperty("myProperty", "myValue"); + sfb.setHibernateProperties(prop); + sfb.afterPropertiesSet(); + assertTrue(sfb.getConfiguration() != null); + assertTrue(invocations.contains("addResource")); + assertTrue(invocations.contains("newSessionFactory")); + } + + public void testLocalSessionFactoryBeanWithValidProperties() throws Exception { + final Set invocations = new HashSet(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected SessionFactory newSessionFactory(Configuration config) { + assertEquals(UserSuppliedConnectionProvider.class.getName(), + config.getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals("myValue", config.getProperty("myProperty")); + invocations.add("newSessionFactory"); + return null; + } + }; + Properties prop = new Properties(); + prop.setProperty(Environment.CONNECTION_PROVIDER, UserSuppliedConnectionProvider.class.getName()); + prop.setProperty("myProperty", "myValue"); + sfb.setHibernateProperties(prop); + sfb.afterPropertiesSet(); + assertTrue(sfb.getConfiguration() != null); + assertTrue(invocations.contains("newSessionFactory")); + } + + public void testLocalSessionFactoryBeanWithInvalidProperties() throws Exception { + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean(); + sfb.setMappingResources(new String[0]); + Properties prop = new Properties(); + prop.setProperty(Environment.CONNECTION_PROVIDER, "myClass"); + sfb.setHibernateProperties(prop); + try { + sfb.afterPropertiesSet(); + } + catch (HibernateException ex) { + // expected, provider class not found + } + } + + public void testLocalSessionFactoryBeanWithInvalidMappings() throws Exception { + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean(); + sfb.setMappingResources(new String[]{"mapping.hbm.xml"}); + try { + sfb.afterPropertiesSet(); + } + catch (IOException ex) { + // expected, mapping resource not found + } + } + + public void testLocalSessionFactoryBeanWithCustomSessionFactory() throws Exception { + MockControl factoryControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sessionFactory = (SessionFactory) factoryControl.getMock(); + sessionFactory.close(); + factoryControl.setVoidCallable(1); + factoryControl.replay(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected SessionFactory newSessionFactory(Configuration config) { + return sessionFactory; + } + }; + sfb.setMappingResources(new String[0]); + sfb.setDataSource(new DriverManagerDataSource()); + sfb.setExposeTransactionAwareSessionFactory(false); + sfb.afterPropertiesSet(); + assertTrue(sessionFactory == sfb.getObject()); + sfb.destroy(); + factoryControl.verify(); + } + + public void testLocalSessionFactoryBeanWithEntityInterceptor() throws Exception { + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration setInterceptor(Interceptor interceptor) { + throw new IllegalArgumentException(interceptor.toString()); + } + }; + } + }; + sfb.setMappingResources(new String[0]); + sfb.setDataSource(new DriverManagerDataSource()); + MockControl interceptorControl = MockControl.createControl(Interceptor.class); + Interceptor entityInterceptor = (Interceptor) interceptorControl.getMock(); + interceptorControl.replay(); + sfb.setEntityInterceptor(entityInterceptor); + try { + sfb.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + assertTrue("Correct exception", ex.getMessage().equals(entityInterceptor.toString())); + } + } + + public void testLocalSessionFactoryBeanWithNamingStrategy() throws Exception { + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration setNamingStrategy(NamingStrategy namingStrategy) { + throw new IllegalArgumentException(namingStrategy.toString()); + } + }; + } + }; + sfb.setMappingResources(new String[0]); + sfb.setDataSource(new DriverManagerDataSource()); + sfb.setNamingStrategy(ImprovedNamingStrategy.INSTANCE); + try { + sfb.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + assertTrue("Correct exception", ex.getMessage().equals(ImprovedNamingStrategy.INSTANCE.toString())); + } + } + + public void testLocalSessionFactoryBeanWithCacheStrategies() throws Exception { + final Properties registeredClassCache = new Properties(); + final Properties registeredCollectionCache = new Properties(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public Configuration setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy) { + registeredClassCache.setProperty(clazz, concurrencyStrategy); + return this; + } + + public Configuration setCollectionCacheConcurrencyStrategy(String collectionRole, String concurrencyStrategy) { + registeredCollectionCache.setProperty(collectionRole, concurrencyStrategy); + return this; + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + return null; + } + }; + + sfb.setMappingResources(new String[0]); + sfb.setDataSource(new DriverManagerDataSource()); + Properties classCache = new Properties(); + classCache.setProperty("org.springframework.beans.TestBean", "read-write"); + sfb.setEntityCacheStrategies(classCache); + Properties collectionCache = new Properties(); + collectionCache.setProperty("org.springframework.beans.TestBean.friends", "read-only"); + sfb.setCollectionCacheStrategies(collectionCache); + sfb.afterPropertiesSet(); + + assertEquals(classCache, registeredClassCache); + assertEquals(collectionCache, registeredCollectionCache); + } + + public void testLocalSessionFactoryBeanWithCacheStrategiesAndRegions() throws Exception { + final Properties registeredClassCache = new Properties(); + final Properties registeredCollectionCache = new Properties(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public void setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy, String regionName) { + registeredClassCache.setProperty(clazz, concurrencyStrategy + "," + regionName); + } + + public void setCollectionCacheConcurrencyStrategy(String collectionRole, String concurrencyStrategy, String regionName) { + registeredCollectionCache.setProperty(collectionRole, concurrencyStrategy + "," + regionName); + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + return null; + } + }; + + sfb.setMappingResources(new String[0]); + sfb.setDataSource(new DriverManagerDataSource()); + Properties classCache = new Properties(); + classCache.setProperty("org.springframework.beans.TestBean", "read-write,myRegion"); + sfb.setEntityCacheStrategies(classCache); + Properties collectionCache = new Properties(); + collectionCache.setProperty("org.springframework.beans.TestBean.friends", "read-only,myRegion"); + sfb.setCollectionCacheStrategies(collectionCache); + sfb.afterPropertiesSet(); + + assertEquals(classCache, registeredClassCache); + assertEquals(collectionCache, registeredCollectionCache); + } + + public void testLocalSessionFactoryBeanWithEventListeners() throws Exception { + final Map registeredListeners = new HashMap(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public void setListener(String type, Object listener) { + registeredListeners.put(type, listener); + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + return null; + } + }; + sfb.setMappingResources(new String[0]); + sfb.setDataSource(new DriverManagerDataSource()); + Map listeners = new HashMap(); + listeners.put("flush", "myListener"); + listeners.put("create", "yourListener"); + sfb.setEventListeners(listeners); + sfb.afterPropertiesSet(); + assertEquals(listeners, registeredListeners); + } + + public void testLocalSessionFactoryBeanWithEventListenerSet() throws Exception { + final Map registeredListeners = new HashMap(); + LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + protected Configuration newConfiguration() { + return new Configuration() { + public void setListeners(String type, Object[] listeners) { + assertTrue(listeners instanceof MergeEventListener[]); + registeredListeners.put(type, new HashSet(Arrays.asList(listeners))); + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + return null; + } + }; + sfb.setMappingResources(new String[0]); + sfb.setDataSource(new DriverManagerDataSource()); + Map listeners = new HashMap(); + Set mergeSet = new HashSet(); + mergeSet.add(new DummyMergeEventListener()); + mergeSet.add(new DummyMergeEventListener()); + listeners.put("merge", mergeSet); + sfb.setEventListeners(listeners); + sfb.afterPropertiesSet(); + assertEquals(listeners, registeredListeners); + } + + public void testLocalSessionFactoryBeanWithFilterDefinitions() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("filterDefinitions.xml", getClass())); + FilterTestLocalSessionFactoryBean sf = (FilterTestLocalSessionFactoryBean) xbf.getBean("&sessionFactory"); + assertEquals(2, sf.registeredFilterDefinitions.size()); + FilterDefinition filter1 = (FilterDefinition) sf.registeredFilterDefinitions.get(0); + FilterDefinition filter2 = (FilterDefinition) sf.registeredFilterDefinitions.get(1); + + assertEquals("filter1", filter1.getFilterName()); + assertEquals(2, filter1.getParameterNames().size()); + assertEquals(Hibernate.STRING, filter1.getParameterType("param1")); + assertEquals(Hibernate.LONG, filter1.getParameterType("otherParam")); + assertEquals("someCondition", filter1.getDefaultFilterCondition()); + + assertEquals("filter2", filter2.getFilterName()); + assertEquals(1, filter2.getParameterNames().size()); + assertEquals(Hibernate.INTEGER, filter2.getParameterType("myParam")); + } + + public void testLocalSessionFactoryBeanWithTypeDefinitions() throws Exception { + XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("typeDefinitions.xml", getClass())); + TypeTestLocalSessionFactoryBean sf = (TypeTestLocalSessionFactoryBean) xbf.getBean("&sessionFactory"); + TypeDef type1 = (TypeDef) sf.mappings.getTypeDef("type1"); + TypeDef type2 = (TypeDef) sf.mappings.getTypeDef("type2"); + + assertEquals("mypackage.MyTypeClass", type1.getTypeClass()); + assertEquals(2, type1.getParameters().size()); + assertEquals("value1", type1.getParameters().getProperty("param1")); + assertEquals("othervalue", type1.getParameters().getProperty("otherParam")); + + assertEquals("mypackage.MyOtherTypeClass", type2.getTypeClass()); + assertEquals(1, type2.getParameters().size()); + assertEquals("myvalue", type2.getParameters().getProperty("myParam")); + } + + + public static class FilterTestLocalSessionFactoryBean extends LocalSessionFactoryBean { + + public List registeredFilterDefinitions = new LinkedList(); + + protected Configuration newConfiguration() throws HibernateException { + return new Configuration() { + public void addFilterDefinition(FilterDefinition definition) { + registeredFilterDefinitions.add(definition); + } + }; + } + + protected SessionFactory newSessionFactory(Configuration config) { + return null; + } + } + + + public static class TypeTestLocalSessionFactoryBean extends LocalSessionFactoryBean { + + public Mappings mappings; + + protected SessionFactory newSessionFactory(Configuration config) { + this.mappings = config.createMappings(); + return null; + } + } + + + public static class DummyMergeEventListener implements MergeEventListener { + + public void onMerge(MergeEvent event) throws HibernateException { + } + + public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/filterDefinitions.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/filterDefinitions.xml new file mode 100644 index 00000000000..96b19990ac4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/filterDefinitions.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + string + long + + + + + + + + integer + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/HibernateDaoSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/HibernateDaoSupportTests.java new file mode 100644 index 00000000000..b6d0e0e1df8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/HibernateDaoSupportTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3.support; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import org.hibernate.SessionFactory; +import org.easymock.MockControl; + +import org.springframework.orm.hibernate3.HibernateTemplate; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class HibernateDaoSupportTests extends TestCase { + + public void testHibernateDaoSupportWithSessionFactory() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + sfControl.replay(); + final List test = new ArrayList(); + HibernateDaoSupport dao = new HibernateDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setSessionFactory(sf); + dao.afterPropertiesSet(); + assertEquals("Correct SessionFactory", sf, dao.getSessionFactory()); + assertEquals("Correct HibernateTemplate", sf, dao.getHibernateTemplate().getSessionFactory()); + assertEquals("initDao called", test.size(), 1); + sfControl.verify(); + } + + public void testHibernateDaoSupportWithHibernateTemplate() throws Exception { + HibernateTemplate template = new HibernateTemplate(); + final List test = new ArrayList(); + HibernateDaoSupport dao = new HibernateDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setHibernateTemplate(template); + dao.afterPropertiesSet(); + assertEquals("Correct HibernateTemplate", template, dao.getHibernateTemplate()); + assertEquals("initDao called", test.size(), 1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/LobTypeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/LobTypeTests.java new file mode 100644 index 00000000000..3be8ba5f858 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/LobTypeTests.java @@ -0,0 +1,630 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3.support; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; +import java.util.List; + +import javax.transaction.Status; +import javax.transaction.Synchronization; +import javax.transaction.TransactionManager; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.easymock.internal.ArrayMatcher; +import org.hibernate.SessionFactory; +import org.hibernate.classic.Session; + +import org.springframework.jdbc.support.lob.LobCreator; +import org.springframework.jdbc.support.lob.LobHandler; +import org.springframework.orm.hibernate3.SessionFactoryUtils; +import org.springframework.transaction.MockJtaTransaction; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class LobTypeTests extends TestCase { + + private MockControl rsControl = MockControl.createControl(ResultSet.class); + private ResultSet rs = (ResultSet) rsControl.getMock(); + private MockControl psControl = MockControl.createControl(PreparedStatement.class); + private PreparedStatement ps = (PreparedStatement) psControl.getMock(); + + private MockControl lobHandlerControl = MockControl.createControl(LobHandler.class); + private LobHandler lobHandler = (LobHandler) lobHandlerControl.getMock(); + private MockControl lobCreatorControl = MockControl.createControl(LobCreator.class); + private LobCreator lobCreator = (LobCreator) lobCreatorControl.getMock(); + + protected void setUp() throws SQLException { + lobHandler.getLobCreator(); + lobHandlerControl.setReturnValue(lobCreator); + lobCreator.close(); + lobCreatorControl.setVoidCallable(1); + + rsControl.replay(); + psControl.replay(); + } + + public void testClobStringType() throws Exception { + lobHandler.getClobAsString(rs, "column"); + lobHandlerControl.setReturnValue("content"); + lobCreator.setClobAsString(ps, 1, "content"); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + ClobStringType type = new ClobStringType(lobHandler, null); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.CLOB, type.sqlTypes()[0]); + assertEquals(String.class, type.returnedClass()); + assertTrue(type.equals("content", "content")); + assertEquals("content", type.deepCopy("content")); + assertFalse(type.isMutable()); + + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + type.nullSafeSet(ps, "content", 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + assertTrue(synchs.get(0).getClass().getName().endsWith("SpringLobCreatorSynchronization")); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testClobStringTypeWithSynchronizedSession() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + lobHandler.getClobAsString(rs, "column"); + lobHandlerControl.setReturnValue("content"); + lobCreator.setClobAsString(ps, 1, "content"); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + ClobStringType type = new ClobStringType(lobHandler, null); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.CLOB, type.sqlTypes()[0]); + assertEquals(String.class, type.returnedClass()); + assertTrue(type.equals("content", "content")); + assertEquals("content", type.deepCopy("content")); + assertFalse(type.isMutable()); + + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + SessionFactoryUtils.getSession(sf, true); + type.nullSafeSet(ps, "content", 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(2, synchs.size()); + assertTrue(synchs.get(0).getClass().getName().endsWith("SpringLobCreatorSynchronization")); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + ((TransactionSynchronization) synchs.get(1)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(1)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + + sfControl.verify(); + sessionControl.verify(); + } + + public void testClobStringTypeWithFlushOnCommit() throws Exception { + lobHandler.getClobAsString(rs, "column"); + lobHandlerControl.setReturnValue("content"); + lobCreator.setClobAsString(ps, 1, "content"); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + ClobStringType type = new ClobStringType(lobHandler, null); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.CLOB, type.sqlTypes()[0]); + assertEquals(String.class, type.returnedClass()); + assertTrue(type.equals("content", "content")); + assertEquals("content", type.deepCopy("content")); + assertFalse(type.isMutable()); + + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + type.nullSafeSet(ps, "content", 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testClobStringTypeWithJtaSynchronization() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + lobHandler.getClobAsString(rs, "column"); + lobHandlerControl.setReturnValue("content"); + lobCreator.setClobAsString(ps, 1, "content"); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + ClobStringType type = new ClobStringType(lobHandler, tm); + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, "content", 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.beforeCompletion(); + synch.afterCompletion(Status.STATUS_COMMITTED); + tmControl.verify(); + } + + public void testClobStringTypeWithJtaSynchronizationAndRollback() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + lobHandler.getClobAsString(rs, "column"); + lobHandlerControl.setReturnValue("content"); + lobCreator.setClobAsString(ps, 1, "content"); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + ClobStringType type = new ClobStringType(lobHandler, tm); + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, "content", 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.afterCompletion(Status.STATUS_ROLLEDBACK); + tmControl.verify(); + } + + public void testBlobStringType() throws Exception { + String content = "content"; + byte[] contentBytes = content.getBytes(); + lobHandler.getBlobAsBytes(rs, "column"); + lobHandlerControl.setReturnValue(contentBytes); + lobCreator.setBlobAsBytes(ps, 1, contentBytes); + lobCreatorControl.setMatcher(new ArrayMatcher()); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobStringType type = new BlobStringType(lobHandler, null); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.BLOB, type.sqlTypes()[0]); + assertEquals(String.class, type.returnedClass()); + assertTrue(type.equals("content", "content")); + assertEquals("content", type.deepCopy("content")); + assertFalse(type.isMutable()); + + assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + type.nullSafeSet(ps, content, 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobStringTypeWithNull() throws Exception { + lobHandler.getBlobAsBytes(rs, "column"); + lobHandlerControl.setReturnValue(null); + lobCreator.setBlobAsBytes(ps, 1, null); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobStringType type = new BlobStringType(lobHandler, null); + assertEquals(null, type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + type.nullSafeSet(ps, null, 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobStringTypeWithJtaSynchronization() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + String content = "content"; + byte[] contentBytes = content.getBytes(); + lobHandler.getBlobAsBytes(rs, "column"); + lobHandlerControl.setReturnValue(contentBytes); + lobCreator.setBlobAsBytes(ps, 1, contentBytes); + lobCreatorControl.setMatcher(new ArrayMatcher()); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobStringType type = new BlobStringType(lobHandler, tm); + assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, content, 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.beforeCompletion(); + synch.afterCompletion(Status.STATUS_COMMITTED); + tmControl.verify(); + } + + public void testBlobStringTypeWithJtaSynchronizationAndRollback() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + String content = "content"; + byte[] contentBytes = content.getBytes(); + lobHandler.getBlobAsBytes(rs, "column"); + lobHandlerControl.setReturnValue(contentBytes); + lobCreator.setBlobAsBytes(ps, 1, contentBytes); + lobCreatorControl.setMatcher(new ArrayMatcher()); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobStringType type = new BlobStringType(lobHandler, tm); + assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, content, 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.afterCompletion(Status.STATUS_ROLLEDBACK); + tmControl.verify(); + } + + public void testBlobByteArrayType() throws Exception { + byte[] content = "content".getBytes(); + lobHandler.getBlobAsBytes(rs, "column"); + lobHandlerControl.setReturnValue(content); + lobCreator.setBlobAsBytes(ps, 1, content); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobByteArrayType type = new BlobByteArrayType(lobHandler, null); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.BLOB, type.sqlTypes()[0]); + assertEquals(byte[].class, type.returnedClass()); + assertTrue(type.equals(new byte[] {(byte) 255}, new byte[] {(byte) 255})); + assertTrue(Arrays.equals(new byte[] {(byte) 255}, (byte[]) type.deepCopy(new byte[] {(byte) 255}))); + assertTrue(type.isMutable()); + + assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + type.nullSafeSet(ps, content, 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobByteArrayTypeWithJtaSynchronization() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + byte[] content = "content".getBytes(); + lobHandler.getBlobAsBytes(rs, "column"); + lobHandlerControl.setReturnValue(content); + lobCreator.setBlobAsBytes(ps, 1, content); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobByteArrayType type = new BlobByteArrayType(lobHandler, tm); + assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, content, 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.beforeCompletion(); + synch.afterCompletion(Status.STATUS_COMMITTED); + tmControl.verify(); + } + + public void testBlobByteArrayTypeWithJtaSynchronizationAndRollback() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + byte[] content = "content".getBytes(); + lobHandler.getBlobAsBytes(rs, "column"); + lobHandlerControl.setReturnValue(content); + lobCreator.setBlobAsBytes(ps, 1, content); + lobCreatorControl.setVoidCallable(1); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobByteArrayType type = new BlobByteArrayType(lobHandler, tm); + assertEquals(content, type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, content, 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.afterCompletion(Status.STATUS_ROLLEDBACK); + tmControl.verify(); + } + + public void testBlobSerializableType() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject("content"); + oos.close(); + + lobHandler.getBlobAsBinaryStream(rs, "column"); + lobHandlerControl.setReturnValue(new ByteArrayInputStream(baos.toByteArray())); + lobCreator.setBlobAsBytes(ps, 1, baos.toByteArray()); + lobCreatorControl.setMatcher(new ArrayMatcher()); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobSerializableType type = new BlobSerializableType(lobHandler, null); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.BLOB, type.sqlTypes()[0]); + assertEquals(Serializable.class, type.returnedClass()); + assertTrue(type.isMutable()); + + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + type.nullSafeSet(ps, "content", 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + ((TransactionSynchronization) synchs.get(0)).afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobSerializableTypeWithNull() throws Exception { + lobHandler.getBlobAsBinaryStream(rs, "column"); + lobHandlerControl.setReturnValue(null); + lobCreator.setBlobAsBytes(ps, 1, null); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobSerializableType type = new BlobSerializableType(lobHandler, null); + assertEquals(null, type.nullSafeGet(rs, new String[] {"column"}, null)); + TransactionSynchronizationManager.initSynchronization(); + try { + type.nullSafeSet(ps, null, 1); + List synchs = TransactionSynchronizationManager.getSynchronizations(); + assertEquals(1, synchs.size()); + ((TransactionSynchronization) synchs.get(0)).beforeCompletion(); + } + finally { + TransactionSynchronizationManager.clearSynchronization(); + } + } + + public void testBlobSerializableTypeWithJtaSynchronization() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject("content"); + oos.close(); + + lobHandler.getBlobAsBinaryStream(rs, "column"); + lobHandlerControl.setReturnValue(new ByteArrayInputStream(baos.toByteArray())); + lobCreator.setBlobAsBytes(ps, 1, baos.toByteArray()); + lobCreatorControl.setMatcher(new ArrayMatcher()); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobSerializableType type = new BlobSerializableType(lobHandler, tm); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.BLOB, type.sqlTypes()[0]); + assertEquals(Serializable.class, type.returnedClass()); + assertTrue(type.isMutable()); + + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, "content", 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.beforeCompletion(); + synch.afterCompletion(Status.STATUS_COMMITTED); + tmControl.verify(); + } + + public void testBlobSerializableTypeWithJtaSynchronizationAndRollback() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 1); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject("content"); + oos.close(); + + lobHandler.getBlobAsBinaryStream(rs, "column"); + lobHandlerControl.setReturnValue(new ByteArrayInputStream(baos.toByteArray())); + lobCreator.setBlobAsBytes(ps, 1, baos.toByteArray()); + lobCreatorControl.setMatcher(new ArrayMatcher()); + + lobHandlerControl.replay(); + lobCreatorControl.replay(); + + BlobSerializableType type = new BlobSerializableType(lobHandler, tm); + assertEquals(1, type.sqlTypes().length); + assertEquals(Types.BLOB, type.sqlTypes()[0]); + assertEquals(Serializable.class, type.returnedClass()); + assertTrue(type.isMutable()); + + assertEquals("content", type.nullSafeGet(rs, new String[] {"column"}, null)); + tmControl.replay(); + type.nullSafeSet(ps, "content", 1); + Synchronization synch = transaction.getSynchronization(); + assertNotNull(synch); + synch.afterCompletion(Status.STATUS_ROLLEDBACK); + tmControl.verify(); + } + + public void testHbm2JavaStyleInitialization() throws Exception { + rsControl.reset(); + psControl.reset(); + lobHandlerControl.reset(); + lobCreatorControl.reset(); + + ClobStringType cst = null; + BlobByteArrayType bbat = null; + BlobSerializableType bst = null; + try { + cst = new ClobStringType(); + bbat = new BlobByteArrayType(); + bst = new BlobSerializableType(); + } + catch (Exception ex) { + fail("Should not have thrown exception on initialization"); + } + + try { + cst.nullSafeGet(rs, new String[] {"column"}, null); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + try { + bbat.nullSafeGet(rs, new String[] {"column"}, null); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + try { + bst.nullSafeGet(rs, new String[] {"column"}, null); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + protected void tearDown() { + try { + rsControl.verify(); + psControl.verify(); + lobHandlerControl.verify(); + lobCreatorControl.verify(); + } + catch (IllegalStateException ex) { + // ignore: test method didn't call replay + } + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java new file mode 100644 index 00000000000..e8bbea99e83 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java @@ -0,0 +1,661 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3.support; + +import java.io.IOException; +import java.sql.Connection; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.transaction.TransactionManager; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.classic.Session; +import org.hibernate.engine.SessionFactoryImplementor; + +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.mock.web.PassThroughFilterChain; +import org.springframework.orm.hibernate3.HibernateAccessor; +import org.springframework.orm.hibernate3.HibernateTransactionManager; +import org.springframework.orm.hibernate3.SessionFactoryUtils; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter; + +/** + * @author Juergen Hoeller + * @since 05.03.2005 + */ +public class OpenSessionInViewTests extends TestCase { + + public void testOpenSessionInViewInterceptorWithSingleSession() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + OpenSessionInViewInterceptor rawInterceptor = new OpenSessionInViewInterceptor(); + rawInterceptor.setSessionFactory(sf); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + MockServletContext sc = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 2); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + interceptor.preHandle(request, response, "handler"); + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + + // check that further invocations simply participate + interceptor.preHandle(request, response, "handler"); + + assertEquals(session, SessionFactoryUtils.getSession(sf, false)); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + sfControl.verify(); + sessionControl.verify(); + + sfControl.reset(); + sessionControl.reset(); + sfControl.replay(); + sessionControl.replay(); + interceptor.postHandle(request, response, "handler", null); + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + + sfControl.reset(); + sessionControl.reset(); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + interceptor.afterCompletion(request, response, "handler", null); + assertFalse(TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + } + + public void testOpenSessionInViewInterceptorWithSingleSessionAndJtaTm() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); + final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + tm.getTransaction(); + tmControl.setReturnValue(null, 2); + + OpenSessionInViewInterceptor rawInterceptor = new OpenSessionInViewInterceptor(); + rawInterceptor.setSessionFactory(sf); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + MockServletContext sc = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + sf.getTransactionManager(); + sfControl.setReturnValue(tm, 2); + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.isOpen(); + sessionControl.setReturnValue(true, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + + tmControl.replay(); + sfControl.replay(); + sessionControl.replay(); + + interceptor.preHandle(request, response, "handler"); + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + + // check that further invocations simply participate + interceptor.preHandle(request, response, "handler"); + + assertEquals(session, SessionFactoryUtils.getSession(sf, false)); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + sfControl.verify(); + sessionControl.verify(); + + sfControl.reset(); + sessionControl.reset(); + sfControl.replay(); + sessionControl.replay(); + interceptor.postHandle(request, response, "handler", null); + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + + sfControl.reset(); + sessionControl.reset(); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + interceptor.afterCompletion(request, response, "handler", null); + assertFalse(TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + } + + public void testOpenSessionInViewInterceptorWithSingleSessionAndFlush() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + OpenSessionInViewInterceptor rawInterceptor = new OpenSessionInViewInterceptor(); + rawInterceptor.setSessionFactory(sf); + rawInterceptor.setFlushMode(HibernateAccessor.FLUSH_AUTO); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + MockServletContext sc = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + sfControl.replay(); + sessionControl.replay(); + interceptor.preHandle(request, response, "handler"); + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + + sfControl.reset(); + sessionControl.reset(); + session.flush(); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + interceptor.postHandle(request, response, "handler", null); + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + + sfControl.reset(); + sessionControl.reset(); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + interceptor.afterCompletion(request, response, "handler", null); + assertFalse(TransactionSynchronizationManager.hasResource(sf)); + sfControl.verify(); + sessionControl.verify(); + } + + public void testOpenSessionInViewInterceptorAndDeferredClose() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + OpenSessionInViewInterceptor rawInterceptor = new OpenSessionInViewInterceptor(); + rawInterceptor.setSessionFactory(sf); + rawInterceptor.setSingleSession(false); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + MockServletContext sc = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + interceptor.preHandle(request, response, "handler"); + org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true); + SessionFactoryUtils.releaseSession(sess, sf); + + // check that further invocations simply participate + interceptor.preHandle(request, response, "handler"); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + sfControl.verify(); + sessionControl.verify(); + sfControl.reset(); + sessionControl.reset(); + + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + sfControl.verify(); + sessionControl.verify(); + } + + public void testOpenSessionInViewFilterWithSingleSession() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + MockControl sf2Control = MockControl.createControl(SessionFactory.class); + final SessionFactory sf2 = (SessionFactory) sf2Control.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + Session session2 = (Session) session2Control.getMock(); + + sf2.openSession(); + sf2Control.setReturnValue(session2, 1); + session2.getSessionFactory(); + session2Control.setReturnValue(sf); + session2.setFlushMode(FlushMode.AUTO); + session2Control.setVoidCallable(1); + session2.close(); + session2Control.setReturnValue(null, 1); + sf2Control.replay(); + session2Control.replay(); + + MockServletContext sc = new MockServletContext(); + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); + wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); + filterConfig2.addInitParameter("sessionFactoryBeanName", "mySessionFactory"); + filterConfig2.addInitParameter("flushMode", "AUTO"); + + final OpenSessionInViewFilter filter = new OpenSessionInViewFilter(); + filter.init(filterConfig); + final OpenSessionInViewFilter filter2 = new OpenSessionInViewFilter(); + filter2.init(filterConfig2); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + servletRequest.setAttribute("invoked", Boolean.TRUE); + } + }; + + final FilterChain filterChain2 = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + assertTrue(TransactionSynchronizationManager.hasResource(sf2)); + filter.doFilter(servletRequest, servletResponse, filterChain); + } + }; + + FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2); + + assertFalse(TransactionSynchronizationManager.hasResource(sf)); + assertFalse(TransactionSynchronizationManager.hasResource(sf2)); + filter2.doFilter(request, response, filterChain3); + assertFalse(TransactionSynchronizationManager.hasResource(sf)); + assertFalse(TransactionSynchronizationManager.hasResource(sf2)); + assertNotNull(request.getAttribute("invoked")); + + sfControl.verify(); + sessionControl.verify(); + sf2Control.verify(); + session2Control.verify(); + + wac.close(); + } + + public void testOpenSessionInViewFilterWithSingleSessionAndPreBoundSession() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + session.close(); + sessionControl.setReturnValue(null, 1); + sfControl.replay(); + sessionControl.replay(); + + MockServletContext sc = new MockServletContext(); + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); + filterConfig2.addInitParameter("sessionFactoryBeanName", "mySessionFactory"); + + OpenSessionInViewInterceptor rawInterceptor = new OpenSessionInViewInterceptor(); + rawInterceptor.setSessionFactory(sf); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + interceptor.preHandle(request, response, "handler"); + + final OpenSessionInViewFilter filter = new OpenSessionInViewFilter(); + filter.init(filterConfig); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + servletRequest.setAttribute("invoked", Boolean.TRUE); + } + }; + + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + filter.doFilter(request, response, filterChain); + assertTrue(TransactionSynchronizationManager.hasResource(sf)); + assertNotNull(request.getAttribute("invoked")); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + sfControl.verify(); + sessionControl.verify(); + + wac.close(); + } + + public void testOpenSessionInViewFilterWithDeferredClose() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + MockControl sf2Control = MockControl.createControl(SessionFactory.class); + final SessionFactory sf2 = (SessionFactory) sf2Control.getMock(); + final MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + Connection con = (Connection) conControl.getMock(); + + sf2.openSession(); + sf2Control.setReturnValue(session2, 1); + session2.beginTransaction(); + session2Control.setReturnValue(tx, 1); + session2.connection(); + session2Control.setReturnValue(con, 2); + tx.commit(); + txControl.setVoidCallable(1); + session2.isConnected(); + session2Control.setReturnValue(true, 1); + con.isReadOnly(); + conControl.setReturnValue(false, 1); + session2.setFlushMode(FlushMode.NEVER); + session2Control.setVoidCallable(1); + + sf2Control.replay(); + session2Control.replay(); + txControl.replay(); + conControl.replay(); + + MockServletContext sc = new MockServletContext(); + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); + wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); + filterConfig.addInitParameter("singleSession", "false"); + filterConfig2.addInitParameter("singleSession", "false"); + filterConfig2.addInitParameter("sessionFactoryBeanName", "mySessionFactory"); + + final OpenSessionInViewFilter filter = new OpenSessionInViewFilter(); + filter.init(filterConfig); + final OpenSessionInViewFilter filter2 = new OpenSessionInViewFilter(); + filter2.init(filterConfig2); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { + HibernateTransactionManager tm = new HibernateTransactionManager(sf); + TransactionStatus ts = tm.getTransaction( + new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_SUPPORTS)); + org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true); + SessionFactoryUtils.releaseSession(sess, sf); + tm.commit(ts); + + sessionControl.verify(); + sessionControl.reset(); + + session.close(); + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + + servletRequest.setAttribute("invoked", Boolean.TRUE); + } + }; + + final FilterChain filterChain2 = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + + HibernateTransactionManager tm = new HibernateTransactionManager(sf2); + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + tm.commit(ts); + + session2Control.verify(); + session2Control.reset(); + + session2.close(); + session2Control.setReturnValue(null, 1); + session2Control.replay(); + + filter.doFilter(servletRequest, servletResponse, filterChain); + } + }; + + FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2); + + filter2.doFilter(request, response, filterChain3); + assertNotNull(request.getAttribute("invoked")); + + sfControl.verify(); + sessionControl.verify(); + sf2Control.verify(); + session2Control.verify(); + txControl.verify(); + conControl.verify(); + + wac.close(); + } + + public void testOpenSessionInViewFilterWithDeferredCloseAndAlreadyActiveDeferredClose() throws Exception { + MockControl sfControl = MockControl.createControl(SessionFactory.class); + final SessionFactory sf = (SessionFactory) sfControl.getMock(); + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + sf.openSession(); + sfControl.setReturnValue(session, 1); + session.getSessionFactory(); + sessionControl.setReturnValue(sf); + session.getFlushMode(); + sessionControl.setReturnValue(FlushMode.NEVER, 1); + session.setFlushMode(FlushMode.NEVER); + sessionControl.setVoidCallable(1); + sfControl.replay(); + sessionControl.replay(); + + MockServletContext sc = new MockServletContext(); + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); + filterConfig.addInitParameter("singleSession", "false"); + filterConfig2.addInitParameter("singleSession", "false"); + filterConfig2.addInitParameter("sessionFactoryBeanName", "mySessionFactory"); + + OpenSessionInViewInterceptor rawInterceptor = new OpenSessionInViewInterceptor(); + rawInterceptor.setSessionFactory(sf); + rawInterceptor.setSingleSession(false); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + interceptor.preHandle(request, response, "handler"); + + final OpenSessionInViewFilter filter = new OpenSessionInViewFilter(); + filter.init(filterConfig); + final OpenSessionInViewFilter filter2 = new OpenSessionInViewFilter(); + filter2.init(filterConfig2); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { + HibernateTransactionManager tm = new HibernateTransactionManager(sf); + TransactionStatus ts = tm.getTransaction( + new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_SUPPORTS)); + org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true); + SessionFactoryUtils.releaseSession(sess, sf); + tm.commit(ts); + + sessionControl.verify(); + sessionControl.reset(); + try { + session.close(); + } + catch (HibernateException ex) { + } + sessionControl.setReturnValue(null, 1); + sessionControl.replay(); + + servletRequest.setAttribute("invoked", Boolean.TRUE); + } + }; + + FilterChain filterChain2 = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + filter.doFilter(servletRequest, servletResponse, filterChain); + } + }; + + filter.doFilter(request, response, filterChain2); + assertNotNull(request.getAttribute("invoked")); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + sfControl.verify(); + sessionControl.verify(); + + wac.close(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptorTests.java new file mode 100644 index 00000000000..4d74833ab97 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptorTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3.support; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.scope.ScopedObject; + +/** + * @author Costin Leau + */ +public class ScopedBeanInterceptorTests extends TestCase { + + public void testInterceptorWithPlainObject() throws Exception { + ScopedBeanInterceptor interceptor = new ScopedBeanInterceptor(); + final Object realObject = new Object(); + + ScopedObject scoped = new ScopedObject() { + public Object getTargetObject() { + return realObject; + } + public void removeFromScope() { + // do nothing + } + }; + + // default contract is to return null for default behavior + assertEquals(null, interceptor.getEntityName(realObject)); + assertEquals(realObject.getClass().getName(), interceptor.getEntityName(scoped)); + } + + public void testInterceptorWithCglibProxy() throws Exception { + ScopedBeanInterceptor interceptor = new ScopedBeanInterceptor(); + final Object realObject = new Object(); + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.setTarget(realObject); + proxyFactory.setProxyTargetClass(true); + final Object proxy = proxyFactory.getProxy(); + + ScopedObject scoped = new ScopedObject() { + public Object getTargetObject() { + return proxy; + } + public void removeFromScope() { + // do nothing + } + }; + + assertEquals(realObject.getClass().getName(), interceptor.getEntityName(scoped)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/typeDefinitions.xml b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/typeDefinitions.xml new file mode 100644 index 00000000000..bd12f319b7f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/hibernate3/typeDefinitions.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + value1 + othervalue + + + + + + + + + myvalue + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoInterceptorTests.java new file mode 100644 index 00000000000..46093da105e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoInterceptorTests.java @@ -0,0 +1,155 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jdo; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Method; + +import javax.jdo.PersistenceManager; +import javax.jdo.PersistenceManagerFactory; + +import junit.framework.TestCase; + +import org.aopalliance.intercept.Interceptor; +import org.aopalliance.intercept.Invocation; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + */ +public class JdoInterceptorTests extends TestCase { + + public void testInterceptor() { + MockControl pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + PersistenceManagerFactory pmf = (PersistenceManagerFactory) pmfControl.getMock(); + MockControl pmControl = MockControl.createControl(PersistenceManager.class); + PersistenceManager pm = (PersistenceManager) pmControl.getMock(); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoInterceptor interceptor = new JdoInterceptor(); + interceptor.setPersistenceManagerFactory(pmf); + try { + interceptor.invoke(new TestInvocation(pmf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + + pmfControl.verify(); + pmControl.verify(); + } + + public void testInterceptorWithPrebound() { + MockControl pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + PersistenceManagerFactory pmf = (PersistenceManagerFactory) pmfControl.getMock(); + MockControl pmControl = MockControl.createControl(PersistenceManager.class); + PersistenceManager pm = (PersistenceManager) pmControl.getMock(); + pmfControl.replay(); + pmControl.replay(); + + TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); + JdoInterceptor interceptor = new JdoInterceptor(); + interceptor.setPersistenceManagerFactory(pmf); + try { + interceptor.invoke(new TestInvocation(pmf)); + } + catch (Throwable t) { + fail("Should not have thrown Throwable: " + t.getMessage()); + } + finally { + TransactionSynchronizationManager.unbindResource(pmf); + } + + pmfControl.verify(); + pmControl.verify(); + } + + + private static class TestInvocation implements MethodInvocation { + + private PersistenceManagerFactory persistenceManagerFactory; + + public TestInvocation(PersistenceManagerFactory persistenceManagerFactory) { + this.persistenceManagerFactory = persistenceManagerFactory; + } + + public Object proceed() throws Throwable { + if (!TransactionSynchronizationManager.hasResource(this.persistenceManagerFactory)) { + throw new IllegalStateException("PersistenceManager not bound"); + } + return null; + } + + public Object[] getArguments() { + return null; + } + + public int getCurrentInterceptorIndex() { + return 0; + } + + public int getNumberOfInterceptors() { + return 0; + } + + public Interceptor getInterceptor(int i) { + return null; + } + + public Method getMethod() { + return null; + } + + public AccessibleObject getStaticPart() { + return getMethod(); + } + + public Object getArgument(int i) { + return null; + } + + public void setArgument(int i, Object handler) { + } + + public int getArgumentCount() { + return 0; + } + + public Object getThis() { + return null; + } + + public Object getProxy() { + return null; + } + + public Invocation cloneInstance() { + return null; + } + + public void release() { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTemplateTests.java new file mode 100644 index 00000000000..f5d40a09ca1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTemplateTests.java @@ -0,0 +1,787 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jdo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.jdo.JDODataStoreException; +import javax.jdo.JDOException; +import javax.jdo.JDOFatalDataStoreException; +import javax.jdo.JDOFatalUserException; +import javax.jdo.JDOObjectNotFoundException; +import javax.jdo.JDOOptimisticVerificationException; +import javax.jdo.JDOUserException; +import javax.jdo.PersistenceManager; +import javax.jdo.PersistenceManagerFactory; +import javax.jdo.Query; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + * @since 03.06.2003 + */ +public class JdoTemplateTests extends TestCase { + + private MockControl pmfControl; + private PersistenceManagerFactory pmf; + private MockControl pmControl; + private PersistenceManager pm; + + protected void setUp() { + pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + pmf = (PersistenceManagerFactory) pmfControl.getMock(); + pmControl = MockControl.createControl(PersistenceManager.class); + pm = (PersistenceManager) pmControl.getMock(); + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 1); + } + + protected void tearDown() { + try { + pmfControl.verify(); + pmControl.verify(); + } + catch (IllegalStateException ex) { + // ignore: test method didn't call replay + } + } + + public void testTemplateExecuteWithNotAllowCreate() { + JdoTemplate jt = new JdoTemplate(); + jt.setPersistenceManagerFactory(pmf); + jt.setAllowCreate(false); + try { + jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return null; + } + }); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testTemplateExecuteWithNotAllowCreateAndThreadBound() { + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.setAllowCreate(false); + TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); + final List l = new ArrayList(); + l.add("test"); + List result = (List) jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return l; + } + }); + assertTrue("Correct result list", result == l); + TransactionSynchronizationManager.unbindResource(pmf); + } + + public void testTemplateExecuteWithNewPersistenceManager() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + final List l = new ArrayList(); + l.add("test"); + List result = (List) jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + public void testTemplateExecuteWithThreadBoundAndFlushEager() { + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + + dialect.flush(pm); + dialectControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + dialectControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.setJdoDialect(dialect); + jt.setFlushEager(true); + jt.setAllowCreate(false); + TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); + final List l = new ArrayList(); + l.add("test"); + List result = (List) jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return l; + } + }); + assertTrue("Correct result list", result == l); + TransactionSynchronizationManager.unbindResource(pmf); + dialectControl.verify(); + } + + public void testGetObjectById() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.getObjectById("0", true); + pmControl.setReturnValue("A"); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals("A", jt.getObjectById("0")); + } + + public void testGetObjectByIdWithClassAndValue() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.getObjectById(String.class, "0"); + pmControl.setReturnValue("A"); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals("A", jt.getObjectById(String.class, "0")); + } + + public void testEvict() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.evict("0"); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.evict("0"); + } + + public void testEvictAllWithCollection() { + Collection coll = new HashSet(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.evictAll(coll); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.evictAll(coll); + } + + public void testEvictAll() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.evictAll(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.evictAll(); + } + + public void testRefresh() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.refresh("0"); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.refresh("0"); + } + + public void testRefreshAllWithCollection() { + Collection coll = new HashSet(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.refreshAll(coll); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.refreshAll(coll); + } + + public void testRefreshAll() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.refreshAll(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.refreshAll(); + } + + public void testMakePersistent() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.makePersistent("0"); + pmControl.setReturnValue(null, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.makePersistent("0"); + } + + public void testMakePersistentAll() { + Collection coll = new HashSet(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.makePersistentAll(coll); + pmControl.setReturnValue(null, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.makePersistentAll(coll); + } + + public void testDeletePersistent() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.deletePersistent("0"); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.deletePersistent("0"); + } + + public void testDeletePersistentAll() { + Collection coll = new HashSet(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.deletePersistentAll(coll); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.deletePersistentAll(coll); + } + + public void testDetachCopy() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.detachCopy("0"); + pmControl.setReturnValue("0x", 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals("0x", jt.detachCopy("0")); + } + + public void testDetachCopyAll() { + Collection attached = new HashSet(); + Collection detached = new HashSet(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.detachCopyAll(attached); + pmControl.setReturnValue(detached, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(detached, jt.detachCopyAll(attached)); + } + + public void testAttachCopy() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.makePersistent("0x"); + pmControl.setReturnValue("0", 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals("0", jt.attachCopy("0x")); + } + + public void testAttachCopyAll() { + Collection detached = new HashSet(); + Collection attached = new HashSet(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.makePersistentAll(detached); + pmControl.setReturnValue(attached, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(attached, jt.attachCopyAll(detached)); + } + + public void testFlush() { + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.flush(); + } + + public void testFlushWithDialect() { + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + dialect.flush(pm); + dialectControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + dialectControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.setJdoDialect(dialect); + jt.flush(); + dialectControl.verify(); + } + + public void testFind() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(String.class); + pmControl.setReturnValue(query); + Collection coll = new HashSet(); + query.execute(); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(String.class)); + queryControl.verify(); + } + + public void testFindWithFilter() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(String.class, "a == b"); + pmControl.setReturnValue(query); + Collection coll = new HashSet(); + query.execute(); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(String.class, "a == b")); + queryControl.verify(); + } + + public void testFindWithFilterAndOrdering() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(String.class, "a == b"); + pmControl.setReturnValue(query); + query.setOrdering("c asc"); + queryControl.setVoidCallable(1); + Collection coll = new HashSet(); + query.execute(); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(String.class, "a == b", "c asc")); + queryControl.verify(); + } + + public void testFindWithParameterArray() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(String.class, "a == b"); + pmControl.setReturnValue(query); + query.declareParameters("params"); + queryControl.setVoidCallable(1); + Object[] values = new Object[0]; + Collection coll = new HashSet(); + query.executeWithArray(values); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(String.class, "a == b", "params", values)); + queryControl.verify(); + } + + public void testFindWithParameterArrayAndOrdering() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(String.class, "a == b"); + pmControl.setReturnValue(query); + query.declareParameters("params"); + queryControl.setVoidCallable(1); + query.setOrdering("c asc"); + queryControl.setVoidCallable(1); + Object[] values = new Object[0]; + Collection coll = new HashSet(); + query.executeWithArray(values); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(String.class, "a == b", "params", values, "c asc")); + queryControl.verify(); + } + + public void testFindWithParameterMap() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(String.class, "a == b"); + pmControl.setReturnValue(query); + query.declareParameters("params"); + queryControl.setVoidCallable(1); + Map values = new HashMap(); + Collection coll = new HashSet(); + query.executeWithMap(values); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(String.class, "a == b", "params", values)); + queryControl.verify(); + } + + public void testFindWithParameterMapAndOrdering() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(String.class, "a == b"); + pmControl.setReturnValue(query); + query.declareParameters("params"); + queryControl.setVoidCallable(1); + query.setOrdering("c asc"); + queryControl.setVoidCallable(1); + Map values = new HashMap(); + Collection coll = new HashSet(); + query.executeWithMap(values); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(String.class, "a == b", "params", values, "c asc")); + queryControl.verify(); + } + + public void testFindWithLanguageAndQueryObject() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery(Query.SQL, "some SQL"); + pmControl.setReturnValue(query); + Collection coll = new HashSet(); + query.execute(); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find(Query.SQL, "some SQL")); + queryControl.verify(); + } + + public void testFindWithQueryString() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newQuery("single string query"); + pmControl.setReturnValue(query); + Collection coll = new HashSet(); + query.execute(); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.find("single string query")); + queryControl.verify(); + } + + public void testFindByNamedQuery() { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm); + pm.newNamedQuery(String.class, "some query name"); + pmControl.setReturnValue(query); + Collection coll = new HashSet(); + query.execute(); + queryControl.setReturnValue(coll); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + queryControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + assertEquals(coll, jt.findByNamedQuery(String.class, "some query name")); + queryControl.verify(); + } + + public void testTemplateExceptions() { + try { + createTemplate().execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new JDOObjectNotFoundException(); + } + }); + fail("Should have thrown JdoObjectRetrievalFailureException"); + } + catch (JdoObjectRetrievalFailureException ex) { + // expected + } + + try { + createTemplate().execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new JDOOptimisticVerificationException(); + } + }); + fail("Should have thrown JdoOptimisticLockingFailureException"); + } + catch (JdoOptimisticLockingFailureException ex) { + // expected + } + + try { + createTemplate().execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new JDODataStoreException(); + } + }); + fail("Should have thrown JdoResourceFailureException"); + } + catch (JdoResourceFailureException ex) { + // expected + } + + try { + createTemplate().execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new JDOFatalDataStoreException(); + } + }); + fail("Should have thrown JdoResourceFailureException"); + } + catch (JdoResourceFailureException ex) { + // expected + } + + try { + createTemplate().execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new JDOUserException(); + } + }); + fail("Should have thrown JdoUsageException"); + } + catch (JdoUsageException ex) { + // expected + } + + try { + createTemplate().execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new JDOFatalUserException(); + } + }); + fail("Should have thrown JdoUsageException"); + } + catch (JdoUsageException ex) { + // expected + } + + try { + createTemplate().execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new JDOException(); + } + }); + fail("Should have thrown JdoSystemException"); + } + catch (JdoSystemException ex) { + // expected + } + } + + public void testTranslateException() { + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + final JDOException ex = new JDOException(); + dialect.translateException(ex); + dialectControl.setReturnValue(new DataIntegrityViolationException("test", ex)); + dialectControl.replay(); + try { + JdoTemplate template = createTemplate(); + template.setJdoDialect(dialect); + template.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw ex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException dive) { + // expected + } + dialectControl.verify(); + } + + private JdoTemplate createTemplate() { + pmfControl.reset(); + pmControl.reset(); + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 1); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + return new JdoTemplate(pmf); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java new file mode 100644 index 00000000000..0294cfcee57 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java @@ -0,0 +1,1209 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jdo; + +import java.lang.reflect.Proxy; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.sql.Savepoint; +import java.util.ArrayList; +import java.util.List; + +import javax.jdo.JDOFatalDataStoreException; +import javax.jdo.PersistenceManager; +import javax.jdo.PersistenceManagerFactory; +import javax.jdo.Query; +import javax.jdo.Transaction; +import javax.sql.DataSource; +import javax.transaction.Status; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.TestBean; +import org.springframework.jdbc.datasource.ConnectionHandle; +import org.springframework.jdbc.datasource.ConnectionHolder; +import org.springframework.jdbc.datasource.SimpleConnectionHandle; +import org.springframework.transaction.InvalidIsolationLevelException; +import org.springframework.transaction.MockJtaTransaction; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.jta.JtaTransactionManager; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + */ +public class JdoTransactionManagerTests extends TestCase { + + private MockControl pmfControl, pmControl, txControl; + + private PersistenceManagerFactory pmf; + + private PersistenceManager pm; + + private Transaction tx; + + + protected void setUp() { + pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + pmf = (PersistenceManagerFactory) pmfControl.getMock(); + pmControl = MockControl.createControl(PersistenceManager.class); + pm = (PersistenceManager) pmControl.getMock(); + txControl = MockControl.createControl(Transaction.class); + tx = (Transaction) txControl.getMock(); + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 1); + } + + protected void tearDown() { + try { + pmfControl.verify(); + pmControl.verify(); + } + catch (IllegalStateException ex) { + // ignore: test method didn't call replay + } + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + + public void testTransactionCommit() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + pm.flush(); + pmControl.setVoidCallable(2); + pm.close(); + pmControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + TransactionTemplate tt = new TransactionTemplate(tm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + + TransactionAwarePersistenceManagerFactoryProxy proxyFactory = + new TransactionAwarePersistenceManagerFactoryProxy(); + proxyFactory.setTargetPersistenceManagerFactory(pmf); + PersistenceManagerFactory proxy = (PersistenceManagerFactory) proxyFactory.getObject(); + assertEquals(pm.toString(), proxy.getPersistenceManager().toString()); + proxy.getPersistenceManager().flush(); + proxy.getPersistenceManager().close(); + + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + public void testTransactionRollback() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 2); + pm.close(); + pmControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + tx.isActive(); + txControl.setReturnValue(true, 1); + tx.rollback(); + txControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new RuntimeException("application exception"); + } + }); + } + }); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException ex) { + // expected + } + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + public void testTransactionRollbackWithAlreadyRolledBack() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 2); + pm.close(); + pmControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + tx.isActive(); + txControl.setReturnValue(false, 1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new RuntimeException("application exception"); + } + }); + } + }); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException ex) { + // expected + } + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + public void testTransactionRollbackOnly() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 2); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + tx.isActive(); + txControl.setReturnValue(true, 1); + tx.rollback(); + txControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + TransactionTemplate tt = new TransactionTemplate(tm); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + JdoTemplate jt = new JdoTemplate(pmf); + jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return null; + } + }); + status.setRollbackOnly(); + return null; + } + }); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + } + + public void testParticipatingTransactionWithCommit() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + final TransactionTemplate tt = new TransactionTemplate(tm); + final List l = new ArrayList(); + l.add("test"); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.reset(); + tx.isActive(); + txControl.setReturnValue(true, 1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + txControl.replay(); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + } + }); + } + }); + assertTrue("Correct result list", result == l); + } + + public void testParticipatingTransactionWithRollback() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + pm.close(); + pmControl.setVoidCallable(1); + tx.isActive(); + txControl.setReturnValue(false, 1); + tx.begin(); + txControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + final TransactionTemplate tt = new TransactionTemplate(tm); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.reset(); + tx.isActive(); + txControl.setReturnValue(true, 3); + tx.setRollbackOnly(); + txControl.setVoidCallable(1); + tx.rollback(); + txControl.setVoidCallable(1); + txControl.replay(); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + throw new RuntimeException("application exception"); + } + }); + } + }); + } + }); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException ex) { + // expected + } + } + + public void testParticipatingTransactionWithRollbackOnly() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 5); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + tx.begin(); + txControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + final TransactionTemplate tt = new TransactionTemplate(tm); + final List l = new ArrayList(); + l.add("test"); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.reset(); + tx.isActive(); + txControl.setReturnValue(true, 1); + tx.setRollbackOnly(); + txControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(true, 1); + tx.commit(); + txControl.setThrowable(new JDOFatalDataStoreException(), 1); + tx.isActive(); + txControl.setReturnValue(false, 1); + txControl.replay(); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + JdoTemplate jt = new JdoTemplate(pmf); + jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + status.setRollbackOnly(); + return null; + } + }); + } + }); + fail("Should have thrown JdoResourceFailureException"); + } + catch (JdoResourceFailureException ex) { + // expected + } + } + + public void testParticipatingTransactionWithWithRequiresNew() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 2); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 6); + tx.begin(); + txControl.setVoidCallable(1); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(2); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + final List l = new ArrayList(); + l.add("test"); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.verify(); + txControl.reset(); + tx.isActive(); + txControl.setReturnValue(true, 1); + tx.begin(); + txControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 2); + tx.commit(); + txControl.setVoidCallable(2); + txControl.replay(); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + } + }); + } + }); + assertTrue("Correct result list", result == l); + } + + public void testParticipatingTransactionWithWithRequiresNewAndPrebound() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 3); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 6); + tx.begin(); + txControl.setVoidCallable(1); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + txControl.verify(); + txControl.reset(); + tx.isActive(); + txControl.setReturnValue(true, 1); + tx.begin(); + txControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 2); + tx.commit(); + txControl.setVoidCallable(2); + txControl.replay(); + + JdoTemplate jt = new JdoTemplate(pmf); + jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + return null; + } + }); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + TransactionSynchronizationManager.unbindResource(pmf); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + public void testJtaTransactionCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.flush(); + pmControl.setVoidCallable(2); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + JdoTemplate jt = new JdoTemplate(pmf); + jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + pm2.flush(); + return l; + } + }); + Object result = jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + pm2.flush(); + return l; + } + }); + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + return result; + } + }); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + utControl.verify(); + } + + public void testParticipatingJtaTransactionWithWithRequiresNewAndPrebound() throws Exception { + final MockControl utControl = MockControl.createControl(UserTransaction.class); + final UserTransaction ut = (UserTransaction) utControl.getMock(); + final MockControl tmControl = MockControl.createControl(TransactionManager.class); + final TransactionManager tm = (TransactionManager) tmControl.getMock(); + + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + utControl.replay(); + + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 1); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut, tm); + final TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + utControl.verify(); + utControl.reset(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.suspend(); + tmControl.setReturnValue(transaction, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 4); + ut.commit(); + utControl.setVoidCallable(2); + tm.resume(transaction); + tmControl.setVoidCallable(1); + utControl.replay(); + tmControl.replay(); + } + catch (Exception ex) { + } + + JdoTemplate jt = new JdoTemplate(pmf); + jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + return null; + } + }); + + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + TransactionSynchronizationManager.unbindResource(pmf); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + utControl.verify(); + } + + + public void testTransactionCommitWithPropagationSupports() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + } + + public void testInvalidIsolation() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 1); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(null, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + } + }); + fail("Should have thrown InvalidIsolationLevelException"); + } + catch (InvalidIsolationLevelException ex) { + // expected + } + } + + public void testTransactionCommitWithPrebound() { + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + tx.isActive(); + txControl.setReturnValue(false, 1); + tx.begin(); + txControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + + PlatformTransactionManager tm = new JdoTransactionManager(pmf); + TransactionTemplate tt = new TransactionTemplate(tm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + TransactionSynchronizationManager.unbindResource(pmf); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + } + + public void testTransactionCommitWithDataSource() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + ConnectionHandle conHandle = new SimpleConnectionHandle(con); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + pm.close(); + pmControl.setVoidCallable(1); + TransactionTemplate tt = new TransactionTemplate(); + dialect.beginTransaction(tx, tt); + dialectControl.setReturnValue(null, 1); + dialect.getJdbcConnection(pm, false); + dialectControl.setReturnValue(conHandle, 1); + dialect.releaseJdbcConnection(conHandle, pm); + dialectControl.setVoidCallable(1); + dialect.cleanupTransaction(null); + dialectControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + pmfControl.replay(); + dsControl.replay(); + dialectControl.replay(); + pmControl.replay(); + txControl.replay(); + conControl.replay(); + + JdoTransactionManager tm = new JdoTransactionManager(); + tm.setPersistenceManagerFactory(pmf); + tm.setDataSource(ds); + tm.setJdoDialect(dialect); + tt.setTransactionManager(tm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + dialectControl.verify(); + conControl.verify(); + } + + public void testTransactionCommitWithAutoDetectedDataSource() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + ConnectionHandle conHandle = new SimpleConnectionHandle(con); + + pmfControl.reset(); + pmf.getConnectionFactory(); + pmfControl.setReturnValue(ds, 2); + con.getMetaData(); + conControl.setReturnValue(null, 1); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + pm.close(); + pmControl.setVoidCallable(1); + TransactionTemplate tt = new TransactionTemplate(); + dialect.beginTransaction(tx, tt); + dialectControl.setReturnValue(null, 1); + dialect.getJdbcConnection(pm, false); + dialectControl.setReturnValue(conHandle, 1); + dialect.releaseJdbcConnection(conHandle, pm); + dialectControl.setVoidCallable(1); + dialect.cleanupTransaction(null); + dialectControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + pmfControl.replay(); + dsControl.replay(); + dialectControl.replay(); + pmControl.replay(); + txControl.replay(); + conControl.replay(); + + JdoTransactionManager tm = new JdoTransactionManager(); + tm.setPersistenceManagerFactory(pmf); + tm.setJdoDialect(dialect); + tm.afterPropertiesSet(); + tt.setTransactionManager(tm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm) { + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + dialectControl.verify(); + conControl.verify(); + } + + public void testTransactionCommitWithAutoDetectedDataSourceAndNoConnection() throws SQLException { + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + final JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + + pmfControl.reset(); + pmf.getConnectionFactory(); + pmfControl.setReturnValue(ds, 1); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + TransactionTemplate tt = new TransactionTemplate(); + dialect.beginTransaction(tx, tt); + dialectControl.setReturnValue(null, 1); + dialect.getJdbcConnection(pm, false); + dialectControl.setReturnValue(null, 1); + dialect.cleanupTransaction(null); + dialectControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + pmfControl.replay(); + dsControl.replay(); + dialectControl.replay(); + pmControl.replay(); + txControl.replay(); + conControl.replay(); + + JdoTransactionManager tm = new JdoTransactionManager(); + tm.setPersistenceManagerFactory(pmf); + tm.setJdoDialect(dialect); + tm.afterPropertiesSet(); + tt.setTransactionManager(tm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); + JdoTemplate jt = new JdoTemplate(); + jt.setPersistenceManagerFactory(pmf); + jt.setJdoDialect(dialect); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + dialectControl.verify(); + conControl.verify(); + } + + public void testExistingTransactionWithPropagationNestedAndRollback() throws SQLException { + doTestExistingTransactionWithPropagationNestedAndRollback(false); + } + + public void testExistingTransactionWithManualSavepointAndRollback() throws SQLException { + doTestExistingTransactionWithPropagationNestedAndRollback(true); + } + + private void doTestExistingTransactionWithPropagationNestedAndRollback(final boolean manualSavepoint) + throws SQLException { + + MockControl dsControl = MockControl.createControl(DataSource.class); + final DataSource ds = (DataSource) dsControl.getMock(); + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + MockControl conControl = MockControl.createControl(Connection.class); + final Connection con = (Connection) conControl.getMock(); + MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); + DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); + MockControl spControl = MockControl.createControl(Savepoint.class); + Savepoint sp = (Savepoint) spControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + pm.flush(); + pmControl.setVoidCallable(1); + pm.close(); + pmControl.setVoidCallable(1); + md.supportsSavepoints(); + mdControl.setReturnValue(true, 1); + con.getMetaData(); + conControl.setReturnValue(md, 1); + con.setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1); + conControl.setReturnValue(sp, 1); + con.rollback(sp); + conControl.setVoidCallable(1); + final TransactionTemplate tt = new TransactionTemplate(); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + dialect.beginTransaction(tx, tt); + dialectControl.setReturnValue(null, 1); + ConnectionHandle conHandle = new SimpleConnectionHandle(con); + dialect.getJdbcConnection(pm, false); + dialectControl.setReturnValue(conHandle, 1); + dialect.releaseJdbcConnection(conHandle, pm); + dialectControl.setVoidCallable(1); + dialect.cleanupTransaction(null); + dialectControl.setVoidCallable(1); + if (!manualSavepoint) { + tx.isActive(); + txControl.setReturnValue(true, 1); + } + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + pmfControl.replay(); + dsControl.replay(); + dialectControl.replay(); + pmControl.replay(); + txControl.replay(); + conControl.replay(); + mdControl.replay(); + spControl.replay(); + + JdoTransactionManager tm = new JdoTransactionManager(); + tm.setNestedTransactionAllowed(true); + tm.setPersistenceManagerFactory(pmf); + tm.setDataSource(ds); + tm.setJdoDialect(dialect); + tt.setTransactionManager(tm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); + if (manualSavepoint) { + Object savepoint = status.createSavepoint(); + status.rollbackToSavepoint(savepoint); + } + else { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); + status.setRollbackOnly(); + } + }); + } + JdoTemplate jt = new JdoTemplate(pmf); + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + pm2.flush(); + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); + dsControl.verify(); + dialectControl.verify(); + conControl.verify(); + mdControl.verify(); + spControl.verify(); + } + + public void testTransactionTimeoutWithJdoDialect() throws SQLException { + doTestTransactionTimeoutWithJdoDialect(true); + } + + public void testTransactionTimeoutWithJdoDialectAndPmProxy() throws SQLException { + doTestTransactionTimeoutWithJdoDialect(false); + } + + private void doTestTransactionTimeoutWithJdoDialect(final boolean exposeNativePm) throws SQLException { + MockControl queryControl = MockControl.createControl(Query.class); + Query query = (Query) queryControl.getMock(); + MockControl dialectControl = MockControl.createControl(JdoDialect.class); + final JdoDialect dialect = (JdoDialect) dialectControl.getMock(); + + TransactionTemplate tt = new TransactionTemplate(); + + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 2); + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.currentTransaction(); + pmControl.setReturnValue(tx, 3); + dialect.beginTransaction(tx, tt); + dialectControl.setReturnValue(null, 1); + if (!exposeNativePm) { + dialect.applyQueryTimeout(query, 10); + } + dialect.cleanupTransaction(null); + dialectControl.setVoidCallable(1); + pm.newQuery(TestBean.class); + pmControl.setReturnValue(query, 1); + pm.close(); + pmControl.setVoidCallable(1); + tx.getRollbackOnly(); + txControl.setReturnValue(false, 1); + tx.commit(); + txControl.setVoidCallable(1); + + pmfControl.replay(); + pmControl.replay(); + txControl.replay(); + queryControl.replay(); + dialectControl.replay(); + + JdoTransactionManager tm = new JdoTransactionManager(pmf); + tm.setJdoDialect(dialect); + tt.setTransactionManager(tm); + tt.setTimeout(10); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); + JdoTemplate jt = new JdoTemplate(pmf); + jt.setJdoDialect(dialect); + if (exposeNativePm) { + jt.setExposeNativePersistenceManager(true); + } + return jt.execute(new JdoCallback() { + public Object doInJdo(PersistenceManager pm2) { + if (exposeNativePm) { + assertSame(pm, pm2); + } + else { + assertTrue(Proxy.isProxyClass(pm2.getClass())); + } + pm2.newQuery(TestBean.class); + return null; + } + }); + } + }); + + assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + dialectControl.verify(); + queryControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/LocalPersistenceManagerFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/LocalPersistenceManagerFactoryTests.java new file mode 100644 index 00000000000..5ad9c14d397 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/LocalPersistenceManagerFactoryTests.java @@ -0,0 +1,146 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jdo; + +import java.io.IOException; +import java.util.Map; +import java.util.Properties; + +import javax.jdo.JDOFatalUserException; +import javax.jdo.PersistenceManagerFactory; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.core.io.ClassPathResource; + +/** + * @author Juergen Hoeller + */ +public class LocalPersistenceManagerFactoryTests extends TestCase { + + public void testLocalPersistenceManagerFactoryBean() throws IOException { + MockControl pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + final PersistenceManagerFactory pmf = (PersistenceManagerFactory) pmfControl.getMock(); + LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { + protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) { + return pmf; + } + }; + pmfb.setJdoProperties(new Properties()); + pmfb.afterPropertiesSet(); + assertSame(pmf, pmfb.getObject()); + } + + public void testLocalPersistenceManagerFactoryBeanWithInvalidSettings() throws IOException { + LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean(); + try { + pmfb.afterPropertiesSet(); + fail("Should have thrown JDOFatalUserException"); + } + catch (JDOFatalUserException ex) { + // expected + } + } + + public void testLocalPersistenceManagerFactoryBeanWithIncompleteProperties() throws IOException { + LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean(); + Properties props = new Properties(); + props.setProperty("myKey", "myValue"); + pmfb.setJdoProperties(props); + try { + pmfb.afterPropertiesSet(); + fail("Should have thrown JDOFatalUserException"); + } + catch (JDOFatalUserException ex) { + // expected + } + } + + public void testLocalPersistenceManagerFactoryBeanWithInvalidProperty() throws IOException { + LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { + protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) { + throw new IllegalArgumentException((String) props.get("myKey")); + } + }; + Properties props = new Properties(); + props.setProperty("myKey", "myValue"); + pmfb.setJdoProperties(props); + try { + pmfb.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + assertTrue("Correct exception", "myValue".equals(ex.getMessage())); + } + } + + public void testLocalPersistenceManagerFactoryBeanWithFile() throws IOException { + LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { + protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) { + throw new IllegalArgumentException((String) props.get("myKey")); + } + }; + pmfb.setConfigLocation(new ClassPathResource("test.properties", getClass())); + try { + pmfb.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + assertTrue("Correct exception", "myValue".equals(ex.getMessage())); + } + } + + public void testLocalPersistenceManagerFactoryBeanWithName() throws IOException { + LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { + protected PersistenceManagerFactory newPersistenceManagerFactory(String name) { + throw new IllegalArgumentException(name); + } + }; + pmfb.setPersistenceManagerFactoryName("myName"); + try { + pmfb.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + assertTrue("Correct exception", "myName".equals(ex.getMessage())); + } + } + + public void testLocalPersistenceManagerFactoryBeanWithNameAndProperties() throws IOException { + LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { + protected PersistenceManagerFactory newPersistenceManagerFactory(String name) { + throw new IllegalArgumentException(name); + } + }; + pmfb.setPersistenceManagerFactoryName("myName"); + pmfb.getJdoPropertyMap().put("myKey", "myValue"); + try { + pmfb.afterPropertiesSet(); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + assertTrue(ex.getMessage().indexOf("persistenceManagerFactoryName") != -1); + assertTrue(ex.getMessage().indexOf("jdoProp") != -1); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/JdoDaoSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/JdoDaoSupportTests.java new file mode 100644 index 00000000000..89b3987b111 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/JdoDaoSupportTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jdo.support; + +import java.util.ArrayList; +import java.util.List; + +import javax.jdo.PersistenceManagerFactory; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.orm.jdo.JdoTemplate; + +/** + * @author Juergen Hoeller + * @since 30.07.2003 + */ +public class JdoDaoSupportTests extends TestCase { + + public void testJdoDaoSupportWithPersistenceManagerFactory() throws Exception { + MockControl pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + PersistenceManagerFactory pmf = (PersistenceManagerFactory) pmfControl.getMock(); + pmf.getConnectionFactory(); + pmfControl.setReturnValue(null, 1); + pmfControl.replay(); + final List test = new ArrayList(); + JdoDaoSupport dao = new JdoDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setPersistenceManagerFactory(pmf); + dao.afterPropertiesSet(); + assertEquals("Correct PersistenceManagerFactory", pmf, dao.getPersistenceManagerFactory()); + assertEquals("Correct JdoTemplate", pmf, dao.getJdoTemplate().getPersistenceManagerFactory()); + assertEquals("initDao called", test.size(), 1); + pmfControl.verify(); + } + + public void testJdoDaoSupportWithJdoTemplate() throws Exception { + JdoTemplate template = new JdoTemplate(); + final List test = new ArrayList(); + JdoDaoSupport dao = new JdoDaoSupport() { + protected void initDao() { + test.add("test"); + } + }; + dao.setJdoTemplate(template); + dao.afterPropertiesSet(); + assertEquals("Correct JdoTemplate", template, dao.getJdoTemplate()); + assertEquals("initDao called", test.size(), 1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewTests.java new file mode 100644 index 00000000000..cd34f0a5b84 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewTests.java @@ -0,0 +1,183 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jdo.support; + +import java.io.IOException; + +import javax.jdo.PersistenceManager; +import javax.jdo.PersistenceManagerFactory; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.mock.web.PassThroughFilterChain; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter; + +/** + * @author Juergen Hoeller + * @since 15.06.2004 + */ +public class OpenPersistenceManagerInViewTests extends TestCase { + + public void testOpenPersistenceManagerInViewInterceptor() throws Exception { + MockControl pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + PersistenceManagerFactory pmf = (PersistenceManagerFactory) pmfControl.getMock(); + MockControl pmControl = MockControl.createControl(PersistenceManager.class); + PersistenceManager pm = (PersistenceManager) pmControl.getMock(); + + OpenPersistenceManagerInViewInterceptor rawInterceptor = new OpenPersistenceManagerInViewInterceptor(); + rawInterceptor.setPersistenceManagerFactory(pmf); + HandlerInterceptor interceptor = new WebRequestHandlerInterceptorAdapter(rawInterceptor); + + MockServletContext sc = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pmfControl.replay(); + pmControl.replay(); + interceptor.preHandle(request, response, "handler"); + assertTrue(TransactionSynchronizationManager.hasResource(pmf)); + + // check that further invocations simply participate + interceptor.preHandle(request, response, "handler"); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + interceptor.preHandle(request, response, "handler"); + interceptor.postHandle(request, response, "handler", null); + interceptor.afterCompletion(request, response, "handler", null); + + pmfControl.verify(); + pmControl.verify(); + + pmfControl.reset(); + pmControl.reset(); + pmfControl.replay(); + pmControl.replay(); + interceptor.postHandle(request, response, "handler", null); + assertTrue(TransactionSynchronizationManager.hasResource(pmf)); + pmfControl.verify(); + pmControl.verify(); + + pmfControl.reset(); + pmControl.reset(); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + interceptor.afterCompletion(request, response, "handler", null); + assertFalse(TransactionSynchronizationManager.hasResource(pmf)); + pmfControl.verify(); + pmControl.verify(); + } + + public void testOpenPersistenceManagerInViewFilter() throws Exception { + MockControl pmfControl = MockControl.createControl(PersistenceManagerFactory.class); + final PersistenceManagerFactory pmf = (PersistenceManagerFactory) pmfControl.getMock(); + MockControl pmControl = MockControl.createControl(PersistenceManager.class); + PersistenceManager pm = (PersistenceManager) pmControl.getMock(); + + pmf.getPersistenceManager(); + pmfControl.setReturnValue(pm, 1); + pm.close(); + pmControl.setVoidCallable(1); + pmfControl.replay(); + pmControl.replay(); + + MockControl pmf2Control = MockControl.createControl(PersistenceManagerFactory.class); + final PersistenceManagerFactory pmf2 = (PersistenceManagerFactory) pmf2Control.getMock(); + MockControl pm2Control = MockControl.createControl(PersistenceManager.class); + PersistenceManager pm2 = (PersistenceManager) pm2Control.getMock(); + + pmf2.getPersistenceManager(); + pmf2Control.setReturnValue(pm2, 1); + pm2.close(); + pm2Control.setVoidCallable(1); + pmf2Control.replay(); + pm2Control.replay(); + + MockServletContext sc = new MockServletContext(); + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.getDefaultListableBeanFactory().registerSingleton("persistenceManagerFactory", pmf); + wac.getDefaultListableBeanFactory().registerSingleton("myPersistenceManagerFactory", pmf2); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); + filterConfig2.addInitParameter("persistenceManagerFactoryBeanName", "myPersistenceManagerFactory"); + + final OpenPersistenceManagerInViewFilter filter = new OpenPersistenceManagerInViewFilter(); + filter.init(filterConfig); + final OpenPersistenceManagerInViewFilter filter2 = new OpenPersistenceManagerInViewFilter(); + filter2.init(filterConfig2); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { + assertTrue(TransactionSynchronizationManager.hasResource(pmf)); + servletRequest.setAttribute("invoked", Boolean.TRUE); + } + }; + + final FilterChain filterChain2 = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + assertTrue(TransactionSynchronizationManager.hasResource(pmf2)); + filter.doFilter(servletRequest, servletResponse, filterChain); + } + }; + + FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2); + + assertFalse(TransactionSynchronizationManager.hasResource(pmf)); + assertFalse(TransactionSynchronizationManager.hasResource(pmf2)); + filter2.doFilter(request, response, filterChain3); + assertFalse(TransactionSynchronizationManager.hasResource(pmf)); + assertFalse(TransactionSynchronizationManager.hasResource(pmf2)); + assertNotNull(request.getAttribute("invoked")); + + pmfControl.verify(); + pmControl.verify(); + pmf2Control.verify(); + pm2Control.verify(); + + wac.close(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/test.properties b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/test.properties new file mode 100644 index 00000000000..cd4acea9278 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/jdo/test.properties @@ -0,0 +1 @@ +myKey=myValue diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/MockSessionFactory.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/MockSessionFactory.java new file mode 100644 index 00000000000..be223561394 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/MockSessionFactory.java @@ -0,0 +1,37 @@ + +package org.springframework.orm.toplink; + +import oracle.toplink.sessions.Session; + +/** + * @author Juergen Hoeller + * @since 28.04.2005 + */ +public class MockSessionFactory implements SessionFactory { + + private Session session; + + public MockSessionFactory(Session session) { + this.session = session; + } + + public void setSession(Session session) { + this.session = session; + } + + public Session createSession() { + return this.session; + } + + public Session createManagedClientSession() { + return this.session; + } + + public Session createTransactionAwareSession() { + return this.session; + } + + public void close() { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionBrokerFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionBrokerFactoryTests.java new file mode 100644 index 00000000000..c8dbcd3899e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionBrokerFactoryTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.toplink; + +import junit.framework.TestCase; +import oracle.toplink.exceptions.ValidationException; +import oracle.toplink.publicinterface.UnitOfWork; +import oracle.toplink.sessionbroker.SessionBroker; +import oracle.toplink.sessions.Session; + +/** + * @author James Clark + */ +public class SessionBrokerFactoryTests extends TestCase { + + /* + * When acquiring ClientSessionBrokers, the SessionBroker can throw RuntimeExceptions indicating + * that this SessionBroker is not capable of creating "client" Sessions. We need to handle + * these differently depending on how the SessionFactory is being used. If we are creating a + * plain Session than we can return the original SessionBroker. + */ + public void testSessionBrokerThrowingValidationException() { + SessionBroker broker = new MockSingleSessionBroker(); + SessionBrokerSessionFactory factory = new SessionBrokerSessionFactory(broker); + + assertEquals(factory.createSession(), broker); + try { + factory.createManagedClientSession(); + fail("Should have thrown ValidationException"); + } + catch (ValidationException ex) { + // expected + } + } + + /** + * Insure that the managed TopLink Session proxy is behaving correctly + * when it has been initialized with a SessionBroker. + */ + public void testManagedSessionBroker() { + SessionBroker client = new MockClientSessionBroker(); + SessionBroker broker = new MockServerSessionBroker(client); + SessionBrokerSessionFactory factory = new SessionBrokerSessionFactory(broker); + + assertEquals(client, factory.createSession()); + + Session session = factory.createManagedClientSession(); + assertEquals(client, session.getActiveSession()); + assertNotNull(session.getActiveUnitOfWork()); + assertEquals(session.getActiveUnitOfWork(), session.getActiveUnitOfWork()); + } + + + private class MockSingleSessionBroker extends SessionBroker { + + public MockSingleSessionBroker() { + } + + public SessionBroker acquireClientSessionBroker() { + throw new ValidationException(); + } + } + + + private class MockServerSessionBroker extends SessionBroker { + + private SessionBroker client; + + public MockServerSessionBroker(SessionBroker client) { + this.client = client; + } + + public SessionBroker acquireClientSessionBroker() { + return client; + } + } + + + private class MockClientSessionBroker extends SessionBroker { + + public MockClientSessionBroker() { + } + + public UnitOfWork acquireUnitOfWork() { + return new UnitOfWork(this); + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionFactoryUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionFactoryUtilsTests.java new file mode 100644 index 00000000000..99dcc54994a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/SessionFactoryUtilsTests.java @@ -0,0 +1,106 @@ +/* + * Created on Mar 18, 2005 + * + */ + +package org.springframework.orm.toplink; + +import junit.framework.TestCase; +import oracle.toplink.sessions.Session; +import org.easymock.MockControl; + +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + * @author James Clark + * @since 28.04.2005 + */ +public class SessionFactoryUtilsTests extends TestCase { + + /** + * When no Session is bound and allowCreate is "false", we should throw an IllegalStateException. + * When no Session is bound, and allowCreate is "true", we should get a Session but it should not + * be bound to the Thread afterwards. + */ + public void testNoSessionBound() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + session.hasExternalTransactionController(); + sessionControl.setReturnValue(false, 1); + + sessionControl.replay(); + try { + Session boundSession = SessionFactoryUtils.getSession(factory, false); + fail(); + } + catch (Throwable t) { + assertTrue(t.getClass().equals(IllegalStateException.class)); + } + + Session boundSession = SessionFactoryUtils.getSession(factory, true); + assertTrue(session == boundSession); + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + + /** + * When called with no previous Session bound, "allowCreate", and "allowSynchronization", + * Session should be returned, it should be bound to the Thread, and a synchronization listener + * should be in the list of thread synchronizations. + */ + public void testNoSessionBoundAllowAndInit() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + session.hasExternalTransactionController(); + sessionControl.setReturnValue(false, 1); + + sessionControl.replay(); + + Session boundSession = SessionFactoryUtils.getSession(factory, true); + assertTrue(session == boundSession); + + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(factory); + assertTrue(holder == null); + + TransactionSynchronizationManager.initSynchronization(); + + boundSession = SessionFactoryUtils.getSession(factory, true); + assertTrue(session == boundSession); + assertTrue(TransactionSynchronizationManager.getSynchronizations().size() == 1); + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(session == ((SessionHolder) TransactionSynchronizationManager.getResource(factory)).getSession()); + + TransactionSynchronizationManager.clearSynchronization(); + TransactionSynchronizationManager.unbindResource(factory); + } + + public void testNoSessionBoundAllowAndNoInit() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + session.hasExternalTransactionController(); + sessionControl.setReturnValue(false, 2); + + sessionControl.replay(); + + Session boundSession = SessionFactoryUtils.getSession(factory, true); + assertTrue(session == boundSession); + + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(factory); + assertTrue(holder == null); + + boundSession = SessionFactoryUtils.getSession(factory, true); + assertTrue(session == boundSession); + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkInterceptorTests.java new file mode 100644 index 00000000000..819133c2ddc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkInterceptorTests.java @@ -0,0 +1,98 @@ +/* + * Created on Mar 20, 2005 + * + */ + +package org.springframework.orm.toplink; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; + +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import oracle.toplink.sessions.Session; + +/** + * @author Juergen Hoeller + * @author James Clark + * @since 28.04.2005 + */ +public class TopLinkInterceptorTests extends TestCase { + + public void testInterceptorWithNoSessionBoundAndNoSynchronizations() throws Throwable { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl methodInvocationControl = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) methodInvocationControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + TopLinkInterceptor interceptor = new TopLinkInterceptor(); + interceptor.setSessionFactory(factory); + + methodInvocation.proceed(); + methodInvocationControl.setReturnValue(null, 1); + session.release(); + sessionControl.setVoidCallable(1); + + methodInvocationControl.replay(); + sessionControl.replay(); + + try { + interceptor.invoke(methodInvocation); + } + catch (Throwable t) { + System.out.println(t); + t.printStackTrace(); + fail(); + } + + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + + sessionControl.verify(); + methodInvocationControl.verify(); + sessionControl.verify(); + } + + public void testInterceptorWithNoSessionBoundAndSynchronizationsActive() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + MockControl methodInvocationControl = MockControl.createControl(MethodInvocation.class); + MethodInvocation methodInvocation = (MethodInvocation) methodInvocationControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + TopLinkInterceptor interceptor = new TopLinkInterceptor(); + interceptor.setSessionFactory(factory); + + try { + methodInvocation.proceed(); + } + catch (Throwable e) { + fail(); + } + methodInvocationControl.setReturnValue(null, 1); + + methodInvocationControl.replay(); + sessionControl.replay(); + + TransactionSynchronizationManager.initSynchronization(); + try { + interceptor.invoke(methodInvocation); + } + catch (Throwable t) { + fail(); + } + + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + assertTrue(TransactionSynchronizationManager.getSynchronizations().size() == 1); + + TransactionSynchronizationManager.clearSynchronization(); + TransactionSynchronizationManager.unbindResource(factory); + + sessionControl.verify(); + methodInvocationControl.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkJtaTransactionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkJtaTransactionTests.java new file mode 100644 index 00000000000..398a814749d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkJtaTransactionTests.java @@ -0,0 +1,321 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.toplink; + +import java.util.ArrayList; +import java.util.List; + +import javax.transaction.Status; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import org.easymock.MockControl; + +import org.springframework.transaction.MockJtaTransaction; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.jta.JtaTransactionManager; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @author James Clark + * @since 28.04.2005 + */ +public class TopLinkJtaTransactionTests extends TestCase { + + public void testParticipatingJtaTransactionWithWithRequiresNew() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl tx1Control = MockControl.createControl(javax.transaction.Transaction.class); + javax.transaction.Transaction tx1 = (javax.transaction.Transaction) tx1Control.getMock(); + + MockControl session1Control = MockControl.createControl(Session.class); + Session session1 = (Session) session1Control.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + final MockSessionFactory sf = new MockSessionFactory(session1); + + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 5); + ut.begin(); + utControl.setVoidCallable(2); + tm.suspend(); + tmControl.setReturnValue(tx1, 1); + tm.resume(tx1); + tmControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(2); + +// session1.hasExternalTransactionController(); +// session1Control.setReturnValue(true,1); + session1.release(); + session1Control.setVoidCallable(1); +// session2.hasExternalTransactionController(); +// session2Control.setReturnValue(true,1); + session2.release(); + session2Control.setVoidCallable(1); + + utControl.replay(); + tmControl.replay(); + session1Control.replay(); + session2Control.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(); + ptm.setUserTransaction(ut); + ptm.setTransactionManager(tm); + final TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + SessionFactoryUtils.getSession(sf, true); + final SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + sf.setSession(session2); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + TopLinkTemplate ht = new TopLinkTemplate(sf); + return ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session session) { + assertTrue("Not enclosing session", session != holder.getSession()); + return null; + } + }); + } + }); + assertTrue("Same thread session as before", + holder.getSession() == SessionFactoryUtils.getSession(sf, false)); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + utControl.verify(); + tmControl.verify(); + session1Control.verify(); + session2Control.verify(); + } + + public void testJtaTransactionCommit() throws Exception { + doTestJtaTransactionCommit(Status.STATUS_NO_TRANSACTION); + } + + public void testJtaTransactionCommitWithExisting() throws Exception { + doTestJtaTransactionCommit(Status.STATUS_ACTIVE); + } + + private void doTestJtaTransactionCommit(int status) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(status, 1); + if (status == Status.STATUS_NO_TRANSACTION) { + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + utControl.setVoidCallable(1); + } + else { + ut.getStatus(); + utControl.setReturnValue(status, 1); + } + utControl.replay(); + + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + final SessionFactory sf = new SingleSessionFactory(session); + + sessionControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + TopLinkTemplate ht = new TopLinkTemplate(sf); + List htl = ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + + ht = new TopLinkTemplate(sf); + htl = ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + + sessionControl.verify(); + sessionControl.reset(); + + try { + session.release(); + sessionControl.setVoidCallable(1); + } + catch (TopLinkException e) { + } + sessionControl.replay(); + return htl; + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + + assertTrue("Correct result list", result == l); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + sessionControl.verify(); + } + + public void testJtaTransactionCommitWithJtaTm() throws Exception { + doTestJtaTransactionCommitWithJtaTm(Status.STATUS_NO_TRANSACTION); + } + + public void testJtaTransactionCommitWithJtaTmAndExisting() throws Exception { + doTestJtaTransactionCommitWithJtaTm(Status.STATUS_ACTIVE); + } + + private void doTestJtaTransactionCommitWithJtaTm(int status) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(status, 1); + if (status == Status.STATUS_NO_TRANSACTION) { + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + utControl.setVoidCallable(1); + } + else { + ut.getStatus(); + utControl.setReturnValue(status, 1); + } + + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction transaction = new MockJtaTransaction(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 6); + tm.getTransaction(); + tmControl.setReturnValue(transaction, 6); + + final MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + final SessionFactory sf = new SingleSessionFactory(session); + + utControl.replay(); + tmControl.replay(); + sessionControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + final List l = new ArrayList(); + l.add("test"); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + try { + assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + TopLinkTemplate ht = new TopLinkTemplate(sf); + List htl = ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + + ht = new TopLinkTemplate(sf); + htl = ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session sess) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + assertEquals(session, sess); + return l; + } + }); + + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + sessionControl.verify(); + sessionControl.reset(); + try { + session.release(); + sessionControl.setVoidCallable(1); + } + catch (TopLinkException e) { + } + sessionControl.replay(); + return htl; + } + catch (Error err) { + err.printStackTrace(); + throw err; + } + } + }); + + assertTrue("Correct result list", result == l); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + sessionControl.verify(); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTemplateTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTemplateTests.java new file mode 100644 index 00000000000..73adb96ea18 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTemplateTests.java @@ -0,0 +1,117 @@ +/* + * Created on Mar 20, 2005 + * + */ + +package org.springframework.orm.toplink; + +import junit.framework.TestCase; +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import org.easymock.MockControl; + +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + * @author James Clark + * @since 28.04.2005 + */ +public class TopLinkTemplateTests extends TestCase { + + public void testTemplateNotAllowingCreate() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + TopLinkTemplate template = new TopLinkTemplate(); + template.setAllowCreate(false); + template.setSessionFactory(factory); + try { + template.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) throws TopLinkException { + return null; + } + }); + fail(); + } + catch (Exception e) { + } + } + + public void testTemplateWithCreate() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + session.release(); + sessionControl.setVoidCallable(1); + + sessionControl.replay(); + + TopLinkTemplate template = new TopLinkTemplate(); + template.setAllowCreate(true); + template.setSessionFactory(factory); + template.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) throws TopLinkException { + assertTrue(session != null); + return null; + } + }); + assertFalse(TransactionSynchronizationManager.hasResource(factory)); + + sessionControl.verify(); + } + + public void testTemplateWithExistingSessionAndNoCreate() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + sessionControl.replay(); + + SessionHolder sessionHolder = new SessionHolder(factory.createSession()); + TransactionSynchronizationManager.bindResource(factory, sessionHolder); + + TopLinkTemplate template = new TopLinkTemplate(); + template.setAllowCreate(false); + template.setSessionFactory(factory); + template.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) throws TopLinkException { + assertTrue(session != null); + return null; + } + }); + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + sessionControl.verify(); + TransactionSynchronizationManager.unbindResource(factory); + } + + public void testTemplateWithExistingSessionAndCreateAllowed() { + MockControl sessionControl = MockControl.createControl(Session.class); + Session session = (Session) sessionControl.getMock(); + + SessionFactory factory = new SingleSessionFactory(session); + + sessionControl.replay(); + + SessionHolder sessionHolder = new SessionHolder(factory.createSession()); + TransactionSynchronizationManager.bindResource(factory, sessionHolder); + + TopLinkTemplate template = new TopLinkTemplate(); + template.setAllowCreate(true); + template.setSessionFactory(factory); + template.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) throws TopLinkException { + assertTrue(session != null); + return null; + } + }); + assertTrue(TransactionSynchronizationManager.hasResource(factory)); + sessionControl.verify(); + TransactionSynchronizationManager.unbindResource(factory); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTransactionManagerTests.java new file mode 100644 index 00000000000..0b97b6654b4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/orm/toplink/TopLinkTransactionManagerTests.java @@ -0,0 +1,496 @@ +/* + * Created on Mar 20, 2005 + * + */ + +package org.springframework.orm.toplink; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import oracle.toplink.sessions.Session; +import oracle.toplink.sessions.UnitOfWork; +import org.easymock.MockControl; + +import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.UnexpectedRollbackException; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @author James Clark + * @since 28.04.2005 + */ +public class TopLinkTransactionManagerTests extends TestCase { + + public void testTransactionCommit() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl uowControl = MockControl.createControl(UnitOfWork.class); + UnitOfWork uow = (UnitOfWork) uowControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + + // during commit, TM must get the active UnitOfWork + session.getActiveUnitOfWork(); + sessionControl.setReturnValue(uow, 2); + uow.beginEarlyTransaction(); + uowControl.setVoidCallable(1); + uow.commit(); + uowControl.setVoidCallable(); + // session should be released when it was bound explicitly by the TM + session.release(); + sessionControl.setVoidCallable(); + + sessionControl.replay(); + uowControl.replay(); + + TopLinkTransactionManager tm = new TopLinkTransactionManager(); + tm.setJdbcExceptionTranslator(new SQLStateSQLExceptionTranslator()); + tm.setSessionFactory(sf); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + TopLinkTemplate template = new TopLinkTemplate(sf); + return template.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) { + return null; + } + }); + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + sessionControl.verify(); + uowControl.verify(); + } + + public void testTransactionRollback() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl uowControl = MockControl.createControl(UnitOfWork.class); + UnitOfWork uow = (UnitOfWork) uowControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + + session.getActiveUnitOfWork(); + sessionControl.setReturnValue(uow, 1); + uow.beginEarlyTransaction(); + uowControl.setVoidCallable(1); + session.release(); + sessionControl.setVoidCallable(1); + + sessionControl.replay(); + uowControl.replay(); + + TopLinkTransactionManager tm = new TopLinkTransactionManager(); + tm.setSessionFactory(sf); + tm.setJdbcExceptionTranslator(new SQLStateSQLExceptionTranslator()); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + try { + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + TopLinkTemplate template = new TopLinkTemplate(sf); + return template.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) { + throw new RuntimeException("failure"); + } + }); + } + }); + fail("Should have propagated RuntimeException"); + } + catch (RuntimeException ex) { + assertTrue(ex.getMessage().equals("failure")); + } + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + sessionControl.verify(); + uowControl.verify(); + } + + public void testTransactionRollbackOnly() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + session.release(); + sessionControl.setVoidCallable(); + sessionControl.replay(); + + TopLinkTransactionManager tm = new TopLinkTransactionManager(); + tm.setSessionFactory(sf); + tm.setLazyDatabaseTransaction(true); + tm.setJdbcExceptionTranslator(new SQLStateSQLExceptionTranslator()); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.setTimeout(10); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", + TransactionSynchronizationManager.hasResource(sf)); + TopLinkTemplate template = new TopLinkTemplate(sf); + template.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) { + return null; + } + }); + status.setRollbackOnly(); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + sessionControl.verify(); + } + + public void testParticipatingTransactionWithCommit() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl uowControl = MockControl.createControl(UnitOfWork.class); + UnitOfWork uow = (UnitOfWork) uowControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + + session.getActiveUnitOfWork(); + sessionControl.setReturnValue(uow, 2); + uow.beginEarlyTransaction(); + uowControl.setVoidCallable(1); + uow.commit(); + uowControl.setVoidCallable(); + session.release(); + sessionControl.setVoidCallable(); + + sessionControl.replay(); + uowControl.replay(); + + PlatformTransactionManager tm = new TopLinkTransactionManager(sf); + final TransactionTemplate tt = new TransactionTemplate(tm); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + TopLinkTemplate ht = new TopLinkTemplate(sf); + return ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session injectedSession) { + assertTrue(session == injectedSession); + return null; + } + }); + } + }); + } + }); + + sessionControl.verify(); + uowControl.verify(); + } + + public void testParticipatingTransactionWithRollback() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + + session.release(); + sessionControl.setVoidCallable(); + + sessionControl.replay(); + + TopLinkTransactionManager tm = new TopLinkTransactionManager(sf); + tm.setLazyDatabaseTransaction(true); + final TransactionTemplate tt = new TransactionTemplate(tm); + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + TopLinkTemplate ht = new TopLinkTemplate(sf); + return ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session session) { + throw new RuntimeException("application exception"); + } + }); + } + }); + } + }); + fail("Should not thrown RuntimeException"); + } + catch (RuntimeException ex) { + assertTrue(ex.getMessage().equals("application exception")); + } + sessionControl.verify(); + } + + public void testParticipatingTransactionWithRollbackOnly() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + final SessionFactory sf = new MockSessionFactory(session); + + session.release(); + sessionControl.setVoidCallable(); + + sessionControl.replay(); + + TopLinkTransactionManager tm = new TopLinkTransactionManager(sf); + tm.setLazyDatabaseTransaction(true); + final TransactionTemplate tt = new TransactionTemplate(tm); + + try { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + TopLinkTemplate ht = new TopLinkTemplate(sf); + ht.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) { + return null; + } + }); + status.setRollbackOnly(); + return null; + } + }); + return null; + } + }); + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + } + + sessionControl.verify(); + } + + public void testParticipatingTransactionWithWithRequiresNew() { + MockControl session1Control = MockControl.createControl(Session.class); + final Session session1 = (Session) session1Control.getMock(); + MockControl session2Control = MockControl.createControl(Session.class); + final Session session2 = (Session) session2Control.getMock(); + + MockControl uow1Control = MockControl.createControl(UnitOfWork.class); + UnitOfWork uow1 = (UnitOfWork) uow1Control.getMock(); + MockControl uow2Control = MockControl.createControl(UnitOfWork.class); + UnitOfWork uow2 = (UnitOfWork) uow2Control.getMock(); + + final MockSessionFactory sf = new MockSessionFactory(session1); + + session2.getActiveUnitOfWork(); + session2Control.setReturnValue(uow2, 2); + uow2.beginEarlyTransaction(); + uow2Control.setVoidCallable(1); + uow2.commit(); + uow2Control.setVoidCallable(); + session2.release(); + session2Control.setVoidCallable(); + + session1.getActiveUnitOfWork(); + session1Control.setReturnValue(uow1, 2); + uow1.beginEarlyTransaction(); + uow1Control.setVoidCallable(1); + uow1.commit(); + uow1Control.setVoidCallable(); + session1.release(); + session1Control.setVoidCallable(); + + session1Control.replay(); + uow1Control.replay(); + session2Control.replay(); + uow2Control.replay(); + + PlatformTransactionManager tm = new TopLinkTransactionManager(sf); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + final SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + sf.setSession(session2); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + TopLinkTemplate ht = new TopLinkTemplate(sf); + return ht.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) { + assertTrue("Not enclosing session", session != holder.getSession()); + return null; + } + }); + } + }); + assertTrue("Same thread session as before", + holder.getSession() == SessionFactoryUtils.getSession(sf, false)); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + session1Control.verify(); + session2Control.verify(); + uow1Control.verify(); + uow2Control.verify(); + } + + public void testParticipatingTransactionWithWithNotSupported() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl uowControl = MockControl.createControl(UnitOfWork.class); + UnitOfWork uow = (UnitOfWork) uowControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + + session.getActiveUnitOfWork(); + sessionControl.setReturnValue(uow, 2); + uow.beginEarlyTransaction(); + uowControl.setVoidCallable(1); + uow.commit(); + uowControl.setVoidCallable(); + session.release(); + sessionControl.setVoidCallable(2); + + sessionControl.replay(); + uowControl.replay(); + + TopLinkTransactionManager tm = new TopLinkTransactionManager(sf); + final TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); + assertTrue("Has thread session", holder != null); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + TopLinkTemplate ht = new TopLinkTemplate(sf); + + return ht.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) { + return null; + } + }); + } + }); + assertTrue("Same thread session as before", holder.getSession() == SessionFactoryUtils.getSession(sf, false)); + return null; + } + }); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + sessionControl.verify(); + uowControl.verify(); + } + + public void testTransactionWithPropagationSupports() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + + // not a new transaction, won't start a new one + session.release(); + sessionControl.setVoidCallable(); + + sessionControl.replay(); + + PlatformTransactionManager tm = new TopLinkTransactionManager(sf); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + + tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("Is not new transaction", !status.isNewTransaction()); + TopLinkTemplate ht = new TopLinkTemplate(sf); + ht.execute(new TopLinkCallback() { + public Object doInTopLink(Session session) { + return null; + } + }); + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + return null; + } + }); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + sessionControl.verify(); + } + + public void testTransactionCommitWithReadOnly() { + MockControl sessionControl = MockControl.createControl(Session.class); + final Session session = (Session) sessionControl.getMock(); + MockControl uowControl = MockControl.createControl(UnitOfWork.class); + UnitOfWork uow = (UnitOfWork) uowControl.getMock(); + + final SessionFactory sf = new MockSessionFactory(session); + + session.release(); + sessionControl.setVoidCallable(); + + sessionControl.replay(); + uowControl.replay(); + + TopLinkTransactionManager tm = new TopLinkTransactionManager(sf); + TransactionTemplate tt = new TransactionTemplate(tm); + tt.setReadOnly(true); + final List l = new ArrayList(); + l.add("test"); + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + + Object result = tt.execute(new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); + TopLinkTemplate ht = new TopLinkTemplate(sf); + return ht.executeFind(new TopLinkCallback() { + public Object doInTopLink(Session session) { + return l; + } + }); + } + }); + assertTrue("Correct result list", result == l); + + assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); + assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); + sessionControl.verify(); + uowControl.verify(); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerTests.java new file mode 100644 index 00000000000..25a3bd2717b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerTests.java @@ -0,0 +1,469 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.httpinvoker; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.support.DefaultRemoteInvocationExecutor; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationFactory; +import org.springframework.remoting.support.RemoteInvocationResult; + +/** + * @author Juergen Hoeller + * @since 09.08.2004 + */ +public class HttpInvokerTests extends TestCase { + + public void testHttpInvokerProxyFactoryBeanAndServiceExporter() throws Throwable { + doTestHttpInvokerProxyFactoryBeanAndServiceExporter(false); + } + + public void testHttpInvokerProxyFactoryBeanAndServiceExporterWithExplicitClassLoader() throws Throwable { + doTestHttpInvokerProxyFactoryBeanAndServiceExporter(true); + } + + private void doTestHttpInvokerProxyFactoryBeanAndServiceExporter(boolean explicitClassLoader) throws Throwable { + TestBean target = new TestBean("myname", 99); + + final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setServiceInterface(ITestBean.class); + exporter.setService(target); + exporter.afterPropertiesSet(); + + HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); + pfb.setServiceInterface(ITestBean.class); + pfb.setServiceUrl("http://myurl"); + + pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { + protected RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { + assertEquals("http://myurl", config.getServiceUrl()); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setContent(baos.toByteArray()); + exporter.handleRequest(request, response); + return readRemoteInvocationResult( + new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); + } + }); + if (explicitClassLoader) { + ((BeanClassLoaderAware) pfb.getHttpInvokerRequestExecutor()).setBeanClassLoader(getClass().getClassLoader()); + } + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + assertEquals("myname", proxy.getName()); + assertEquals(99, proxy.getAge()); + proxy.setAge(50); + assertEquals(50, proxy.getAge()); + proxy.setStringArray(new String[] {"str1", "str2"}); + assertTrue(Arrays.equals(new String[] {"str1", "str2"}, proxy.getStringArray())); + + try { + proxy.exceptional(new IllegalStateException()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + try { + proxy.exceptional(new IllegalAccessException()); + fail("Should have thrown IllegalAccessException"); + } + catch (IllegalAccessException ex) { + // expected + } + } + + public void testHttpInvokerProxyFactoryBeanAndServiceExporterWithIOException() throws Exception { + TestBean target = new TestBean("myname", 99); + + final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setServiceInterface(ITestBean.class); + exporter.setService(target); + exporter.afterPropertiesSet(); + + HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); + pfb.setServiceInterface(ITestBean.class); + pfb.setServiceUrl("http://myurl"); + + pfb.setHttpInvokerRequestExecutor(new HttpInvokerRequestExecutor() { + public RemoteInvocationResult executeRequest( + HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws IOException { + throw new IOException("argh"); + } + }); + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + try { + proxy.setAge(50); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + assertTrue(ex.getCause() instanceof IOException); + } + } + + public void testHttpInvokerProxyFactoryBeanAndServiceExporterWithGzipCompression() throws Throwable { + TestBean target = new TestBean("myname", 99); + + final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter() { + protected InputStream decorateInputStream(HttpServletRequest request, InputStream is) throws IOException { + if ("gzip".equals(request.getHeader("Compression"))) { + return new GZIPInputStream(is); + } + else { + return is; + } + } + protected OutputStream decorateOutputStream( + HttpServletRequest request, HttpServletResponse response, OutputStream os) throws IOException { + if ("gzip".equals(request.getHeader("Compression"))) { + return new GZIPOutputStream(os); + } + else { + return os; + } + } + }; + exporter.setServiceInterface(ITestBean.class); + exporter.setService(target); + exporter.afterPropertiesSet(); + + HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); + pfb.setServiceInterface(ITestBean.class); + pfb.setServiceUrl("http://myurl"); + + pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { + protected RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) + throws IOException, ClassNotFoundException { + assertEquals("http://myurl", config.getServiceUrl()); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Compression", "gzip"); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setContent(baos.toByteArray()); + try { + exporter.handleRequest(request, response); + } + catch (ServletException ex) { + throw new IOException(ex.toString()); + } + return readRemoteInvocationResult( + new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); + } + protected OutputStream decorateOutputStream(OutputStream os) throws IOException { + return new GZIPOutputStream(os); + } + protected InputStream decorateInputStream(InputStream is) throws IOException { + return new GZIPInputStream(is); + } + }); + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + assertEquals("myname", proxy.getName()); + assertEquals(99, proxy.getAge()); + proxy.setAge(50); + assertEquals(50, proxy.getAge()); + + try { + proxy.exceptional(new IllegalStateException()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + try { + proxy.exceptional(new IllegalAccessException()); + fail("Should have thrown IllegalAccessException"); + } + catch (IllegalAccessException ex) { + // expected + } + } + + public void testHttpInvokerProxyFactoryBeanAndServiceExporterWithWrappedInvocations() throws Throwable { + TestBean target = new TestBean("myname", 99); + + final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter() { + protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + Object obj = ois.readObject(); + if (!(obj instanceof TestRemoteInvocationWrapper)) { + throw new IOException("Deserialized object needs to be assignable to type [" + + TestRemoteInvocationWrapper.class.getName() + "]: " + obj); + } + return ((TestRemoteInvocationWrapper) obj).remoteInvocation; + } + protected void doWriteRemoteInvocationResult(RemoteInvocationResult result, ObjectOutputStream oos) + throws IOException { + oos.writeObject(new TestRemoteInvocationResultWrapper(result)); + } + }; + exporter.setServiceInterface(ITestBean.class); + exporter.setService(target); + exporter.afterPropertiesSet(); + + HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); + pfb.setServiceInterface(ITestBean.class); + pfb.setServiceUrl("http://myurl"); + + pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { + protected RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { + assertEquals("http://myurl", config.getServiceUrl()); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setContent(baos.toByteArray()); + exporter.handleRequest(request, response); + return readRemoteInvocationResult( + new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); + } + protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream oos) throws IOException { + oos.writeObject(new TestRemoteInvocationWrapper(invocation)); + } + protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + Object obj = ois.readObject(); + if (!(obj instanceof TestRemoteInvocationResultWrapper)) { + throw new IOException("Deserialized object needs to be assignable to type [" + + TestRemoteInvocationResultWrapper.class.getName() + "]: " + obj); + } + return ((TestRemoteInvocationResultWrapper) obj).remoteInvocationResult; + } + }); + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + assertEquals("myname", proxy.getName()); + assertEquals(99, proxy.getAge()); + proxy.setAge(50); + assertEquals(50, proxy.getAge()); + + try { + proxy.exceptional(new IllegalStateException()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + try { + proxy.exceptional(new IllegalAccessException()); + fail("Should have thrown IllegalAccessException"); + } + catch (IllegalAccessException ex) { + // expected + } + } + + public void testHttpInvokerProxyFactoryBeanAndServiceExporterWithInvocationAttributes() throws Exception { + TestBean target = new TestBean("myname", 99); + + final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setServiceInterface(ITestBean.class); + exporter.setService(target); + exporter.setRemoteInvocationExecutor(new DefaultRemoteInvocationExecutor() { + public Object invoke(RemoteInvocation invocation, Object targetObject) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + assertNotNull(invocation.getAttributes()); + assertEquals(1, invocation.getAttributes().size()); + assertEquals("myValue", invocation.getAttributes().get("myKey")); + assertEquals("myValue", invocation.getAttribute("myKey")); + return super.invoke(invocation, targetObject); + } + }); + exporter.afterPropertiesSet(); + + HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); + pfb.setServiceInterface(ITestBean.class); + pfb.setServiceUrl("http://myurl"); + pfb.setRemoteInvocationFactory(new RemoteInvocationFactory() { + public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { + RemoteInvocation invocation = new RemoteInvocation(methodInvocation); + invocation.addAttribute("myKey", "myValue"); + try { + invocation.addAttribute("myKey", "myValue"); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected: already defined + } + assertNotNull(invocation.getAttributes()); + assertEquals(1, invocation.getAttributes().size()); + assertEquals("myValue", invocation.getAttributes().get("myKey")); + assertEquals("myValue", invocation.getAttribute("myKey")); + return invocation; + } + }); + + pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { + protected RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { + assertEquals("http://myurl", config.getServiceUrl()); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setContent(baos.toByteArray()); + exporter.handleRequest(request, response); + return readRemoteInvocationResult( + new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); + } + }); + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + assertEquals("myname", proxy.getName()); + assertEquals(99, proxy.getAge()); + } + + public void testHttpInvokerProxyFactoryBeanAndServiceExporterWithCustomInvocationObject() throws Exception { + TestBean target = new TestBean("myname", 99); + + final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setServiceInterface(ITestBean.class); + exporter.setService(target); + exporter.setRemoteInvocationExecutor(new DefaultRemoteInvocationExecutor() { + public Object invoke(RemoteInvocation invocation, Object targetObject) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + assertTrue(invocation instanceof TestRemoteInvocation); + assertNull(invocation.getAttributes()); + assertNull(invocation.getAttribute("myKey")); + return super.invoke(invocation, targetObject); + } + }); + exporter.afterPropertiesSet(); + + HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); + pfb.setServiceInterface(ITestBean.class); + pfb.setServiceUrl("http://myurl"); + pfb.setRemoteInvocationFactory(new RemoteInvocationFactory() { + public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { + RemoteInvocation invocation = new TestRemoteInvocation(methodInvocation); + assertNull(invocation.getAttributes()); + assertNull(invocation.getAttribute("myKey")); + return invocation; + } + }); + + pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { + protected RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { + assertEquals("http://myurl", config.getServiceUrl()); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setContent(baos.toByteArray()); + exporter.handleRequest(request, response); + return readRemoteInvocationResult( + new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); + } + }); + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + assertEquals("myname", proxy.getName()); + assertEquals(99, proxy.getAge()); + } + + public void testHttpInvokerWithSpecialLocalMethods() throws Exception { + String serviceUrl = "http://myurl"; + HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); + pfb.setServiceInterface(ITestBean.class); + pfb.setServiceUrl(serviceUrl); + + pfb.setHttpInvokerRequestExecutor(new HttpInvokerRequestExecutor() { + public RemoteInvocationResult executeRequest( + HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws IOException { + throw new IOException("argh"); + } + }); + + pfb.afterPropertiesSet(); + ITestBean proxy = (ITestBean) pfb.getObject(); + + // shouldn't go through to remote service + assertTrue(proxy.toString().indexOf("HTTP invoker") != -1); + assertTrue(proxy.toString().indexOf(serviceUrl) != -1); + assertEquals(proxy.hashCode(), proxy.hashCode()); + assertTrue(proxy.equals(proxy)); + + // should go through + try { + proxy.setAge(50); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + assertTrue(ex.getCause() instanceof IOException); + } + } + + + private static class TestRemoteInvocation extends RemoteInvocation { + + public TestRemoteInvocation(MethodInvocation methodInvocation) { + super(methodInvocation); + } + } + + + private static class TestRemoteInvocationWrapper implements Serializable { + + private final RemoteInvocation remoteInvocation; + + public TestRemoteInvocationWrapper(RemoteInvocation remoteInvocation) { + this.remoteInvocation = remoteInvocation; + } + } + + + private static class TestRemoteInvocationResultWrapper implements Serializable { + + private final RemoteInvocationResult remoteInvocationResult; + + public TestRemoteInvocationResultWrapper(RemoteInvocationResult remoteInvocationResult) { + this.remoteInvocationResult = remoteInvocationResult; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxrpc/JaxRpcSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxrpc/JaxRpcSupportTests.java new file mode 100644 index 00000000000..8444157bf12 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/jaxrpc/JaxRpcSupportTests.java @@ -0,0 +1,705 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.jaxrpc; + +import java.net.MalformedURLException; +import java.net.URL; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.xml.namespace.QName; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceException; +import javax.xml.rpc.ServiceFactory; +import javax.xml.rpc.Stub; + +import junit.framework.TestCase; +import org.easymock.ArgumentsMatcher; +import org.easymock.MockControl; + +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteLookupFailureException; +import org.springframework.util.ObjectUtils; + +/** + * @author Juergen Hoeller + * @since 18.12.2003 + */ +public class JaxRpcSupportTests extends TestCase { + + public void testLocalJaxRpcServiceFactoryBeanWithServiceNameAndNamespace() throws Exception { + LocalJaxRpcServiceFactoryBean factory = new LocalJaxRpcServiceFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.afterPropertiesSet(); + assertEquals(MockServiceFactory.service1, factory.getObject()); + } + + public void testLocalJaxRpcServiceFactoryBeanWithServiceNameAndWsdl() throws Exception { + LocalJaxRpcServiceFactoryBean factory = new LocalJaxRpcServiceFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setServiceName("myService2"); + factory.setWsdlDocumentUrl(new URL("http://myUrl1")); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + assertEquals(MockServiceFactory.service2, factory.getObject()); + } + + public void testLocalJaxRpcServiceFactoryBeanWithServiceNameAndWsdlAndProperties() throws Exception { + LocalJaxRpcServiceFactoryBean factory = new LocalJaxRpcServiceFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setServiceName("myService2"); + factory.setWsdlDocumentUrl(new URL("http://myUrl1")); + Properties props = new Properties(); + props.setProperty("myKey", "myValue"); + factory.setJaxRpcServiceProperties(props); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + assertEquals(MockServiceFactory.service1, factory.getObject()); + } + + public void testLocalJaxRpcServiceFactoryBeanWithJaxRpcServiceInterface() throws Exception { + LocalJaxRpcServiceFactoryBean factory = new LocalJaxRpcServiceFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setJaxRpcServiceInterface(IRemoteBean.class); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + assertEquals(MockServiceFactory.service2, factory.getObject()); + } + + public void testLocalJaxRpcServiceFactoryBeanWithJaxRpcServiceInterfaceAndWsdl() throws Exception { + LocalJaxRpcServiceFactoryBean factory = new LocalJaxRpcServiceFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setWsdlDocumentUrl(new URL("http://myUrl1")); + factory.setJaxRpcServiceInterface(IRemoteBean.class); + Properties props = new Properties(); + props.setProperty("myKey", "myValue"); + factory.setJaxRpcServiceProperties(props); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + assertEquals(MockServiceFactory.service1, factory.getObject()); + } + + public void testJaxRpcPortProxyFactoryBean() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setPortInterface(IRemoteBean.class); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getPortStub() instanceof Stub); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + MockServiceFactory.service1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithProperties() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setUsername("user"); + factory.setPassword("pw"); + factory.setEndpointAddress("ea"); + factory.setMaintainSession(true); + factory.setPortInterface(IRemoteBean.class); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + + assertTrue(factory.getPortStub() instanceof Stub); + Stub stub = (Stub) factory.getPortStub(); + assertEquals("user", stub._getProperty(Stub.USERNAME_PROPERTY)); + assertEquals("pw", stub._getProperty(Stub.PASSWORD_PROPERTY)); + assertEquals("ea", stub._getProperty(Stub.ENDPOINT_ADDRESS_PROPERTY)); + assertTrue(((Boolean) stub._getProperty(Stub.SESSION_MAINTAIN_PROPERTY)).booleanValue()); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + MockServiceFactory.service1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithCustomProperties() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setUsername("user"); + factory.setPassword("pw"); + Properties customProps = new Properties(); + customProps.setProperty("myProp", "myValue"); + factory.setCustomProperties(customProps); + factory.setPortInterface(IRemoteBean.class); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + + assertTrue(factory.getPortStub() instanceof Stub); + Stub stub = (Stub) factory.getPortStub(); + assertEquals("user", stub._getProperty(Stub.USERNAME_PROPERTY)); + assertEquals("pw", stub._getProperty(Stub.PASSWORD_PROPERTY)); + assertEquals("myValue", stub._getProperty("myProp")); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + MockServiceFactory.service1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithCustomPropertyMap() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setEndpointAddress("ea"); + factory.setMaintainSession(true); + Map customProps = new HashMap(); + customProps.put("myProp", new Integer(1)); + factory.setCustomPropertyMap(customProps); + factory.addCustomProperty("myOtherProp", "myOtherValue"); + factory.setPortInterface(IRemoteBean.class); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + + assertTrue(factory.getPortStub() instanceof Stub); + Stub stub = (Stub) factory.getPortStub(); + assertEquals("ea", stub._getProperty(Stub.ENDPOINT_ADDRESS_PROPERTY)); + assertTrue(((Boolean) stub._getProperty(Stub.SESSION_MAINTAIN_PROPERTY)).booleanValue()); + assertEquals(new Integer(1), stub._getProperty("myProp")); + assertEquals("myOtherValue", stub._getProperty("myOtherProp")); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + MockServiceFactory.service1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithDynamicCalls() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(CallMockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setServiceInterface(IBusinessBean.class); + factory.afterPropertiesSet(); + assertNull(factory.getPortStub()); + + assertTrue(factory.getObject() instanceof IBusinessBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + proxy.setName("myName"); + MockServiceFactory.service1Control.verify(); + CallMockServiceFactory.call1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithDynamicCallsAndProperties() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(CallWithPropertiesMockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setUsername("user"); + factory.setPassword("pw"); + factory.setEndpointAddress("ea"); + factory.setMaintainSession(true); + factory.setServiceInterface(IBusinessBean.class); + factory.afterPropertiesSet(); + assertNull(factory.getPortStub()); + + assertTrue(factory.getObject() instanceof IBusinessBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + proxy.setName("myName"); + MockServiceFactory.service1Control.verify(); + CallMockServiceFactory.call1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithDynamicCallsAndServiceException() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(CallMockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myServiceX"); + factory.setPortName("myPort"); + factory.setServiceInterface(IRemoteBean.class); + try { + factory.afterPropertiesSet(); + fail("Should have thrown RemoteLookupFailureException"); + } + catch (RemoteLookupFailureException ex) { + // expected + } + } + + public void testJaxRpcPortProxyFactoryBeanWithDynamicCallsAndLazyLookupAndServiceException() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(CallMockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myServiceX"); + factory.setPortName("myPort"); + factory.setServiceInterface(IRemoteBean.class); + factory.setLookupServiceOnStartup(false); + factory.afterPropertiesSet(); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + try { + proxy.setName("exception"); + fail("Should have thrown RemoteException"); + } + catch (RemoteLookupFailureException ex) { + // expected + assertTrue(ex.getCause() instanceof ServiceException); + } + } + + public void testJaxRpcPortProxyFactoryBeanWithDynamicCallsAndRemoteException() throws Exception { + ExceptionCallMockServiceFactory serviceFactory = new ExceptionCallMockServiceFactory(); + + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactory(serviceFactory); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setServiceInterface(IRemoteBean.class); + factory.afterPropertiesSet(); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + + try { + proxy.setName("exception"); + fail("Should have thrown RemoteException"); + } + catch (RemoteException ex) { + // expected + } + + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + + assertEquals(1, serviceFactory.serviceCount); + MockServiceFactory.service1Control.verify(); + CallMockServiceFactory.call1Control.verify(); + ExceptionCallMockServiceFactory.call2Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithDynamicCallsAndRemoteExceptionAndRefresh() throws Exception { + ExceptionCallMockServiceFactory serviceFactory = new ExceptionCallMockServiceFactory(); + + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactory(serviceFactory); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setServiceInterface(IRemoteBean.class); + factory.setRefreshServiceAfterConnectFailure(true); + factory.afterPropertiesSet(); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + + try { + proxy.setName("exception"); + fail("Should have thrown RemoteException"); + } + catch (RemoteException ex) { + // expected + } + + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + + assertEquals(2, serviceFactory.serviceCount); + MockServiceFactory.service1Control.verify(); + CallMockServiceFactory.call1Control.verify(); + ExceptionCallMockServiceFactory.call2Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithPortInterface() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setPortInterface(IRemoteBean.class); + factory.setServiceInterface(IBusinessBean.class); + factory.afterPropertiesSet(); + assertTrue(factory.getObject() instanceof IBusinessBean); + assertFalse(factory.getObject() instanceof IRemoteBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + MockServiceFactory.service1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithPortInterfaceAndServiceException() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myServiceX"); + factory.setPortInterface(IRemoteBean.class); + factory.setPortName("myPort"); + factory.setServiceInterface(IRemoteBean.class); + try { + factory.afterPropertiesSet(); + fail("Should have thrown RemoteLookupFailureException"); + } + catch (RemoteLookupFailureException ex) { + // expected + } + } + + public void testJaxRpcPortProxyFactoryBeanWithPortInterfaceAndLazyLookupAndServiceException() throws Exception { + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactoryClass(MockServiceFactory.class); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myServiceX"); + factory.setPortName("myPort"); + factory.setPortInterface(IRemoteBean.class); + factory.setServiceInterface(IRemoteBean.class); + factory.setLookupServiceOnStartup(false); + factory.afterPropertiesSet(); + + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + try { + proxy.setName("exception"); + fail("Should have thrown Service"); + } + catch (RemoteLookupFailureException ex) { + // expected + assertTrue(ex.getCause() instanceof ServiceException); + } + } + + public void testJaxRpcPortProxyFactoryBeanWithPortInterfaceAndRemoteException() throws Exception { + MockServiceFactory serviceFactory = new MockServiceFactory(); + + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactory(serviceFactory); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setPortInterface(IRemoteBean.class); + factory.setServiceInterface(IBusinessBean.class); + factory.afterPropertiesSet(); + + assertTrue(factory.getObject() instanceof IBusinessBean); + assertFalse(factory.getObject() instanceof IRemoteBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + + try { + proxy.setName("exception"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + + assertEquals(1, serviceFactory.serviceCount); + MockServiceFactory.service1Control.verify(); + } + + public void testJaxRpcPortProxyFactoryBeanWithPortInterfaceAndRemoteExceptionAndRefresh() throws Exception { + ExceptionMockServiceFactory serviceFactory = new ExceptionMockServiceFactory(); + + JaxRpcPortProxyFactoryBean factory = new JaxRpcPortProxyFactoryBean(); + factory.setServiceFactory(serviceFactory); + factory.setNamespaceUri("myNamespace"); + factory.setServiceName("myService1"); + factory.setPortName("myPort"); + factory.setPortInterface(IRemoteBean.class); + factory.setServiceInterface(IBusinessBean.class); + factory.setRefreshServiceAfterConnectFailure(true); + factory.afterPropertiesSet(); + + assertTrue(factory.getObject() instanceof IBusinessBean); + assertFalse(factory.getObject() instanceof IRemoteBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + + try { + proxy.setName("exception"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + proxy.setName("myName"); + assertEquals("myName", RemoteBean.name); + + assertEquals(2, serviceFactory.serviceCount); + MockServiceFactory.service1Control.verify(); + } + + + public static class MockServiceFactory extends ServiceFactory { + + protected static MockControl service1Control; + protected static Service service1; + protected static MockControl service2Control; + protected static Service service2; + protected int serviceCount = 0; + + public MockServiceFactory() throws Exception { + service1Control = MockControl.createControl(Service.class); + service1 = (Service) service1Control.getMock(); + service2Control = MockControl.createControl(Service.class); + service2 = (Service) service2Control.getMock(); + initMocks(); + service1Control.replay(); + } + + protected void initMocks() throws Exception { + service1.getPort(new QName("myNamespace", "myPort"), IRemoteBean.class); + service1Control.setReturnValue(new RemoteBean()); + } + + public Service createService(QName qName) throws ServiceException { + if (!"myNamespace".equals(qName.getNamespaceURI()) || !"myService1".equals(qName.getLocalPart())) { + throw new ServiceException("not supported"); + } + serviceCount++; + return service1; + } + + public Service createService(URL url, QName qName) throws ServiceException { + try { + if (!(new URL("http://myUrl1")).equals(url) || !"".equals(qName.getNamespaceURI()) || + !"myService2".equals(qName.getLocalPart())) { + throw new ServiceException("not supported"); + } + } + catch (MalformedURLException ex) { + } + serviceCount++; + return service2; + } + + public Service loadService(URL url, QName qName, Properties props) throws ServiceException { + try { + if (!(new URL("http://myUrl1")).equals(url) || !"".equals(qName.getNamespaceURI()) || + !"myService2".equals(qName.getLocalPart())) { + throw new ServiceException("not supported"); + } + } + catch (MalformedURLException ex) { + } + if (props == null || !"myValue".equals(props.getProperty("myKey"))) { + throw new ServiceException("invalid properties"); + } + serviceCount++; + return service1; + } + + public Service loadService(Class ifc) throws ServiceException { + if (!IRemoteBean.class.equals(ifc)) { + throw new ServiceException("not supported"); + } + serviceCount++; + return service2; + } + + public Service loadService(URL url, Class ifc, Properties props) throws ServiceException { + try { + if (!(new URL("http://myUrl1")).equals(url) || !IRemoteBean.class.equals(ifc)) { + throw new ServiceException("not supported"); + } + } + catch (MalformedURLException ex) { + } + if (props == null || !"myValue".equals(props.getProperty("myKey"))) { + throw new ServiceException("invalid properties"); + } + serviceCount++; + return service1; + } + } + + + public static class ExceptionMockServiceFactory extends MockServiceFactory { + + public ExceptionMockServiceFactory() throws Exception { + super(); + } + + protected void initMocks() throws Exception { + super.initMocks(); + service1.getPort(new QName("myNamespace", "myPort"), IRemoteBean.class); + service1Control.setReturnValue(new RemoteBean()); + } + } + + + public static class CallMockServiceFactory extends MockServiceFactory { + + protected static MockControl call1Control; + protected static Call call1; + + public CallMockServiceFactory() throws Exception { + super(); + } + + protected void initMocks() throws Exception { + initStandardCall(1); + } + + protected void initStandardCall(int count) throws Exception { + call1Control = MockControl.createControl(Call.class); + call1 = (Call) call1Control.getMock(); + service1.createCall(new QName("myNamespace", "myPort"), "setName"); + service1Control.setReturnValue(call1, count); + call1.invoke(new Object[] {"myName"}); + call1Control.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] objects, Object[] objects1) { + return Arrays.equals((Object[]) objects[0], (Object[]) objects1[0]); + } + public String toString(Object[] objects) { + return ObjectUtils.nullSafeToString(objects[0]); + } + }); + call1Control.setReturnValue(null, count); + extendStandardCall(); + call1Control.replay(); + } + + protected void extendStandardCall() { + } + } + + + public static class ExceptionCallMockServiceFactory extends CallMockServiceFactory { + + protected static MockControl call2Control; + protected static Call call2; + + public ExceptionCallMockServiceFactory() throws Exception { + } + + protected void initMocks() throws Exception { + initExceptionCall(); + initStandardCall(2); + } + + protected void initExceptionCall() throws Exception { + call2Control = MockControl.createControl(Call.class); + call2 = (Call) call2Control.getMock(); + service1.createCall(new QName("myNamespace", "myPort"), "setName"); + service1Control.setReturnValue(call2); + call2.invoke(new Object[] {"exception"}); + call2Control.setMatcher(new ArgumentsMatcher() { + public boolean matches(Object[] objects, Object[] objects1) { + return Arrays.equals((Object[]) objects[0], (Object[]) objects1[0]); + } + public String toString(Object[] objects) { + return ObjectUtils.nullSafeToString(objects[0]); + } + }); + call2Control.setThrowable(new RemoteException()); + call2Control.replay(); + } + } + + + public static class CallWithPropertiesMockServiceFactory extends CallMockServiceFactory { + + public CallWithPropertiesMockServiceFactory() throws Exception { + } + + protected void extendStandardCall() { + call1.setProperty(Call.USERNAME_PROPERTY, "user"); + call1Control.setVoidCallable(); + call1.setProperty(Call.PASSWORD_PROPERTY, "pw"); + call1Control.setVoidCallable(); + call1.setTargetEndpointAddress("ea"); + call1Control.setVoidCallable(); + call1.setProperty(Call.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE); + call1Control.setVoidCallable(); + } + } + + + public static interface IBusinessBean { + + public void setName(String name); + + } + + + public static interface IRemoteBean extends Remote { + + public void setName(String name) throws RemoteException; + + } + + + public static class RemoteBean implements IRemoteBean, Stub { + + private static String name; + private static Map properties; + + public RemoteBean() { + properties = new HashMap(); + } + + public void setName(String nam) throws RemoteException { + if ("exception".equals(nam)) { + throw new RemoteException(); + } + name = nam; + } + + public void _setProperty(String key, Object o) { + properties.put(key, o); + } + + public Object _getProperty(String key) { + return properties.get(key); + } + + public Iterator _getPropertyNames() { + return properties.keySet().iterator(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java new file mode 100644 index 00000000000..2f2b1e81559 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java @@ -0,0 +1,452 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.rmi; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.rmi.ConnectException; +import java.rmi.ConnectIOException; +import java.rmi.MarshalException; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.StubNotFoundException; +import java.rmi.UnknownHostException; +import java.rmi.UnmarshalException; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteProxyFailureException; +import org.springframework.remoting.support.RemoteInvocation; + +/** + * @author Juergen Hoeller + * @since 16.05.2003 + */ +public class RmiSupportTests extends TestCase { + + public void testRmiProxyFactoryBean() throws Exception { + CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); + factory.setServiceInterface(IRemoteBean.class); + factory.setServiceUrl("rmi://localhost:1090/test"); + factory.afterPropertiesSet(); + assertTrue("Correct singleton value", factory.isSingleton()); + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + proxy.setName("myName"); + assertEquals(RemoteBean.name, "myName"); + assertEquals(1, factory.counter); + } + + public void testRmiProxyFactoryBeanWithRemoteException() throws Exception { + doTestRmiProxyFactoryBeanWithException(RemoteException.class); + } + + public void testRmiProxyFactoryBeanWithConnectException() throws Exception { + doTestRmiProxyFactoryBeanWithException(ConnectException.class); + } + + public void testRmiProxyFactoryBeanWithConnectIOException() throws Exception { + doTestRmiProxyFactoryBeanWithException(ConnectIOException.class); + } + + public void testRmiProxyFactoryBeanWithUnknownHostException() throws Exception { + doTestRmiProxyFactoryBeanWithException(UnknownHostException.class); + } + + public void testRmiProxyFactoryBeanWithNoSuchObjectException() throws Exception { + doTestRmiProxyFactoryBeanWithException(NoSuchObjectException.class); + } + + public void testRmiProxyFactoryBeanWithStubNotFoundException() throws Exception { + doTestRmiProxyFactoryBeanWithException(StubNotFoundException.class); + } + + public void testRmiProxyFactoryBeanWithMarshalException() throws Exception { + doTestRmiProxyFactoryBeanWithException(MarshalException.class); + } + + public void testRmiProxyFactoryBeanWithUnmarshalException() throws Exception { + doTestRmiProxyFactoryBeanWithException(UnmarshalException.class); + } + + private void doTestRmiProxyFactoryBeanWithException(Class exceptionClass) throws Exception { + CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); + factory.setServiceInterface(IRemoteBean.class); + factory.setServiceUrl("rmi://localhost:1090/test"); + factory.afterPropertiesSet(); + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + try { + proxy.setName(exceptionClass.getName()); + fail("Should have thrown " + exceptionClass.getName()); + } + catch (Exception ex) { + if (exceptionClass.isInstance(ex)) { + // expected + } + else { + throw ex; + } + } + assertEquals(1, factory.counter); + } + + public void testRmiProxyFactoryBeanWithConnectExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithExceptionAndRefresh(ConnectException.class); + } + + public void testRmiProxyFactoryBeanWithConnectIOExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithExceptionAndRefresh(ConnectIOException.class); + } + + public void testRmiProxyFactoryBeanWithUnknownHostExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithExceptionAndRefresh(UnknownHostException.class); + } + + public void testRmiProxyFactoryBeanWithNoSuchObjectExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithExceptionAndRefresh(NoSuchObjectException.class); + } + + public void testRmiProxyFactoryBeanWithStubNotFoundExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithExceptionAndRefresh(StubNotFoundException.class); + } + + private void doTestRmiProxyFactoryBeanWithExceptionAndRefresh(Class exceptionClass) throws Exception { + CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); + factory.setServiceInterface(IRemoteBean.class); + factory.setServiceUrl("rmi://localhost:1090/test"); + factory.setRefreshStubOnConnectFailure(true); + factory.afterPropertiesSet(); + assertTrue(factory.getObject() instanceof IRemoteBean); + IRemoteBean proxy = (IRemoteBean) factory.getObject(); + try { + proxy.setName(exceptionClass.getName()); + fail("Should have thrown " + exceptionClass.getName()); + } + catch (Exception ex) { + if (exceptionClass.isInstance(ex)) { + // expected + } + else { + throw ex; + } + } + assertEquals(2, factory.counter); + } + + public void testRmiProxyFactoryBeanWithBusinessInterface() throws Exception { + CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); + factory.setServiceInterface(IBusinessBean.class); + factory.setServiceUrl("rmi://localhost:1090/test"); + factory.afterPropertiesSet(); + assertTrue(factory.getObject() instanceof IBusinessBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + assertFalse(proxy instanceof IRemoteBean); + proxy.setName("myName"); + assertEquals(RemoteBean.name, "myName"); + assertEquals(1, factory.counter); + } + + public void testRmiProxyFactoryBeanWithWrongBusinessInterface() throws Exception { + CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); + factory.setServiceInterface(IWrongBusinessBean.class); + factory.setServiceUrl("rmi://localhost:1090/test"); + factory.afterPropertiesSet(); + assertTrue(factory.getObject() instanceof IWrongBusinessBean); + IWrongBusinessBean proxy = (IWrongBusinessBean) factory.getObject(); + assertFalse(proxy instanceof IRemoteBean); + try { + proxy.setOtherName("name"); + fail("Should have thrown RemoteProxyFailureException"); + } + catch (RemoteProxyFailureException ex) { + assertTrue(ex.getCause() instanceof NoSuchMethodException); + assertTrue(ex.getMessage().indexOf("setOtherName") != -1); + assertTrue(ex.getMessage().indexOf("IWrongBusinessBean") != -1); + } + assertEquals(1, factory.counter); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndRemoteException() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( + RemoteException.class, RemoteAccessException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndConnectException() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( + ConnectException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndConnectIOException() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( + ConnectIOException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndUnknownHostException() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( + UnknownHostException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndNoSuchObjectExceptionException() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( + NoSuchObjectException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndStubNotFoundException() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( + StubNotFoundException.class, RemoteConnectFailureException.class); + } + + private void doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( + Class rmiExceptionClass, Class springExceptionClass) throws Exception { + + CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); + factory.setServiceInterface(IBusinessBean.class); + factory.setServiceUrl("rmi://localhost:1090/test"); + factory.afterPropertiesSet(); + assertTrue(factory.getObject() instanceof IBusinessBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + assertFalse(proxy instanceof IRemoteBean); + try { + proxy.setName(rmiExceptionClass.getName()); + fail("Should have thrown " + rmiExceptionClass.getName()); + } + catch (Exception ex) { + if (springExceptionClass.isInstance(ex)) { + // expected + } + else { + throw ex; + } + } + assertEquals(1, factory.counter); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndRemoteExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( + RemoteException.class, RemoteAccessException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndConnectExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( + ConnectException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndConnectIOExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( + ConnectIOException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndUnknownHostExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( + UnknownHostException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndNoSuchObjectExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( + NoSuchObjectException.class, RemoteConnectFailureException.class); + } + + public void testRmiProxyFactoryBeanWithBusinessInterfaceAndStubNotFoundExceptionAndRefresh() throws Exception { + doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( + StubNotFoundException.class, RemoteConnectFailureException.class); + } + + private void doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( + Class rmiExceptionClass, Class springExceptionClass) throws Exception { + + CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); + factory.setServiceInterface(IBusinessBean.class); + factory.setServiceUrl("rmi://localhost:1090/test"); + factory.setRefreshStubOnConnectFailure(true); + factory.afterPropertiesSet(); + assertTrue(factory.getObject() instanceof IBusinessBean); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + assertFalse(proxy instanceof IRemoteBean); + try { + proxy.setName(rmiExceptionClass.getName()); + fail("Should have thrown " + rmiExceptionClass.getName()); + } + catch (Exception ex) { + if (springExceptionClass.isInstance(ex)) { + // expected + } + else { + throw ex; + } + } + if (RemoteConnectFailureException.class.isAssignableFrom(springExceptionClass)) { + assertEquals(2, factory.counter); + } + else { + assertEquals(1, factory.counter); + } + } + + public void testRmiClientInterceptorRequiresUrl() throws Exception{ + RmiClientInterceptor client = new RmiClientInterceptor(); + client.setServiceInterface(IRemoteBean.class); + + try { + client.afterPropertiesSet(); + fail("url isn't set, expected IllegalArgumentException"); + } + catch(IllegalArgumentException e){ + // expected + } + } + + public void testRemoteInvocation() throws NoSuchMethodException { + // let's see if the remote invocation object works + + final RemoteBean rb = new RemoteBean(); + final Method setNameMethod = rb.getClass().getDeclaredMethod("setName", new Class[] {String.class}); + + MethodInvocation mi = new MethodInvocation() { + public Method getMethod() { + return setNameMethod; + } + public Object[] getArguments() { + return new Object[] {"bla"}; + } + public Object proceed() throws Throwable { + throw new UnsupportedOperationException(); + } + public Object getThis() { + return rb; + } + public AccessibleObject getStaticPart() { + return setNameMethod; + } + }; + + RemoteInvocation inv = new RemoteInvocation(mi); + + assertEquals("setName", inv.getMethodName()); + assertEquals("bla", inv.getArguments()[0]); + assertEquals(String.class, inv.getParameterTypes()[0]); + + // this is a bit BS, but we need to test it + inv = new RemoteInvocation(); + inv.setArguments(new Object[] { "bla" }); + assertEquals("bla", inv.getArguments()[0]); + inv.setMethodName("setName"); + assertEquals("setName", inv.getMethodName()); + inv.setParameterTypes(new Class[] {String.class}); + assertEquals(String.class, inv.getParameterTypes()[0]); + + inv = new RemoteInvocation("setName", new Class[] {String.class}, new Object[] {"bla"}); + assertEquals("bla", inv.getArguments()[0]); + assertEquals("setName", inv.getMethodName()); + assertEquals(String.class, inv.getParameterTypes()[0]); + } + + public void testRmiInvokerWithSpecialLocalMethods() throws Exception { + String serviceUrl = "rmi://localhost:1090/test"; + RmiProxyFactoryBean factory = new RmiProxyFactoryBean() { + protected Remote lookupStub() { + return new RmiInvocationHandler() { + public String getTargetInterfaceName() { + return null; + } + public Object invoke(RemoteInvocation invocation) throws RemoteException { + throw new RemoteException(); + } + }; + } + }; + factory.setServiceInterface(IBusinessBean.class); + factory.setServiceUrl(serviceUrl); + factory.afterPropertiesSet(); + IBusinessBean proxy = (IBusinessBean) factory.getObject(); + + // shouldn't go through to remote service + assertTrue(proxy.toString().indexOf("RMI invoker") != -1); + assertTrue(proxy.toString().indexOf(serviceUrl) != -1); + assertEquals(proxy.hashCode(), proxy.hashCode()); + assertTrue(proxy.equals(proxy)); + + // should go through + try { + proxy.setName("test"); + fail("Should have thrown RemoteAccessException"); + } + catch (RemoteAccessException ex) { + // expected + } + } + + + private static class CountingRmiProxyFactoryBean extends RmiProxyFactoryBean { + + private int counter = 0; + + protected Remote lookupStub() { + counter++; + return new RemoteBean(); + } + } + + + public static interface IBusinessBean { + + public void setName(String name); + + } + + + public static interface IWrongBusinessBean { + + public void setOtherName(String name); + + } + + + public static interface IRemoteBean extends Remote { + + public void setName(String name) throws RemoteException; + + } + + + public static class RemoteBean implements IRemoteBean { + + private static String name; + + public void setName(String nam) throws RemoteException { + if (nam != null && nam.endsWith("Exception")) { + RemoteException rex = null; + try { + Class exClass = Class.forName(nam); + Constructor ctor = exClass.getConstructor(new Class[] {String.class}); + rex = (RemoteException) ctor.newInstance(new Object[] {"myMessage"}); + } + catch (Exception ex) { + throw new RemoteException("Illegal exception class name: " + nam, ex); + } + throw rex; + } + name = nam; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/remoting/support/RemoteInvocationUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/remoting/support/RemoteInvocationUtilsTests.java new file mode 100644 index 00000000000..57d532d3e9f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/remoting/support/RemoteInvocationUtilsTests.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.remoting.support; + +import junit.framework.TestCase; + +/** + * @author Rick Evans + */ +public class RemoteInvocationUtilsTests extends TestCase { + + public void testFillInClientStackTraceIfPossibleSunnyDay() throws Exception { + try { + throw new IllegalStateException("Mmm"); + } + catch (Exception ex) { + int originalStackTraceLngth = ex.getStackTrace().length; + RemoteInvocationUtils.fillInClientStackTraceIfPossible(ex); + assertTrue("Stack trace not being filled in", + ex.getStackTrace().length > originalStackTraceLngth); + } + } + + public void testFillInClientStackTraceIfPossibleWithNullThrowable() throws Exception { + // just want to ensure that it doesn't bomb + RemoteInvocationUtils.fillInClientStackTraceIfPossible(null); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/TestMethodInvokingTask.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/TestMethodInvokingTask.java new file mode 100644 index 00000000000..364610db9e8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/TestMethodInvokingTask.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling; + +/** + * @author Juergen Hoeller + * @since 09.10.2004 + */ +public class TestMethodInvokingTask { + + public int counter = 0; + + private Object lock = new Object(); + + public void doSomething() { + this.counter++; + } + + public void doWait() { + this.counter++; + // wait until stop is called + synchronized (this.lock) { + try { + this.lock.wait(); + } + catch (InterruptedException e) { + // fall through + } + } + } + + public void stop() { + synchronized(this.lock) { + this.lock.notify(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ConcurrentTaskExecutorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ConcurrentTaskExecutorTests.java new file mode 100644 index 00000000000..0d8729dfdf3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ConcurrentTaskExecutorTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.backportconcurrent; + +import junit.framework.TestCase; + +import org.springframework.core.task.NoOpRunnable; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ConcurrentTaskExecutorTests extends TestCase { + + public void testZeroArgCtorResultsInDefaultTaskExecutorBeingUsed() throws Exception { + ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(); + // must not throw a NullPointerException + executor.execute(new NoOpRunnable()); + } + + public void testPassingNullExecutorToCtorResultsInDefaultTaskExecutorBeingUsed() throws Exception { + ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(null); + // must not throw a NullPointerException + executor.execute(new NoOpRunnable()); + } + + public void testPassingNullExecutorToSetterResultsInDefaultTaskExecutorBeingUsed() throws Exception { + ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(); + executor.setConcurrentExecutor(null); + // must not throw a NullPointerException + executor.execute(new NoOpRunnable()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBeanTests.java new file mode 100644 index 00000000000..b2a440c5117 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBeanTests.java @@ -0,0 +1,263 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.backportconcurrent; + +import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionHandler; +import edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService; +import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory; +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.core.task.NoOpRunnable; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ScheduledExecutorFactoryBeanTests extends TestCase { + + public void testThrowsExceptionIfPoolSizeIsLessThanZero() throws Exception { + try { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setPoolSize(-1); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.afterPropertiesSet(); + fail("Pool size less than zero"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testShutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception { + MockControl mockScheduledExecutorService = MockControl.createNiceControl(ScheduledExecutorService.class); + final ScheduledExecutorService executor = (ScheduledExecutorService) mockScheduledExecutorService.getMock(); + executor.shutdownNow(); + mockScheduledExecutorService.setReturnValue(null); + mockScheduledExecutorService.replay(); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + return executor; + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.afterPropertiesSet(); + factory.destroy(); + + mockScheduledExecutorService.verify(); + } + + public void testShutdownIsPropagatedToTheExecutorOnDestroy() throws Exception { + MockControl mockScheduledExecutorService = MockControl.createNiceControl(ScheduledExecutorService.class); + final ScheduledExecutorService executor = (ScheduledExecutorService) mockScheduledExecutorService.getMock(); + executor.shutdown(); + mockScheduledExecutorService.setVoidCallable(); + mockScheduledExecutorService.replay(); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + return executor; + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.setWaitForTasksToCompleteOnShutdown(true); + factory.afterPropertiesSet(); + factory.destroy(); + + mockScheduledExecutorService.verify(); + } + + public void testOneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setVoidCallable(); + mockRunnable.replay(); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new ScheduledExecutorTask(runnable) + }); + factory.afterPropertiesSet(); + pauseToLetTaskStart(1); + factory.destroy(); + + mockRunnable.verify(); + } + + public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setVoidCallable(); + runnable.run(); + mockRunnable.setVoidCallable(); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setFixedRate(true); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task}); + factory.afterPropertiesSet(); + pauseToLetTaskStart(2); + factory.destroy(); + + mockRunnable.verify(); + } + + public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setFixedRate(true); + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task}); + factory.setContinueScheduledExecutionAfterException(true); + factory.afterPropertiesSet(); + pauseToLetTaskStart(2); + factory.destroy(); + + mockRunnable.verify(); + } + + public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setVoidCallable(); + runnable.run(); + mockRunnable.setVoidCallable(); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setDelay(3000); // nice long wait... + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task}); + factory.afterPropertiesSet(); + pauseToLetTaskStart(1); + // invoke destroy before tasks have even been scheduled... + factory.destroy(); + + try { + mockRunnable.verify(); + fail("Mock must never have been called"); + } + catch (AssertionFailedError expected) { + } + } + + public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception { + MockControl mockRunnable = MockControl.createControl(Runnable.class); + Runnable runnable = (Runnable) mockRunnable.getMock(); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + runnable.run(); + mockRunnable.setThrowable(new IllegalStateException()); + mockRunnable.replay(); + + ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); + task.setPeriod(500); + task.setDelay(3000); // nice long wait... + + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task}); + factory.setContinueScheduledExecutionAfterException(true); + factory.afterPropertiesSet(); + pauseToLetTaskStart(1); + // invoke destroy before tasks have even been scheduled... + factory.destroy(); + + try { + mockRunnable.verify(); + fail("Mock must never have been called"); + } + catch (AssertionFailedError expected) { + } + } + + public void testSettingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + assertNotNull("Bah; the setThreadFactory(..) method must use a default ThreadFactory if a null arg is passed in."); + return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler); + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.setThreadFactory(null); // the null must not propagate + factory.afterPropertiesSet(); + factory.destroy(); + } + + public void testSettingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { + protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + assertNotNull("Bah; the setRejectedExecutionHandler(..) method must use a default RejectedExecutionHandler if a null arg is passed in."); + return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler); + } + }; + factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ + new NoOpScheduledExecutorTask() + }); + factory.setRejectedExecutionHandler(null); // the null must not propagate + factory.afterPropertiesSet(); + factory.destroy(); + } + + public void testObjectTypeReportsCorrectType() throws Exception { + ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); + assertEquals(ScheduledExecutorService.class, factory.getObjectType()); + } + + + private static void pauseToLetTaskStart(int seconds) { + try { + Thread.sleep(seconds * 1000); + } + catch (InterruptedException ignored) { + } + } + + + private static class NoOpScheduledExecutorTask extends ScheduledExecutorTask { + + public NoOpScheduledExecutorTask() { + super(new NoOpRunnable()); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java new file mode 100644 index 00000000000..e98d0c1482a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java @@ -0,0 +1,1082 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.quartz; + +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.quartz.CronTrigger; +import org.quartz.Job; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.JobListener; +import org.quartz.ObjectAlreadyExistsException; +import org.quartz.Scheduler; +import org.quartz.SchedulerContext; +import org.quartz.SchedulerException; +import org.quartz.SchedulerFactory; +import org.quartz.SchedulerListener; +import org.quartz.SimpleTrigger; +import org.quartz.Trigger; +import org.quartz.TriggerListener; +import org.quartz.impl.SchedulerRepository; +import org.quartz.spi.JobFactory; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.io.FileSystemResourceLoader; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.TestMethodInvokingTask; + +/** + * @author Juergen Hoeller + * @author Alef Arendsen + * @author Rob Harrop + * @since 20.02.2004 + */ +public class QuartzSupportTests extends TestCase { + + public void testSchedulerFactoryBean() throws Exception { + doTestSchedulerFactoryBean(false, false); + } + + public void testSchedulerFactoryBeanWithExplicitJobDetail() throws Exception { + doTestSchedulerFactoryBean(true, false); + } + + public void testSchedulerFactoryBeanWithPrototypeJob() throws Exception { + doTestSchedulerFactoryBean(false, true); + } + + private void doTestSchedulerFactoryBean(boolean explicitJobDetail, boolean prototypeJob) throws Exception { + TestBean tb = new TestBean("tb", 99); + JobDetailBean jobDetail0 = new JobDetailBean(); + jobDetail0.setJobClass(Job.class); + jobDetail0.setBeanName("myJob0"); + Map jobData = new HashMap(); + jobData.put("testBean", tb); + jobDetail0.setJobDataAsMap(jobData); + jobDetail0.afterPropertiesSet(); + assertEquals(tb, jobDetail0.getJobDataMap().get("testBean")); + + CronTriggerBean trigger0 = new CronTriggerBean(); + trigger0.setBeanName("myTrigger0"); + trigger0.setJobDetail(jobDetail0); + trigger0.setCronExpression("0/1 * * * * ?"); + trigger0.afterPropertiesSet(); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryBean mijdfb = new MethodInvokingJobDetailFactoryBean(); + mijdfb.setBeanName("myJob1"); + if (prototypeJob) { + StaticListableBeanFactory beanFactory = new StaticListableBeanFactory(); + beanFactory.addBean("task", task1); + mijdfb.setTargetBeanName("task"); + mijdfb.setBeanFactory(beanFactory); + } + else { + mijdfb.setTargetObject(task1); + } + mijdfb.setTargetMethod("doSomething"); + mijdfb.afterPropertiesSet(); + JobDetail jobDetail1 = (JobDetail) mijdfb.getObject(); + + SimpleTriggerBean trigger1 = new SimpleTriggerBean(); + trigger1.setBeanName("myTrigger1"); + trigger1.setJobDetail(jobDetail1); + trigger1.setStartDelay(0); + trigger1.setRepeatInterval(20); + trigger1.afterPropertiesSet(); + + MockControl schedulerControl = MockControl.createControl(Scheduler.class); + final Scheduler scheduler = (Scheduler) schedulerControl.getMock(); + scheduler.getContext(); + schedulerControl.setReturnValue(new SchedulerContext()); + scheduler.getJobDetail("myJob0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getJobDetail("myJob1", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getTrigger("myTrigger0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getTrigger("myTrigger1", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.addJob(jobDetail0, true); + schedulerControl.setVoidCallable(); + scheduler.scheduleJob(trigger0); + schedulerControl.setReturnValue(new Date()); + scheduler.addJob(jobDetail1, true); + schedulerControl.setVoidCallable(); + scheduler.scheduleJob(trigger1); + schedulerControl.setReturnValue(new Date()); + scheduler.start(); + schedulerControl.setVoidCallable(); + scheduler.shutdown(false); + schedulerControl.setVoidCallable(); + schedulerControl.replay(); + + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean() { + protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName) { + return scheduler; + } + }; + schedulerFactoryBean.setJobFactory(null); + Map schedulerContext = new HashMap(); + schedulerContext.put("otherTestBean", tb); + schedulerFactoryBean.setSchedulerContextAsMap(schedulerContext); + if (explicitJobDetail) { + schedulerFactoryBean.setJobDetails(new JobDetail[] {jobDetail0}); + } + schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); + try { + schedulerFactoryBean.afterPropertiesSet(); + } + finally { + schedulerFactoryBean.destroy(); + } + + schedulerControl.verify(); + } + + public void testSchedulerFactoryBeanWithExistingJobs() throws Exception { + doTestSchedulerFactoryBeanWithExistingJobs(false); + } + + public void testSchedulerFactoryBeanWithOverwriteExistingJobs() throws Exception { + doTestSchedulerFactoryBeanWithExistingJobs(true); + } + + private void doTestSchedulerFactoryBeanWithExistingJobs(boolean overwrite) throws Exception { + TestBean tb = new TestBean("tb", 99); + JobDetailBean jobDetail0 = new JobDetailBean(); + jobDetail0.setJobClass(Job.class); + jobDetail0.setBeanName("myJob0"); + Map jobData = new HashMap(); + jobData.put("testBean", tb); + jobDetail0.setJobDataAsMap(jobData); + jobDetail0.afterPropertiesSet(); + assertEquals(tb, jobDetail0.getJobDataMap().get("testBean")); + + CronTriggerBean trigger0 = new CronTriggerBean(); + trigger0.setBeanName("myTrigger0"); + trigger0.setJobDetail(jobDetail0); + trigger0.setCronExpression("0/1 * * * * ?"); + trigger0.afterPropertiesSet(); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryBean mijdfb = new MethodInvokingJobDetailFactoryBean(); + mijdfb.setBeanName("myJob1"); + mijdfb.setTargetObject(task1); + mijdfb.setTargetMethod("doSomething"); + mijdfb.afterPropertiesSet(); + JobDetail jobDetail1 = (JobDetail) mijdfb.getObject(); + + SimpleTriggerBean trigger1 = new SimpleTriggerBean(); + trigger1.setBeanName("myTrigger1"); + trigger1.setJobDetail(jobDetail1); + trigger1.setStartDelay(0); + trigger1.setRepeatInterval(20); + trigger1.afterPropertiesSet(); + + MockControl schedulerControl = MockControl.createControl(Scheduler.class); + final Scheduler scheduler = (Scheduler) schedulerControl.getMock(); + scheduler.getContext(); + schedulerControl.setReturnValue(new SchedulerContext()); + scheduler.getTrigger("myTrigger0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getTrigger("myTrigger1", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(new SimpleTrigger()); + if (overwrite) { + scheduler.addJob(jobDetail1, true); + schedulerControl.setVoidCallable(); + scheduler.rescheduleJob("myTrigger1", Scheduler.DEFAULT_GROUP, trigger1); + schedulerControl.setReturnValue(new Date()); + } + else { + scheduler.getJobDetail("myJob0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + } + scheduler.addJob(jobDetail0, true); + schedulerControl.setVoidCallable(); + scheduler.scheduleJob(trigger0); + schedulerControl.setReturnValue(new Date()); + scheduler.start(); + schedulerControl.setVoidCallable(); + scheduler.shutdown(false); + schedulerControl.setVoidCallable(); + schedulerControl.replay(); + + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean() { + protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName) { + return scheduler; + } + }; + schedulerFactoryBean.setJobFactory(null); + Map schedulerContext = new HashMap(); + schedulerContext.put("otherTestBean", tb); + schedulerFactoryBean.setSchedulerContextAsMap(schedulerContext); + schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); + if (overwrite) { + schedulerFactoryBean.setOverwriteExistingJobs(true); + } + try { + schedulerFactoryBean.afterPropertiesSet(); + } + finally { + schedulerFactoryBean.destroy(); + } + + schedulerControl.verify(); + } + + public void testSchedulerFactoryBeanWithExistingJobsAndRaceCondition() throws Exception { + doTestSchedulerFactoryBeanWithExistingJobsAndRaceCondition(false); + } + + public void testSchedulerFactoryBeanWithOverwriteExistingJobsAndRaceCondition() throws Exception { + doTestSchedulerFactoryBeanWithExistingJobsAndRaceCondition(true); + } + + private void doTestSchedulerFactoryBeanWithExistingJobsAndRaceCondition(boolean overwrite) throws Exception { + TestBean tb = new TestBean("tb", 99); + JobDetailBean jobDetail0 = new JobDetailBean(); + jobDetail0.setJobClass(Job.class); + jobDetail0.setBeanName("myJob0"); + Map jobData = new HashMap(); + jobData.put("testBean", tb); + jobDetail0.setJobDataAsMap(jobData); + jobDetail0.afterPropertiesSet(); + assertEquals(tb, jobDetail0.getJobDataMap().get("testBean")); + + CronTriggerBean trigger0 = new CronTriggerBean(); + trigger0.setBeanName("myTrigger0"); + trigger0.setJobDetail(jobDetail0); + trigger0.setCronExpression("0/1 * * * * ?"); + trigger0.afterPropertiesSet(); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryBean mijdfb = new MethodInvokingJobDetailFactoryBean(); + mijdfb.setBeanName("myJob1"); + mijdfb.setTargetObject(task1); + mijdfb.setTargetMethod("doSomething"); + mijdfb.afterPropertiesSet(); + JobDetail jobDetail1 = (JobDetail) mijdfb.getObject(); + + SimpleTriggerBean trigger1 = new SimpleTriggerBean(); + trigger1.setBeanName("myTrigger1"); + trigger1.setJobDetail(jobDetail1); + trigger1.setStartDelay(0); + trigger1.setRepeatInterval(20); + trigger1.afterPropertiesSet(); + + MockControl schedulerControl = MockControl.createControl(Scheduler.class); + final Scheduler scheduler = (Scheduler) schedulerControl.getMock(); + scheduler.getContext(); + schedulerControl.setReturnValue(new SchedulerContext()); + scheduler.getTrigger("myTrigger0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getTrigger("myTrigger1", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(new SimpleTrigger()); + if (overwrite) { + scheduler.addJob(jobDetail1, true); + schedulerControl.setVoidCallable(); + scheduler.rescheduleJob("myTrigger1", Scheduler.DEFAULT_GROUP, trigger1); + schedulerControl.setReturnValue(new Date()); + } + else { + scheduler.getJobDetail("myJob0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + } + scheduler.addJob(jobDetail0, true); + schedulerControl.setVoidCallable(); + scheduler.scheduleJob(trigger0); + schedulerControl.setThrowable(new ObjectAlreadyExistsException("")); + if (overwrite) { + scheduler.rescheduleJob("myTrigger0", Scheduler.DEFAULT_GROUP, trigger0); + schedulerControl.setReturnValue(new Date()); + } + scheduler.start(); + schedulerControl.setVoidCallable(); + scheduler.shutdown(false); + schedulerControl.setVoidCallable(); + schedulerControl.replay(); + + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean() { + protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName) { + return scheduler; + } + }; + schedulerFactoryBean.setJobFactory(null); + Map schedulerContext = new HashMap(); + schedulerContext.put("otherTestBean", tb); + schedulerFactoryBean.setSchedulerContextAsMap(schedulerContext); + schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); + if (overwrite) { + schedulerFactoryBean.setOverwriteExistingJobs(true); + } + try { + schedulerFactoryBean.afterPropertiesSet(); + } + finally { + schedulerFactoryBean.destroy(); + } + + schedulerControl.verify(); + } + + public void testSchedulerFactoryBeanWithListeners() throws Exception { + JobFactory jobFactory = new AdaptableJobFactory(); + + MockControl schedulerControl = MockControl.createControl(Scheduler.class); + final Scheduler scheduler = (Scheduler) schedulerControl.getMock(); + + SchedulerListener schedulerListener = new TestSchedulerListener(); + JobListener globalJobListener = new TestJobListener(); + JobListener jobListener = new TestJobListener(); + TriggerListener globalTriggerListener = new TestTriggerListener(); + TriggerListener triggerListener = new TestTriggerListener(); + + scheduler.setJobFactory(jobFactory); + schedulerControl.setVoidCallable(); + scheduler.addSchedulerListener(schedulerListener); + schedulerControl.setVoidCallable(); + scheduler.addGlobalJobListener(globalJobListener); + schedulerControl.setVoidCallable(); + scheduler.addJobListener(jobListener); + schedulerControl.setVoidCallable(); + scheduler.addGlobalTriggerListener(globalTriggerListener); + schedulerControl.setVoidCallable(); + scheduler.addTriggerListener(triggerListener); + schedulerControl.setVoidCallable(); + scheduler.start(); + schedulerControl.setVoidCallable(); + scheduler.shutdown(false); + schedulerControl.setVoidCallable(); + schedulerControl.replay(); + + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean() { + protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName) { + return scheduler; + } + }; + schedulerFactoryBean.setJobFactory(jobFactory); + schedulerFactoryBean.setSchedulerListeners(new SchedulerListener[] {schedulerListener}); + schedulerFactoryBean.setGlobalJobListeners(new JobListener[] {globalJobListener}); + schedulerFactoryBean.setJobListeners(new JobListener[] {jobListener}); + schedulerFactoryBean.setGlobalTriggerListeners(new TriggerListener[] {globalTriggerListener}); + schedulerFactoryBean.setTriggerListeners(new TriggerListener[] {triggerListener}); + try { + schedulerFactoryBean.afterPropertiesSet(); + } + finally { + schedulerFactoryBean.destroy(); + } + + schedulerControl.verify(); + } + + /*public void testMethodInvocationWithConcurrency() throws Exception { + methodInvokingConcurrency(true); + }*/ + + // We can't test both since Quartz somehow seems to keep things in memory + // enable both and one of them will fail (order doesn't matter). + /*public void testMethodInvocationWithoutConcurrency() throws Exception { + methodInvokingConcurrency(false); + }*/ + + private void methodInvokingConcurrency(boolean concurrent) throws Exception { + // Test the concurrency flag. + // Method invoking job with two triggers. + // If the concurrent flag is false, the triggers are NOT allowed + // to interfere with each other. + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryBean mijdfb = new MethodInvokingJobDetailFactoryBean(); + // set the concurrency flag! + mijdfb.setConcurrent(concurrent); + mijdfb.setBeanName("myJob1"); + mijdfb.setTargetObject(task1); + mijdfb.setTargetMethod("doWait"); + mijdfb.afterPropertiesSet(); + JobDetail jobDetail1 = (JobDetail) mijdfb.getObject(); + + SimpleTriggerBean trigger0 = new SimpleTriggerBean(); + trigger0.setBeanName("myTrigger1"); + trigger0.setJobDetail(jobDetail1); + trigger0.setStartDelay(0); + trigger0.setRepeatInterval(1); + trigger0.setRepeatCount(1); + trigger0.afterPropertiesSet(); + + SimpleTriggerBean trigger1 = new SimpleTriggerBean(); + trigger1.setBeanName("myTrigger1"); + trigger1.setJobDetail(jobDetail1); + trigger1.setStartDelay(1000L); + trigger1.setRepeatInterval(1); + trigger1.setRepeatCount(1); + trigger1.afterPropertiesSet(); + + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); + schedulerFactoryBean.setJobDetails(new JobDetail[] {jobDetail1}); + schedulerFactoryBean.setTriggers(new Trigger[] {trigger1, trigger0}); + schedulerFactoryBean.afterPropertiesSet(); + + // ok scheduler is set up... let's wait for like 4 seconds + try { + Thread.sleep(4000); + } + catch (InterruptedException ex) { + // fall through + } + + if (concurrent) { + assertEquals(2, task1.counter); + task1.stop(); + // we're done, both jobs have ran, let's call it a day + return; + } + else { + assertEquals(1, task1.counter); + task1.stop(); + // we need to check whether or not the test succeed with non-concurrent jobs + } + + try { + Thread.sleep(4000); + } + catch (InterruptedException ex) { + // fall through + } + + task1.stop(); + assertEquals(2, task1.counter); + + // Although we're destroying the scheduler, it does seem to keep things in memory: + // When executing both tests (concurrent and non-concurrent), the second test always + // fails. + schedulerFactoryBean.destroy(); + } + + public void testSchedulerFactoryBeanWithPlainQuartzObjects() throws Exception { + JobFactory jobFactory = new AdaptableJobFactory(); + + TestBean tb = new TestBean("tb", 99); + JobDetail jobDetail0 = new JobDetail(); + jobDetail0.setJobClass(Job.class); + jobDetail0.setName("myJob0"); + jobDetail0.setGroup(Scheduler.DEFAULT_GROUP); + jobDetail0.getJobDataMap().put("testBean", tb); + assertEquals(tb, jobDetail0.getJobDataMap().get("testBean")); + + CronTrigger trigger0 = new CronTrigger(); + trigger0.setName("myTrigger0"); + trigger0.setGroup(Scheduler.DEFAULT_GROUP); + trigger0.setJobName("myJob0"); + trigger0.setJobGroup(Scheduler.DEFAULT_GROUP); + trigger0.setStartTime(new Date()); + trigger0.setCronExpression("0/1 * * * * ?"); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryBean mijdfb = new MethodInvokingJobDetailFactoryBean(); + mijdfb.setName("myJob1"); + mijdfb.setGroup(Scheduler.DEFAULT_GROUP); + mijdfb.setTargetObject(task1); + mijdfb.setTargetMethod("doSomething"); + mijdfb.afterPropertiesSet(); + JobDetail jobDetail1 = (JobDetail) mijdfb.getObject(); + + SimpleTrigger trigger1 = new SimpleTrigger(); + trigger1.setName("myTrigger1"); + trigger1.setGroup(Scheduler.DEFAULT_GROUP); + trigger1.setJobName("myJob1"); + trigger1.setJobGroup(Scheduler.DEFAULT_GROUP); + trigger1.setStartTime(new Date()); + trigger1.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); + trigger1.setRepeatInterval(20); + + MockControl schedulerControl = MockControl.createControl(Scheduler.class); + final Scheduler scheduler = (Scheduler) schedulerControl.getMock(); + scheduler.setJobFactory(jobFactory); + schedulerControl.setVoidCallable(); + scheduler.getJobDetail("myJob0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getJobDetail("myJob1", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getTrigger("myTrigger0", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.getTrigger("myTrigger1", Scheduler.DEFAULT_GROUP); + schedulerControl.setReturnValue(null); + scheduler.addJob(jobDetail0, true); + schedulerControl.setVoidCallable(); + scheduler.addJob(jobDetail1, true); + schedulerControl.setVoidCallable(); + scheduler.scheduleJob(trigger0); + schedulerControl.setReturnValue(new Date()); + scheduler.scheduleJob(trigger1); + schedulerControl.setReturnValue(new Date()); + scheduler.start(); + schedulerControl.setVoidCallable(); + scheduler.shutdown(false); + schedulerControl.setVoidCallable(); + schedulerControl.replay(); + + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean() { + protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName) { + return scheduler; + } + }; + schedulerFactoryBean.setJobFactory(jobFactory); + schedulerFactoryBean.setJobDetails(new JobDetail[] {jobDetail0, jobDetail1}); + schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); + try { + schedulerFactoryBean.afterPropertiesSet(); + } + finally { + schedulerFactoryBean.destroy(); + } + + schedulerControl.verify(); + } + + public void testSchedulerFactoryBeanWithApplicationContext() throws Exception { + TestBean tb = new TestBean("tb", 99); + StaticApplicationContext ac = new StaticApplicationContext(); + + MockControl schedulerControl = MockControl.createControl(Scheduler.class); + final Scheduler scheduler = (Scheduler) schedulerControl.getMock(); + SchedulerContext schedulerContext = new SchedulerContext(); + scheduler.getContext(); + schedulerControl.setReturnValue(schedulerContext, 4); + scheduler.start(); + schedulerControl.setVoidCallable(); + scheduler.shutdown(false); + schedulerControl.setVoidCallable(); + schedulerControl.replay(); + + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean() { + protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName) { + return scheduler; + } + }; + schedulerFactoryBean.setJobFactory(null); + Map schedulerContextMap = new HashMap(); + schedulerContextMap.put("testBean", tb); + schedulerFactoryBean.setSchedulerContextAsMap(schedulerContextMap); + schedulerFactoryBean.setApplicationContext(ac); + schedulerFactoryBean.setApplicationContextSchedulerContextKey("appCtx"); + try { + schedulerFactoryBean.afterPropertiesSet(); + Scheduler returnedScheduler = (Scheduler) schedulerFactoryBean.getObject(); + assertEquals(tb, returnedScheduler.getContext().get("testBean")); + assertEquals(ac, returnedScheduler.getContext().get("appCtx")); + } + finally { + schedulerFactoryBean.destroy(); + } + + schedulerControl.verify(); + } + + public void testJobDetailBeanWithApplicationContext() throws Exception { + TestBean tb = new TestBean("tb", 99); + StaticApplicationContext ac = new StaticApplicationContext(); + + JobDetailBean jobDetail = new JobDetailBean(); + jobDetail.setJobClass(Job.class); + jobDetail.setBeanName("myJob0"); + Map jobData = new HashMap(); + jobData.put("testBean", tb); + jobDetail.setJobDataAsMap(jobData); + jobDetail.setApplicationContext(ac); + jobDetail.setApplicationContextJobDataKey("appCtx"); + jobDetail.afterPropertiesSet(); + + assertEquals(tb, jobDetail.getJobDataMap().get("testBean")); + assertEquals(ac, jobDetail.getJobDataMap().get("appCtx")); + } + + public void testMethodInvokingJobDetailFactoryBeanWithListenerNames() throws Exception { + TestMethodInvokingTask task = new TestMethodInvokingTask(); + MethodInvokingJobDetailFactoryBean mijdfb = new MethodInvokingJobDetailFactoryBean(); + String[] names = new String[] {"test1", "test2"}; + mijdfb.setName("myJob1"); + mijdfb.setGroup(Scheduler.DEFAULT_GROUP); + mijdfb.setTargetObject(task); + mijdfb.setTargetMethod("doSomething"); + mijdfb.setJobListenerNames(names); + mijdfb.afterPropertiesSet(); + JobDetail jobDetail = (JobDetail) mijdfb.getObject(); + List result = Arrays.asList(jobDetail.getJobListenerNames()); + assertEquals(Arrays.asList(names), result); + } + + public void testJobDetailBeanWithListenerNames() { + JobDetailBean jobDetail = new JobDetailBean(); + String[] names = new String[] {"test1", "test2"}; + jobDetail.setJobListenerNames(names); + List result = Arrays.asList(jobDetail.getJobListenerNames()); + assertEquals(Arrays.asList(names), result); + } + + public void testCronTriggerBeanWithListenerNames() { + CronTriggerBean trigger = new CronTriggerBean(); + String[] names = new String[] {"test1", "test2"}; + trigger.setTriggerListenerNames(names); + List result = Arrays.asList(trigger.getTriggerListenerNames()); + assertEquals(Arrays.asList(names), result); + } + + public void testSimpleTriggerBeanWithListenerNames() { + SimpleTriggerBean trigger = new SimpleTriggerBean(); + String[] names = new String[] {"test1", "test2"}; + trigger.setTriggerListenerNames(names); + List result = Arrays.asList(trigger.getTriggerListenerNames()); + assertEquals(Arrays.asList(names), result); + } + + public void testSchedulerWithTaskExecutor() throws Exception { + CountingTaskExecutor taskExecutor = new CountingTaskExecutor(); + DummyJob.count = 0; + + JobDetail jobDetail = new JobDetail(); + jobDetail.setJobClass(DummyJob.class); + jobDetail.setName("myJob"); + + SimpleTriggerBean trigger = new SimpleTriggerBean(); + trigger.setName("myTrigger"); + trigger.setJobDetail(jobDetail); + trigger.setStartDelay(1); + trigger.setRepeatInterval(500); + trigger.setRepeatCount(1); + trigger.afterPropertiesSet(); + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + bean.setTaskExecutor(taskExecutor); + bean.setTriggers(new Trigger[] {trigger}); + bean.setJobDetails(new JobDetail[] {jobDetail}); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertTrue(DummyJob.count > 0); + assertEquals(DummyJob.count, taskExecutor.count); + + bean.destroy(); + } + + public void testSchedulerWithRunnable() throws Exception { + DummyRunnable.count = 0; + + JobDetail jobDetail = new JobDetailBean(); + jobDetail.setJobClass(DummyRunnable.class); + jobDetail.setName("myJob"); + + SimpleTriggerBean trigger = new SimpleTriggerBean(); + trigger.setName("myTrigger"); + trigger.setJobDetail(jobDetail); + trigger.setStartDelay(1); + trigger.setRepeatInterval(500); + trigger.setRepeatCount(1); + trigger.afterPropertiesSet(); + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + bean.setTriggers(new Trigger[] {trigger}); + bean.setJobDetails(new JobDetail[] {jobDetail}); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertTrue(DummyRunnable.count > 0); + + bean.destroy(); + } + + public void testSchedulerWithQuartzJobBean() throws Exception { + DummyJob.param = 0; + DummyJob.count = 0; + + JobDetail jobDetail = new JobDetail(); + jobDetail.setJobClass(DummyJobBean.class); + jobDetail.setName("myJob"); + jobDetail.getJobDataMap().put("param", "10"); + + SimpleTriggerBean trigger = new SimpleTriggerBean(); + trigger.setName("myTrigger"); + trigger.setJobDetail(jobDetail); + trigger.setStartDelay(1); + trigger.setRepeatInterval(500); + trigger.setRepeatCount(1); + trigger.afterPropertiesSet(); + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + bean.setTriggers(new Trigger[] {trigger}); + bean.setJobDetails(new JobDetail[] {jobDetail}); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertEquals(10, DummyJobBean.param); + assertTrue(DummyJobBean.count > 0); + + bean.destroy(); + } + + public void testSchedulerWithSpringBeanJobFactory() throws Exception { + DummyJob.param = 0; + DummyJob.count = 0; + + JobDetail jobDetail = new JobDetail(); + jobDetail.setJobClass(DummyJob.class); + jobDetail.setName("myJob"); + jobDetail.getJobDataMap().put("param", "10"); + jobDetail.getJobDataMap().put("ignoredParam", "10"); + + SimpleTriggerBean trigger = new SimpleTriggerBean(); + trigger.setName("myTrigger"); + trigger.setJobDetail(jobDetail); + trigger.setStartDelay(1); + trigger.setRepeatInterval(500); + trigger.setRepeatCount(1); + trigger.afterPropertiesSet(); + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + bean.setJobFactory(new SpringBeanJobFactory()); + bean.setTriggers(new Trigger[] {trigger}); + bean.setJobDetails(new JobDetail[] {jobDetail}); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertEquals(10, DummyJob.param); + assertTrue(DummyJob.count > 0); + + bean.destroy(); + } + + public void testSchedulerWithSpringBeanJobFactoryAndParamMismatchNotIgnored() throws Exception { + DummyJob.param = 0; + DummyJob.count = 0; + + JobDetail jobDetail = new JobDetail(); + jobDetail.setJobClass(DummyJob.class); + jobDetail.setName("myJob"); + jobDetail.getJobDataMap().put("para", "10"); + jobDetail.getJobDataMap().put("ignoredParam", "10"); + + SimpleTriggerBean trigger = new SimpleTriggerBean(); + trigger.setName("myTrigger"); + trigger.setJobDetail(jobDetail); + trigger.setStartDelay(1); + trigger.setRepeatInterval(500); + trigger.setRepeatCount(1); + trigger.afterPropertiesSet(); + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + SpringBeanJobFactory jobFactory = new SpringBeanJobFactory(); + jobFactory.setIgnoredUnknownProperties(new String[] {"ignoredParam"}); + bean.setJobFactory(jobFactory); + bean.setTriggers(new Trigger[] {trigger}); + bean.setJobDetails(new JobDetail[] {jobDetail}); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertEquals(0, DummyJob.param); + assertTrue(DummyJob.count == 0); + + bean.destroy(); + } + + public void testSchedulerWithSpringBeanJobFactoryAndRunnable() throws Exception { + DummyRunnable.param = 0; + DummyRunnable.count = 0; + + JobDetail jobDetail = new JobDetailBean(); + jobDetail.setJobClass(DummyRunnable.class); + jobDetail.setName("myJob"); + jobDetail.getJobDataMap().put("param", "10"); + + SimpleTriggerBean trigger = new SimpleTriggerBean(); + trigger.setName("myTrigger"); + trigger.setJobDetail(jobDetail); + trigger.setStartDelay(1); + trigger.setRepeatInterval(500); + trigger.setRepeatCount(1); + trigger.afterPropertiesSet(); + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + bean.setJobFactory(new SpringBeanJobFactory()); + bean.setTriggers(new Trigger[] {trigger}); + bean.setJobDetails(new JobDetail[] {jobDetail}); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertEquals(10, DummyRunnable.param); + assertTrue(DummyRunnable.count > 0); + + bean.destroy(); + } + + public void testSchedulerWithSpringBeanJobFactoryAndQuartzJobBean() throws Exception { + DummyJobBean.param = 0; + DummyJobBean.count = 0; + + JobDetail jobDetail = new JobDetail(); + jobDetail.setJobClass(DummyJobBean.class); + jobDetail.setName("myJob"); + jobDetail.getJobDataMap().put("param", "10"); + + SimpleTriggerBean trigger = new SimpleTriggerBean(); + trigger.setName("myTrigger"); + trigger.setJobDetail(jobDetail); + trigger.setStartDelay(1); + trigger.setRepeatInterval(500); + trigger.setRepeatCount(1); + trigger.afterPropertiesSet(); + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + bean.setJobFactory(new SpringBeanJobFactory()); + bean.setTriggers(new Trigger[] {trigger}); + bean.setJobDetails(new JobDetail[] {jobDetail}); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertEquals(10, DummyJobBean.param); + assertTrue(DummyJobBean.count > 0); + + bean.destroy(); + } + + public void testSchedulerWithSpringBeanJobFactoryAndJobSchedulingData() throws Exception { + DummyJob.param = 0; + DummyJob.count = 0; + + SchedulerFactoryBean bean = new SchedulerFactoryBean(); + bean.setJobFactory(new SpringBeanJobFactory()); + bean.setJobSchedulingDataLocation("org/springframework/scheduling/quartz/job-scheduling-data.xml"); + bean.setResourceLoader(new FileSystemResourceLoader()); + bean.afterPropertiesSet(); + + Thread.sleep(500); + assertEquals(10, DummyJob.param); + assertTrue(DummyJob.count > 0); + + bean.destroy(); + } + + /** + * Tests the creation of multiple schedulers (SPR-772) + */ + public void testMultipleSchedulers() throws Exception { + ClassPathXmlApplicationContext ctx = + new ClassPathXmlApplicationContext("/org/springframework/scheduling/quartz/multipleSchedulers.xml"); + try { + Scheduler scheduler1 = (Scheduler) ctx.getBean("scheduler1"); + Scheduler scheduler2 = (Scheduler) ctx.getBean("scheduler2"); + assertNotSame(scheduler1, scheduler2); + assertEquals("quartz1", scheduler1.getSchedulerName()); + assertEquals("quartz2", scheduler2.getSchedulerName()); + } + finally { + ctx.close(); + } + } + + public void testWithTwoAnonymousMethodInvokingJobDetailFactoryBeans() throws InterruptedException { + ClassPathXmlApplicationContext ctx = + new ClassPathXmlApplicationContext("/org/springframework/scheduling/quartz/multipleAnonymousMethodInvokingJobDetailFB.xml"); + Thread.sleep(3000); + try { + QuartzTestBean exportService = (QuartzTestBean) ctx.getBean("exportService"); + QuartzTestBean importService = (QuartzTestBean) ctx.getBean("importService"); + + assertEquals("doImport called exportService", 0, exportService.getImportCount()); + assertEquals("doExport not called on exportService", 2, exportService.getExportCount()); + assertEquals("doImport not called on importService", 2, importService.getImportCount()); + assertEquals("doExport called on importService", 0, importService.getExportCount()); + } + finally { + ctx.close(); + } + } + + public void testSchedulerAccessorBean() throws InterruptedException { + ClassPathXmlApplicationContext ctx = + new ClassPathXmlApplicationContext("/org/springframework/scheduling/quartz/schedulerAccessorBean.xml"); + Thread.sleep(3000); + try { + QuartzTestBean exportService = (QuartzTestBean) ctx.getBean("exportService"); + QuartzTestBean importService = (QuartzTestBean) ctx.getBean("importService"); + + assertEquals("doImport called exportService", 0, exportService.getImportCount()); + assertEquals("doExport not called on exportService", 2, exportService.getExportCount()); + assertEquals("doImport not called on importService", 2, importService.getImportCount()); + assertEquals("doExport called on importService", 0, importService.getExportCount()); + } + finally { + ctx.close(); + } + } + + public void testSchedulerRepositoryExposure() throws InterruptedException { + ClassPathXmlApplicationContext ctx = + new ClassPathXmlApplicationContext("/org/springframework/scheduling/quartz/schedulerRepositoryExposure.xml"); + assertSame(SchedulerRepository.getInstance().lookup("myScheduler"), ctx.getBean("scheduler")); + ctx.close(); + } + + + private static class TestSchedulerListener implements SchedulerListener { + + public void jobScheduled(Trigger trigger) { + } + + public void jobUnscheduled(String triggerName, String triggerGroup) { + } + + public void triggerFinalized(Trigger trigger) { + } + + public void triggersPaused(String triggerName, String triggerGroup) { + } + + public void triggersResumed(String triggerName, String triggerGroup) { + } + + public void jobsPaused(String jobName, String jobGroup) { + } + + public void jobsResumed(String jobName, String jobGroup) { + } + + public void schedulerError(String msg, SchedulerException cause) { + } + + public void schedulerShutdown() { + } + } + + + private static class TestJobListener implements JobListener { + + public String getName() { + return null; + } + + public void jobToBeExecuted(JobExecutionContext context) { + } + + public void jobExecutionVetoed(JobExecutionContext context) { + } + + public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { + } + } + + + private static class TestTriggerListener implements TriggerListener { + + public String getName() { + return null; + } + + public void triggerFired(Trigger trigger, JobExecutionContext context) { + } + + public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) { + return false; + } + + public void triggerMisfired(Trigger trigger) { + } + + public void triggerComplete(Trigger trigger, JobExecutionContext context, int triggerInstructionCode) { + } + } + + + public static class CountingTaskExecutor implements TaskExecutor { + + private int count; + + public void execute(Runnable task) { + this.count++; + task.run(); + } + } + + + public static class DummyJob implements Job { + + private static int param; + + private static int count; + + public void setParam(int value) { + if (param > 0) { + throw new IllegalStateException("Param already set"); + } + param = value; + } + + public synchronized void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + count++; + } + } + + + public static class DummyJobBean extends QuartzJobBean { + + private static int param; + + private static int count; + + public void setParam(int value) { + if (param > 0) { + throw new IllegalStateException("Param already set"); + } + param = value; + } + + protected synchronized void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { + count++; + } + } + + + public static class DummyRunnable implements Runnable { + + private static int param; + + private static int count; + + public void setParam(int value) { + if (param > 0) { + throw new IllegalStateException("Param already set"); + } + param = value; + } + + public void run() { + count++; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzTestBean.java new file mode 100644 index 00000000000..8890e39ed08 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/QuartzTestBean.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.quartz; + +/** + * @author Rob Harrop + */ +public class QuartzTestBean { + + private int importCount; + + private int exportCount; + + + public void doImport() { + ++importCount; + } + + public void doExport() { + ++exportCount; + } + + public int getImportCount() { + return importCount; + } + + public int getExportCount() { + return exportCount; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/job-scheduling-data.xml b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/job-scheduling-data.xml new file mode 100644 index 00000000000..d9200432831 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/job-scheduling-data.xml @@ -0,0 +1,29 @@ + + + + + myJob + myGroup + org.springframework.scheduling.quartz.QuartzSupportTests$DummyJob + + + param + 10 + + + + + + myTrigger + myGroup + 1 + 500 + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleAnonymousMethodInvokingJobDetailFB.xml b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleAnonymousMethodInvokingJobDetailFB.xml new file mode 100644 index 00000000000..40f5a8d7626 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleAnonymousMethodInvokingJobDetailFB.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleSchedulers.xml b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleSchedulers.xml new file mode 100644 index 00000000000..02d8f3668b6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/multipleSchedulers.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerAccessorBean.xml b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerAccessorBean.xml new file mode 100644 index 00000000000..0c4c9578b2d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerAccessorBean.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerRepositoryExposure.xml b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerRepositoryExposure.xml new file mode 100644 index 00000000000..46410a7cd31 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/quartz/schedulerRepositoryExposure.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerSupportTests.java new file mode 100644 index 00000000000..620c737c860 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerSupportTests.java @@ -0,0 +1,122 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.timer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import junit.framework.TestCase; + +import org.springframework.scheduling.TestMethodInvokingTask; + +/** + * @author Juergen Hoeller + * @since 20.02.2004 + */ +public class TimerSupportTests extends TestCase { + + public void testTimerFactoryBean() throws Exception { + final TestTimerTask timerTask0 = new TestTimerTask(); + + TestMethodInvokingTask task1 = new TestMethodInvokingTask(); + MethodInvokingTimerTaskFactoryBean mittfb = new MethodInvokingTimerTaskFactoryBean(); + mittfb.setTargetObject(task1); + mittfb.setTargetMethod("doSomething"); + mittfb.afterPropertiesSet(); + final TimerTask timerTask1 = (TimerTask) mittfb.getObject(); + + final TestRunnable timerTask2 = new TestRunnable(); + + ScheduledTimerTask[] tasks = new ScheduledTimerTask[3]; + tasks[0] = new ScheduledTimerTask(timerTask0, 0, 10, false); + tasks[1] = new ScheduledTimerTask(timerTask1, 10, 20, true); + tasks[2] = new ScheduledTimerTask(timerTask2, 20); + + final List success = new ArrayList(3); + final Timer timer = new Timer(true) { + public void schedule(TimerTask task, long delay, long period) { + if (task == timerTask0 && delay == 0 && period == 10) { + success.add(Boolean.TRUE); + } + } + public void scheduleAtFixedRate(TimerTask task, long delay, long period) { + if (task == timerTask1 && delay == 10 && period == 20) { + success.add(Boolean.TRUE); + } + } + public void schedule(TimerTask task, long delay) { + if (task instanceof DelegatingTimerTask && delay == 20) { + success.add(Boolean.TRUE); + } + } + public void cancel() { + success.add(Boolean.TRUE); + } + }; + + TimerFactoryBean timerFactoryBean = new TimerFactoryBean() { + protected Timer createTimer(String name, boolean daemon) { + return timer; + } + }; + try { + timerFactoryBean.setScheduledTimerTasks(tasks); + timerFactoryBean.afterPropertiesSet(); + assertTrue(timerFactoryBean.getObject() instanceof Timer); + timerTask0.run(); + timerTask1.run(); + timerTask2.run(); + } + finally { + timerFactoryBean.destroy(); + } + + assertTrue("Correct Timer invocations", success.size() == 4); + assertTrue("TimerTask0 works", timerTask0.counter == 1); + assertTrue("TimerTask1 works", task1.counter == 1); + assertTrue("TimerTask2 works", timerTask2.counter == 1); + } + + public void testPlainTimerFactoryBean() { + TimerFactoryBean tfb = new TimerFactoryBean(); + tfb.afterPropertiesSet(); + tfb.destroy(); + } + + + private static class TestTimerTask extends TimerTask { + + private int counter = 0; + + public void run() { + counter++; + } + } + + + private static class TestRunnable implements Runnable { + + private int counter = 0; + + public void run() { + counter++; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerTaskExecutorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerTaskExecutorTests.java new file mode 100644 index 00000000000..db011ede1f7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scheduling/timer/TimerTaskExecutorTests.java @@ -0,0 +1,189 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.timer; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +import java.util.Timer; + +/** + * Unit tests for the {@link TimerTaskExecutor} class. + * + * @author Rick Evans + */ +public final class TimerTaskExecutorTests extends TestCase { + + public void testExecuteChokesWithNullTimer() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TimerTaskExecutor executor = new TimerTaskExecutor(); + executor.execute(new NoOpRunnable()); + } + }.runTest(); + } + + public void testExecuteChokesWithNullTask() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TimerTaskExecutor executor = new TimerTaskExecutor(new Timer()); + executor.execute(null); + } + }.runTest(); + } + + public void testExecuteChokesWithNegativeDelay() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TimerTaskExecutor executor = new TimerTaskExecutor(new Timer()); + executor.setDelay(-10); + executor.execute(new NoOpRunnable()); + } + }.runTest(); + } + + public void testExecuteReallyDoesScheduleTheSuppliedTask() throws Exception { + final Object monitor = new Object(); + + RunAwareRunnable task = new RunAwareRunnable(monitor); + + TimerTaskExecutor executor = new TimerTaskExecutor(new Timer()); + executor.execute(task); + + synchronized (monitor) { + monitor.wait(5000); + } + + assertTrue("Supplied task (a Runnable) is not being invoked.", task.isRunWasCalled()); + } + + public void testCtorWithNullTimer() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new TimerTaskExecutor(null); + } + }.runTest(); + } + + public void testCreateTimerMethodIsCalledIfNoTimerIsExplicitlySupplied() throws Exception { + CreationAwareTimerTaskExecutor executor = new CreationAwareTimerTaskExecutor(); + executor.afterPropertiesSet(); + assertTrue("If no Timer is set explicitly, then the protected createTimer() " + + "method must be called to create the Timer (it obviously isn't being called).", + executor.isCreateTimerWasCalled()); + } + + public void testCreateTimerMethodIsNotCalledIfTimerIsExplicitlySupplied() throws Exception { + CreationAwareTimerTaskExecutor executor = new CreationAwareTimerTaskExecutor(); + executor.setTimer(new Timer()); + executor.afterPropertiesSet(); + assertFalse("If a Timer is set explicitly, then the protected createTimer() " + + "method must not be called to create the Timer (it obviously is being called, in error).", + executor.isCreateTimerWasCalled()); + } + + public void testThatTheDestroyCallbackCancelsTheTimerIfNoTimerIsExplicitlySupplied() throws Exception { + + final CancelAwareTimer timer = new CancelAwareTimer(); + + TimerTaskExecutor executor = new TimerTaskExecutor() { + + protected Timer createTimer() { + return timer; + } + }; + executor.afterPropertiesSet(); + executor.destroy(); + assertTrue("When the Timer used is created by the TimerTaskExecutor because " + + "no Timer was set explicitly, then the destroy() callback must cancel() said Timer (it obviously isn't doing this).", + timer.isCancelWasCalled()); + } + + public void testThatTheDestroyCallbackDoesNotCancelTheTimerIfTheTimerWasSuppliedExplictly() throws Exception { + TimerTaskExecutor executor = new TimerTaskExecutor(); + CancelAwareTimer timer = new CancelAwareTimer(); + executor.setTimer(timer); + executor.afterPropertiesSet(); + executor.destroy(); + assertFalse("When the Timer used is not created by the TimerTaskExecutor because " + + "it Timer was set explicitly, then the destroy() callback must NOT cancel() said Timer (it obviously is, in error).", + timer.isCancelWasCalled()); + } + + + private final static class CreationAwareTimerTaskExecutor extends TimerTaskExecutor { + + private boolean createTimerWasCalled = false; + + + public boolean isCreateTimerWasCalled() { + return this.createTimerWasCalled; + } + + protected Timer createTimer() { + this.createTimerWasCalled = true; + return super.createTimer(); + } + + } + + private static class CancelAwareTimer extends Timer { + + private boolean cancelWasCalled; + + + public boolean isCancelWasCalled() { + return this.cancelWasCalled; + } + + + public void cancel() { + this.cancelWasCalled = true; + super.cancel(); + } + } + + private static class RunAwareRunnable implements Runnable { + private boolean runWasCalled; + private final Object monitor; + + public RunAwareRunnable(Object monitor) { + this.monitor = monitor; + } + + + public boolean isRunWasCalled() { + return this.runWasCalled; + } + + + public void run() { + this.runWasCalled = true; + synchronized (monitor) { + monitor.notifyAll(); + } + } + } + + private static final class NoOpRunnable implements Runnable { + + public void run() { + // explicit no-op + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/Calculator.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/Calculator.java new file mode 100644 index 00000000000..a2923db8214 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/Calculator.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +/** + * @author Rob Harrop + */ +public interface Calculator { + + int add(int x, int y); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/CallCounter.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/CallCounter.java new file mode 100644 index 00000000000..ee21c8c2e78 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/CallCounter.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +/** + * @author Juergen Hoeller + */ +public interface CallCounter { + + void before(); + + int getCalls(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/ConfigurableMessenger.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/ConfigurableMessenger.java new file mode 100644 index 00000000000..bf7b4656455 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/ConfigurableMessenger.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +/** + * @author Juergen Hoeller + */ +public interface ConfigurableMessenger extends Messenger { + + void setMessage(String message); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/ContextScriptBean.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/ContextScriptBean.java new file mode 100644 index 00000000000..052209d92f8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/ContextScriptBean.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +import org.springframework.beans.TestBean; +import org.springframework.context.ApplicationContext; + +/** + * @author Juergen Hoeller + * @since 08.08.2006 + */ +public interface ContextScriptBean extends ScriptBean { + + TestBean getTestBean(); + + ApplicationContext getApplicationContext(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/Messenger.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/Messenger.java new file mode 100644 index 00000000000..7e1f3aff64a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/Messenger.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +/** + * @author Rob Harrop + */ +public interface Messenger { + + String getMessage(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/MessengerScrambler.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/MessengerScrambler.java new file mode 100644 index 00000000000..cf8253f91b3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/MessengerScrambler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +import org.aspectj.lang.ProceedingJoinPoint; + +/** + * Twee advice that 'scrambles' the return value + * of a {@link Messenger} invocation. + * + * @author Rick Evans + */ +public final class MessengerScrambler { + + public String scramble(ProceedingJoinPoint pjp) throws Throwable { + String message = (String) pjp.proceed(); + return new StringBuffer(message).reverse().toString(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/ScriptBean.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/ScriptBean.java new file mode 100644 index 00000000000..2630e5b3a9c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/ScriptBean.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +/** + * Simple interface used in testing the scripted beans support. + * + * @author Rick Evans + */ +public interface ScriptBean { + + String getName(); + + void setName(String name); + + int getAge(); + + void setAge(int age); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/TestBeanAwareMessenger.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/TestBeanAwareMessenger.java new file mode 100644 index 00000000000..ddc139475cc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/TestBeanAwareMessenger.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting; + +import org.springframework.beans.TestBean; + +/** + * @author Juergen Hoeller + */ +public interface TestBeanAwareMessenger extends ConfigurableMessenger { + + TestBean getTestBean(); + + void setTestBean(TestBean testBean); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Broken.bsh b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Broken.bsh new file mode 100644 index 00000000000..5b1af163a47 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Broken.bsh @@ -0,0 +1 @@ +one sure is the loneliest number... that i'll ever know \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/BshScriptFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/BshScriptFactoryTests.java new file mode 100644 index 00000000000..090ef9fde41 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/BshScriptFactoryTests.java @@ -0,0 +1,306 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.bsh; + +import java.util.Arrays; +import java.util.Collection; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.target.dynamic.Refreshable; +import org.springframework.beans.TestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.NestedRuntimeException; +import org.springframework.scripting.Calculator; +import org.springframework.scripting.ConfigurableMessenger; +import org.springframework.scripting.Messenger; +import org.springframework.scripting.ScriptCompilationException; +import org.springframework.scripting.ScriptSource; +import org.springframework.scripting.TestBeanAwareMessenger; +import org.springframework.scripting.support.ScriptFactoryPostProcessor; + +/** + * @author Rob Harrop + * @author Rick Evans + * @author Juergen Hoeller + */ +public class BshScriptFactoryTests extends TestCase { + + public void testStaticScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass()); + + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Calculator.class)).contains("calculator")); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messenger")); + + Calculator calc = (Calculator) ctx.getBean("calculator"); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertEquals(calc, calc); + assertEquals(messenger, messenger); + assertTrue(!messenger.equals(calc)); + assertTrue(messenger.hashCode() != calc.hashCode()); + assertTrue(!messenger.toString().equals(calc.toString())); + + assertEquals(5, calc.add(2, 3)); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + + assertTrue(ctx.getBeansOfType(Calculator.class).values().contains(calc)); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + + public void testStaticScriptWithNullReturnValue() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerWithConfig")); + + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerWithConfig"); + messenger.setMessage(null); + assertNull(messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + + public void testStaticScriptWithTwoInterfacesSpecified() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerWithConfigExtra")); + + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerWithConfigExtra"); + messenger.setMessage(null); + assertNull(messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + + ctx.close(); + assertNull(messenger.getMessage()); + } + + public void testStaticWithScriptReturningInstance() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstance")); + + Messenger messenger = (Messenger) ctx.getBean("messengerInstance"); + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + + ctx.close(); + assertNull(messenger.getMessage()); + } + + public void testStaticScriptImplementingInterface() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerImpl")); + + Messenger messenger = (Messenger) ctx.getBean("messengerImpl"); + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + + ctx.close(); + assertNull(messenger.getMessage()); + } + + public void testStaticPrototypeScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertNotSame(messenger, messenger2); + assertSame(messenger.getClass(), messenger2.getClass()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + } + + public void testNonStaticScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bshRefreshableContext.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger)); + assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + + Refreshable refreshable = (Refreshable) messenger; + refreshable.refresh(); + + assertEquals("Message is incorrect after refresh", desiredMessage, messenger.getMessage()); + assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount()); + } + + public void testNonStaticPrototypeScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bshRefreshableContext.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger)); + assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable); + + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + + Refreshable refreshable = (Refreshable) messenger; + refreshable.refresh(); + + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount()); + } + + public void testScriptCompilationException() throws Exception { + try { + new ClassPathXmlApplicationContext("org/springframework/scripting/bsh/bshBrokenContext.xml"); + fail("Must throw exception for broken script file"); + } + catch (NestedRuntimeException ex) { + assertTrue(ex.contains(ScriptCompilationException.class)); + } + } + + public void testScriptThatCompilesButIsJustPlainBad() throws Exception { + MockControl mock = MockControl.createControl(ScriptSource.class); + ScriptSource script = (ScriptSource) mock.getMock(); + script.getScriptAsString(); + final String badScript = "String getMessage() { throw new IllegalArgumentException(); }"; + mock.setReturnValue(badScript); + script.isModified(); + mock.setReturnValue(true); + mock.replay(); + BshScriptFactory factory = new BshScriptFactory( + ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript, + new Class[] {Messenger.class}); + try { + Messenger messenger = (Messenger) factory.getScriptedObject(script, new Class[]{Messenger.class}); + messenger.getMessage(); + fail("Must have thrown a BshScriptUtils.BshExecutionException."); + } + catch (BshScriptUtils.BshExecutionException expected) { + } + mock.verify(); + } + + public void testCtorWithNullScriptSourceLocator() throws Exception { + try { + new BshScriptFactory(null, new Class[] {Messenger.class}); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithEmptyScriptSourceLocator() throws Exception { + try { + new BshScriptFactory("", new Class[] {Messenger.class}); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithWhitespacedScriptSourceLocator() throws Exception { + try { + new BshScriptFactory("\n ", new Class[] {Messenger.class}); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testResourceScriptFromTag() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass()); + TestBean testBean = (TestBean) ctx.getBean("testBean"); + + Collection beanNames = Arrays.asList(ctx.getBeanNamesForType(Messenger.class)); + assertTrue(beanNames.contains("messenger")); + assertTrue(beanNames.contains("messengerImpl")); + assertTrue(beanNames.contains("messengerInstance")); + + Messenger messenger = (Messenger) ctx.getBean("messenger"); + assertEquals("Hello World!", messenger.getMessage()); + assertFalse(messenger instanceof Refreshable); + + Messenger messengerImpl = (Messenger) ctx.getBean("messengerImpl"); + assertEquals("Hello World!", messengerImpl.getMessage()); + + Messenger messengerInstance = (Messenger) ctx.getBean("messengerInstance"); + assertEquals("Hello World!", messengerInstance.getMessage()); + + TestBeanAwareMessenger messengerByType = (TestBeanAwareMessenger) ctx.getBean("messengerByType"); + assertEquals(testBean, messengerByType.getTestBean()); + + TestBeanAwareMessenger messengerByName = (TestBeanAwareMessenger) ctx.getBean("messengerByName"); + assertEquals(testBean, messengerByName.getTestBean()); + + Collection beans = ctx.getBeansOfType(Messenger.class).values(); + assertTrue(beans.contains(messenger)); + assertTrue(beans.contains(messengerImpl)); + assertTrue(beans.contains(messengerInstance)); + assertTrue(beans.contains(messengerByType)); + assertTrue(beans.contains(messengerByName)); + + ctx.close(); + assertNull(messenger.getMessage()); + assertNull(messengerImpl.getMessage()); + assertNull(messengerInstance.getMessage()); + } + + public void testPrototypeScriptFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertNotSame(messenger, messenger2); + assertSame(messenger.getClass(), messenger2.getClass()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + } + + public void testInlineScriptFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass()); + Calculator calculator = (Calculator) ctx.getBean("calculator"); + assertNotNull(calculator); + assertFalse(calculator instanceof Refreshable); + } + + public void testRefreshableFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger"); + assertEquals("Hello World!", messenger.getMessage()); + assertTrue("Messenger should be Refreshable", messenger instanceof Refreshable); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Calculator.bsh b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Calculator.bsh new file mode 100644 index 00000000000..cc88f798123 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Calculator.bsh @@ -0,0 +1,3 @@ +int add(int x, int y) { + return x + y; +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Messenger.bsh b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Messenger.bsh new file mode 100644 index 00000000000..b15af62a160 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/Messenger.bsh @@ -0,0 +1,21 @@ +String message; + +boolean active; + +void init() { + active = true; +} + +String getMessage() { + if (!active && message != null) throw new java.lang.IllegalStateException(); + return message; +} + +void setMessage(String aMessage) { + message = aMessage; +} + +void destroy() { + message = null; + active = false; +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerImpl.bsh b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerImpl.bsh new file mode 100644 index 00000000000..62bfe8b7bf3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerImpl.bsh @@ -0,0 +1,38 @@ +import org.springframework.beans.TestBean; +import org.springframework.scripting.TestBeanAwareMessenger; + +public class MyMessenger implements TestBeanAwareMessenger { + + private String message; + + private TestBean testBean; + + private boolean active; + + public void init() { + active = true; + } + + public String getMessage() { + if (!active && message != null) throw new java.lang.IllegalStateException(); + return message; + } + + public void setMessage(String aMessage) { + message = aMessage; + } + + public TestBean getTestBean() { + return testBean; + } + + public void setTestBean(TestBean tb) { + testBean = tb; + } + + public void destroy() { + message = null; + active = false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerInstance.bsh b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerInstance.bsh new file mode 100644 index 00000000000..e211b1b3f6c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/MessengerInstance.bsh @@ -0,0 +1,28 @@ +import org.springframework.scripting.Messenger; + +public class MyMessenger implements Messenger { + + private String message; + + private boolean active; + + public void init() { + active = true; + } + + public String getMessage() { + if (!active && message != null) throw new java.lang.IllegalStateException(); + return message; + } + + public void setMessage(String aMessage) { + message = aMessage; + } + + public void destroy() { + message = null; + active = false; + } +} + +return new MyMessenger() ; diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bsh-with-xsd.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bsh-with-xsd.xml new file mode 100644 index 00000000000..09453b3c0da --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bsh-with-xsd.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + int add(int x, int y) { + return x + y; + } + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshBrokenContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshBrokenContext.xml new file mode 100644 index 00000000000..ffa602cfdda --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshBrokenContext.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshContext.xml new file mode 100644 index 00000000000..27f6378f981 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshContext.xml @@ -0,0 +1,71 @@ + + + + + + + + + + inline: +int add(int x, int y) { + return x + y; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshRefreshableContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshRefreshableContext.xml new file mode 100644 index 00000000000..a5365960226 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/bsh/bshRefreshableContext.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ITestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ITestBean.java new file mode 100644 index 00000000000..30ad6626a30 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ITestBean.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.config; + +/** + * @author Mark Fisher + */ +public interface ITestBean { + + boolean isInitialized(); + + boolean isDestroyed(); + + ITestBean getOtherBean(); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/OtherTestBean.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/OtherTestBean.java new file mode 100644 index 00000000000..4a542c0c6e4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/OtherTestBean.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.config; + +/** + * @author Mark Fisher + */ +public class OtherTestBean implements ITestBean { + + public ITestBean getOtherBean() { + return null; + } + + public boolean isInitialized() { + return false; + } + + public boolean isDestroyed() { + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ScriptingDefaultsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ScriptingDefaultsTests.java new file mode 100644 index 00000000000..28d88820585 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/ScriptingDefaultsTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.config; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.target.dynamic.AbstractRefreshableTargetSource; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Mark Fisher + */ +public class ScriptingDefaultsTests extends TestCase { + + private static final String CONFIG = + "org/springframework/scripting/config/scriptingDefaultsTests.xml"; + + + public void testDefaultRefreshCheckDelay() throws Exception { + ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG); + Advised advised = (Advised) context.getBean("testBean"); + AbstractRefreshableTargetSource targetSource = + ((AbstractRefreshableTargetSource) advised.getTargetSource()); + Field field = AbstractRefreshableTargetSource.class.getDeclaredField("refreshCheckDelay"); + field.setAccessible(true); + long delay = ((Long) field.get(targetSource)).longValue(); + assertEquals(5000L, delay); + } + + public void testDefaultInitMethod() { + ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG); + ITestBean testBean = (ITestBean) context.getBean("testBean"); + assertTrue(testBean.isInitialized()); + } + + public void testDefaultDestroyMethod() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(CONFIG); + ITestBean testBean = (ITestBean) context.getBean("nonRefreshableTestBean"); + assertFalse(testBean.isDestroyed()); + context.close(); + assertTrue(testBean.isDestroyed()); + } + + public void testDefaultAutowire() { + ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG); + ITestBean testBean = (ITestBean) context.getBean("testBean"); + ITestBean otherBean = (ITestBean) context.getBean("otherBean"); + assertEquals(otherBean, testBean.getOtherBean()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/TestBean.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/TestBean.groovy new file mode 100644 index 00000000000..74188adfb55 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/TestBean.groovy @@ -0,0 +1,19 @@ +package org.springframework.scripting.config + +class TestBean implements ITestBean { + + ITestBean otherBean + + boolean initialized + + boolean destroyed + + void setOtherBean(ITestBean otherBean) { + this.otherBean = otherBean; + } + + void startup() { this.initialized = true } + + void shutdown() { this.destroyed = true } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/scriptingDefaultsTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/scriptingDefaultsTests.xml new file mode 100644 index 00000000000..50ccdf95853 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/config/scriptingDefaultsTests.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Broken.groovyb b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Broken.groovyb new file mode 100644 index 00000000000..b9e6515230c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Broken.groovyb @@ -0,0 +1,14 @@ +I have eaten +the plums +that were in +the icebox + +and which +you were probably +saving +for breakfast + +Forgive me +they were delicious +so sweet +and so cold \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Calculator.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Calculator.groovy new file mode 100644 index 00000000000..9be3036fd5d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Calculator.groovy @@ -0,0 +1,10 @@ +package org.springframework.scripting.groovy; + +import org.springframework.scripting.Calculator + +class GroovyCalculator implements Calculator { + + int add(int x, int y) { + return x + y; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/CallCounter.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/CallCounter.groovy new file mode 100644 index 00000000000..fd2303782d8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/CallCounter.groovy @@ -0,0 +1,24 @@ +package org.springframework.scripting.groovy; + +import org.springframework.scripting.CallCounter; + +class GroovyCallCounter implements CallCounter { + + int count = -100; + + void init() { + count = 0; + } + + void before() { + count++; + } + + int getCalls() { + return count; + } + + void destroy() { + count = -200; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/DelegatingCalculator.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/DelegatingCalculator.groovy new file mode 100644 index 00000000000..e60fb52734c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/DelegatingCalculator.groovy @@ -0,0 +1,19 @@ +package org.springframework.scripting.groovy; + +import org.springframework.scripting.Calculator + +class DelegatingCalculator implements Calculator { + + def Calculator delegate; + + int add(int x, int y) { + //println "hello" + //println this.metaClass.getClass() + //println delegate.metaClass.getClass() + //delegate.metaClass.invokeMethod("add", [x,y]) + + delegate.callMissingMethod() + + return delegate.add(x,y) + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyClassLoadingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyClassLoadingTests.java new file mode 100644 index 00000000000..530559a6b47 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyClassLoadingTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.groovy; + +import java.lang.reflect.Method; + +import groovy.lang.GroovyClassLoader; +import junit.framework.TestCase; + +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.util.ReflectionUtils; + +/** + * @author Mark Fisher + */ +public class GroovyClassLoadingTests extends TestCase { + + public void testClassLoading() throws Exception { + StaticApplicationContext context = new StaticApplicationContext(); + + GroovyClassLoader gcl = new GroovyClassLoader(); + Class class1 = gcl.parseClass("class TestBean { def myMethod() { \"foo\" } }"); + Class class2 = gcl.parseClass("class TestBean { def myMethod() { \"bar\" } }"); + + context.registerBeanDefinition("testBean", new RootBeanDefinition(class1)); + Object testBean1 = context.getBean("testBean"); + Method method1 = class1.getDeclaredMethod("myMethod", new Class[0]); + Object result1 = ReflectionUtils.invokeMethod(method1, testBean1); + assertEquals("foo", (String) result1); + + // ### uncommenting the next line causes the test to pass for Spring > 2.0.2 ### + //context.removeBeanDefinition("testBean"); + + context.registerBeanDefinition("testBean", new RootBeanDefinition(class2)); + Object testBean2 = context.getBean("testBean"); + Method method2 = class2.getDeclaredMethod("myMethod", new Class[0]); + Object result2 = ReflectionUtils.invokeMethod(method2, testBean2); + assertEquals("bar", (String) result2); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java new file mode 100644 index 00000000000..a8641a688ba --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java @@ -0,0 +1,447 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.groovy; + +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.Map; + +import groovy.lang.DelegatingMetaClass; +import groovy.lang.GroovyObject; +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.target.dynamic.Refreshable; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.NestedRuntimeException; +import org.springframework.scripting.Calculator; +import org.springframework.scripting.CallCounter; +import org.springframework.scripting.ConfigurableMessenger; +import org.springframework.scripting.ContextScriptBean; +import org.springframework.scripting.Messenger; +import org.springframework.scripting.ScriptCompilationException; +import org.springframework.scripting.ScriptSource; +import org.springframework.scripting.support.ScriptFactoryPostProcessor; +import org.springframework.test.AssertThrows; + +/** + * @author Rob Harrop + * @author Rick Evans + * @author Rod Johnson + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class GroovyScriptFactoryTests extends TestCase { + + public void testStaticScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); + + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Calculator.class)).contains("calculator")); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messenger")); + + Calculator calc = (Calculator) ctx.getBean("calculator"); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(calc)); + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + + assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertEquals(calc, calc); + assertEquals(messenger, messenger); + assertTrue(!messenger.equals(calc)); + assertTrue(messenger.hashCode() != calc.hashCode()); + assertTrue(!messenger.toString().equals(calc.toString())); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + + assertTrue(ctx.getBeansOfType(Calculator.class).values().contains(calc)); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + + public void testStaticPrototypeScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertNotSame(messenger, messenger2); + assertSame(messenger.getClass(), messenger2.getClass()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + } + + public void testStaticScriptWithInstance() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstance")); + Messenger messenger = (Messenger) ctx.getBean("messengerInstance"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + + public void testStaticScriptWithInlineDefinedInstance() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstanceInline")); + Messenger messenger = (Messenger) ctx.getBean("messengerInstanceInline"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + + public void testNonStaticScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyRefreshableContext.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger)); + assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + + Refreshable refreshable = (Refreshable) messenger; + refreshable.refresh(); + + assertEquals("Message is incorrect after refresh.", desiredMessage, messenger.getMessage()); + assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount()); + } + + public void testNonStaticPrototypeScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyRefreshableContext.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger)); + assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable); + + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + + Refreshable refreshable = (Refreshable) messenger; + refreshable.refresh(); + + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount()); + } + + public void testScriptCompilationException() throws Exception { + try { + new ClassPathXmlApplicationContext("org/springframework/scripting/groovy/groovyBrokenContext.xml"); + fail("Should throw exception for broken script file"); + } + catch (NestedRuntimeException ex) { + assertTrue("Wrong root cause: " + ex, ex.contains(ScriptCompilationException.class)); + } + } + + public void testScriptedClassThatDoesNotHaveANoArgCtor() throws Exception { + MockControl mock = MockControl.createControl(ScriptSource.class); + ScriptSource script = (ScriptSource) mock.getMock(); + script.getScriptAsString(); + final String badScript = "class Foo { public Foo(String foo) {}}"; + mock.setReturnValue(badScript); + script.suggestedClassName(); + mock.setReturnValue("someName"); + mock.replay(); + GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript); + try { + factory.getScriptedObject(script, new Class[]{}); + fail("Must have thrown a ScriptCompilationException (no public no-arg ctor in scripted class)."); + } + catch (ScriptCompilationException expected) { + assertTrue(expected.contains(InstantiationException.class)); + } + mock.verify(); + } + + public void testScriptedClassThatHasNoPublicNoArgCtor() throws Exception { + MockControl mock = MockControl.createControl(ScriptSource.class); + ScriptSource script = (ScriptSource) mock.getMock(); + script.getScriptAsString(); + final String badScript = "class Foo { protected Foo() {}}"; + mock.setReturnValue(badScript); + script.suggestedClassName(); + mock.setReturnValue("someName"); + mock.replay(); + GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript); + try { + factory.getScriptedObject(script, new Class[]{}); + fail("Must have thrown a ScriptCompilationException (no oublic no-arg ctor in scripted class)."); + } + catch (ScriptCompilationException expected) { + assertTrue(expected.contains(IllegalAccessException.class)); + } + mock.verify(); + } + + public void testWithTwoClassesDefinedInTheOneGroovyFile_CorrectClassFirst() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("twoClassesCorrectOneFirst.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + assertNotNull(messenger); + assertEquals("Hello World!", messenger.getMessage()); + + // Check can cast to GroovyObject + GroovyObject goo = (GroovyObject) messenger; + } + + public void testWithTwoClassesDefinedInTheOneGroovyFile_WrongClassFirst() throws Exception { + try { + ApplicationContext ctx = new ClassPathXmlApplicationContext("twoClassesWrongOneFirst.xml", getClass()); + ctx.getBean("messenger", Messenger.class); + fail("Must have failed: two classes defined in GroovyScriptFactory source, non-Messenger class defined first."); + } + // just testing for failure here, hence catching Exception... + catch (Exception expected) { + } + } + + public void testCtorWithNullScriptSourceLocator() throws Exception { + try { + new GroovyScriptFactory(null); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithEmptyScriptSourceLocator() throws Exception { + try { + new GroovyScriptFactory(""); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithWhitespacedScriptSourceLocator() throws Exception { + try { + new GroovyScriptFactory("\n "); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testWithInlineScriptWithLeadingWhitespace() throws Exception { + try { + new ClassPathXmlApplicationContext("lwspBadGroovyContext.xml", getClass()); + fail("Must have thrown a BeanCreationException ('inline:' prefix was preceded by whitespace"); + } + catch (BeanCreationException expected) { + assertTrue(expected.contains(FileNotFoundException.class)); + } + } + + public void testGetScriptedObjectDoesNotChokeOnNullInterfacesBeingPassedIn() throws Exception { + MockControl mock = MockControl.createControl(ScriptSource.class); + ScriptSource scriptSource = (ScriptSource) mock.getMock(); + scriptSource.getScriptAsString(); + mock.setReturnValue("class Bar {}"); + scriptSource.suggestedClassName(); + mock.setReturnValue("someName"); + mock.replay(); + + GroovyScriptFactory factory = new GroovyScriptFactory("a script source locator (doesn't matter here)"); + Object scriptedObject = factory.getScriptedObject(scriptSource, null); + assertNotNull(scriptedObject); + mock.verify(); + } + + public void testGetScriptedObjectDoesChokeOnNullScriptSourceBeingPassedIn() throws Exception { + GroovyScriptFactory factory = new GroovyScriptFactory("a script source locator (doesn't matter here)"); + try { + factory.getScriptedObject(null, null); + fail("Must have thrown a NullPointerException as per contract ('null' ScriptSource supplied"); + } + catch (NullPointerException expected) { + } + } + + public void testResourceScriptFromTag() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + CallCounter countingAspect = (CallCounter) ctx.getBean("getMessageAspect"); + + assertTrue(AopUtils.isAopProxy(messenger)); + assertFalse(messenger instanceof Refreshable); + assertEquals(0, countingAspect.getCalls()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals(1, countingAspect.getCalls()); + + ctx.close(); + assertEquals(-200, countingAspect.getCalls()); + } + + public void testPrototypeScriptFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertNotSame(messenger, messenger2); + assertSame(messenger.getClass(), messenger2.getClass()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + } + + public void testInlineScriptFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass()); + Calculator calculator = (Calculator) ctx.getBean("calculator"); + assertNotNull(calculator); + assertFalse(calculator instanceof Refreshable); + } + + public void testRefreshableFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("refreshableMessenger")); + + Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger"); + CallCounter countingAspect = (CallCounter) ctx.getBean("getMessageAspect"); + + assertTrue(AopUtils.isAopProxy(messenger)); + assertTrue(messenger instanceof Refreshable); + assertEquals(0, countingAspect.getCalls()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals(1, countingAspect.getCalls()); + + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + + public void testAnonymousScriptDetected() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass()); + Map beans = ctx.getBeansOfType(Messenger.class); + assertEquals(4, beans.size()); + } + + /** + * Tests the SPR-2098 bug whereby no more than 1 property element could be + * passed to a scripted bean :( + */ + public void testCanPassInMoreThanOneProperty() { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-multiple-properties.xml", getClass()); + TestBean tb = (TestBean) ctx.getBean("testBean"); + + ContextScriptBean bean = (ContextScriptBean) ctx.getBean("bean"); + assertEquals("The first property ain't bein' injected.", "Sophie Marceau", bean.getName()); + assertEquals("The second property ain't bein' injected.", 31, bean.getAge()); + assertEquals(tb, bean.getTestBean()); + assertEquals(ctx, bean.getApplicationContext()); + + ContextScriptBean bean2 = (ContextScriptBean) ctx.getBean("bean2"); + assertEquals(tb, bean2.getTestBean()); + assertEquals(ctx, bean2.getApplicationContext()); + + try { + ctx.getBean("bean3"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + assertTrue(ex.contains(UnsatisfiedDependencyException.class)); + } + } + + public void testMetaClassWithBeans() { + testMetaClass("org/springframework/scripting/groovy/calculators.xml"); + } + + public void testMetaClassWithXsd() { + testMetaClass("org/springframework/scripting/groovy/calculators-with-xsd.xml"); + } + + private void testMetaClass(final String xmlFile) { + // expect the exception we threw in the custom metaclass to show it got invoked + AssertThrows at = new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + ApplicationContext ctx = + new ClassPathXmlApplicationContext(xmlFile); + Calculator calc = (Calculator) ctx.getBean("delegatingCalculator"); + calc.add(1, 2); + } + }; + at.runTest(); + assertEquals("Gotcha", at.getActualException().getMessage()); + } + + public void testFactoryBean() { + ApplicationContext context = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); + Object factory = context.getBean("&factory"); + assertTrue(factory instanceof FactoryBean); + Object result = context.getBean("factory"); + assertTrue(result instanceof String); + assertEquals("test", result); + } + + public void testRefreshableFactoryBean() { + ApplicationContext context = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); + Object factory = context.getBean("&refreshableFactory"); + assertTrue(factory instanceof FactoryBean); + Object result = context.getBean("refreshableFactory"); + assertTrue(result instanceof String); + assertEquals("test", result); + } + + + public static class TestCustomizer implements GroovyObjectCustomizer { + + public void customize(GroovyObject goo) { + DelegatingMetaClass dmc = new DelegatingMetaClass(goo.getMetaClass()) { + public Object invokeMethod(Object arg0, String mName, Object[] arg2) { + if (mName.indexOf("Missing") != -1) { + throw new IllegalStateException("Gotcha"); + } + else { + return super.invokeMethod(arg0, mName, arg2); + } + } + }; + dmc.initialize(); + goo.setMetaClass(dmc); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Messenger.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Messenger.groovy new file mode 100644 index 00000000000..6f411a695c5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/Messenger.groovy @@ -0,0 +1,8 @@ +package org.springframework.scripting.groovy; + +import org.springframework.scripting.ConfigurableMessenger + +class GroovyMessenger implements ConfigurableMessenger { + + def String message; +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/MessengerInstance.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/MessengerInstance.groovy new file mode 100644 index 00000000000..8f0a864329c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/MessengerInstance.groovy @@ -0,0 +1,14 @@ +package org.springframework.scripting.groovy; + +import org.springframework.scripting.Messenger + +class GroovyMessenger implements Messenger { + + GroovyMessenger() { + println "GroovyMessenger" + } + + def String message; +} + +return new GroovyMessenger(); diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/ScriptBean.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/ScriptBean.groovy new file mode 100644 index 00000000000..d1b82bfece9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/ScriptBean.groovy @@ -0,0 +1,23 @@ +import org.springframework.beans.TestBean +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.scripting.ContextScriptBean + +class GroovyScriptBean implements ContextScriptBean, ApplicationContextAware { + + private int age + + int getAge() { + return this.age + } + + void setAge(int age) { + this.age = age + } + + def String name + + def TestBean testBean; + + def ApplicationContext applicationContext +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/TestFactoryBean.groovy b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/TestFactoryBean.groovy new file mode 100644 index 00000000000..e86c13a6efb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/TestFactoryBean.groovy @@ -0,0 +1,17 @@ +import org.springframework.beans.factory.FactoryBean + +class TestFactoryBean implements FactoryBean { + + public boolean isSingleton() { + true + } + + public Class getObjectType() { + String.class + } + + public Object getObject() { + "test" + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators-with-xsd.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators-with-xsd.xml new file mode 100644 index 00000000000..8c90f9b2673 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators-with-xsd.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators.xml new file mode 100644 index 00000000000..b936acc96e9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/calculators.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-multiple-properties.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-multiple-properties.xml new file mode 100644 index 00000000000..58ce5e022aa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-multiple-properties.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-with-xsd.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-with-xsd.xml new file mode 100644 index 00000000000..1887788bd97 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovy-with-xsd.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + package org.springframework.scripting.groovy; +import org.springframework.scripting.Calculator +class GroovyCalculator implements Calculator { + int add(int x, int y) { + return x + y; + } +} + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyBrokenContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyBrokenContext.xml new file mode 100644 index 00000000000..e8e17e1b29d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyBrokenContext.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyContext.xml new file mode 100644 index 00000000000..a159b1791e7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyContext.xml @@ -0,0 +1,71 @@ + + + + + + + + inline: +package org.springframework.scripting.groovy; +import org.springframework.scripting.Calculator +class GroovyCalculator implements Calculator { + int add(int x, int y) { + return x + y; + } +} + + + + + + + + + + + + + + + + + + + + + + inline: +package org.springframework.scripting.groovy; +import org.springframework.scripting.Messenger +class GroovyMessenger implements Messenger { + def String message; +} +return new GroovyMessenger(); + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyRefreshableContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyRefreshableContext.xml new file mode 100644 index 00000000000..34c8b401d1a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/groovyRefreshableContext.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/lwspBadGroovyContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/lwspBadGroovyContext.xml new file mode 100644 index 00000000000..2d5692534de --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/lwspBadGroovyContext.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + inline: + + class Bingo { + + @Property String message; + } + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesCorrectOneFirst.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesCorrectOneFirst.xml new file mode 100644 index 00000000000..b32cc8294f7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesCorrectOneFirst.xml @@ -0,0 +1,28 @@ + + + + + + + + + inline: + package org.springframework.scripting.groovy; + + import org.springframework.scripting.Messenger; + + class GroovyMessenger implements Messenger { + + def String message; + } + + class Bingo { + + def String message; + } + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesWrongOneFirst.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesWrongOneFirst.xml new file mode 100644 index 00000000000..c3b4e80f166 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/groovy/twoClassesWrongOneFirst.xml @@ -0,0 +1,28 @@ + + + + + + + + + inline: + package org.springframework.scripting.groovy; + + import org.springframework.scripting.Messenger; + + class Bingo { + + @Property String message; + } + + class GroovyMessenger implements Messenger { + + @Property String message; + } + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java new file mode 100644 index 00000000000..d2ad09952dc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.jruby; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.CountingBeforeAdvice; +import org.springframework.aop.support.AopUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.scripting.Messenger; + +/** + * @author Rob Harrop + */ +public class AdvisedJRubyScriptFactoryTests extends TestCase { + + public void testAdviseWithProxyFactoryBean() throws Exception { + ApplicationContext context = + new ClassPathXmlApplicationContext("advisedByProxyFactoryBean.xml", getClass()); + + Messenger bean = (Messenger) context.getBean("messenger"); + assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean)); + assertTrue("Bean is not an Advised object", bean instanceof Advised); + + CountingBeforeAdvice advice = (CountingBeforeAdvice) context.getBean("advice"); + assertEquals(0, advice.getCalls()); + bean.getMessage(); + assertEquals(1, advice.getCalls()); + } + + public void testAdviseWithBeanNameAutoProxyCreator() throws Exception { + ApplicationContext context = + new ClassPathXmlApplicationContext("advisedByBeanNameAutoProxyCreator.xml", getClass()); + + Messenger bean = (Messenger) context.getBean("messenger"); + assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean)); + assertTrue("Bean is not an Advised object", bean instanceof Advised); + + CountingBeforeAdvice advice = (CountingBeforeAdvice) context.getBean("advice"); + assertEquals(0, advice.getCalls()); + bean.getMessage(); + assertEquals(1, advice.getCalls()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Broken.rb b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Broken.rb new file mode 100644 index 00000000000..0e16bb77584 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Broken.rb @@ -0,0 +1,4 @@ +In A Station Of The Metro + +the apparition of these faces in the crowd +petals on a wet black bough diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Calculator.rb b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Calculator.rb new file mode 100644 index 00000000000..d3785e03f74 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Calculator.rb @@ -0,0 +1,9 @@ +require 'java' + +class RubyCalculator + include org.springframework.scripting.Calculator + + def add(x, y) + x + y + end +end diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java new file mode 100644 index 00000000000..08bf6b6cc57 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java @@ -0,0 +1,286 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.jruby; + +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.target.dynamic.Refreshable; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.scripting.Calculator; +import org.springframework.scripting.ConfigurableMessenger; +import org.springframework.scripting.Messenger; +import org.springframework.scripting.ScriptCompilationException; +import org.springframework.scripting.TestBeanAwareMessenger; + +/** + * @author Rob Harrop + * @author Rick Evans + * @author Juergen Hoeller + */ +public class JRubyScriptFactoryTests extends TestCase { + + private static final String RUBY_SCRIPT_SOURCE_LOCATOR = + "inline:require 'java'\n" + + "class RubyBar\n" + + "end\n" + + "RubyBar.new"; + + + public void testStaticScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContext.xml", getClass()); + Calculator calc = (Calculator) ctx.getBean("calculator"); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertEquals(calc, calc); + assertEquals(messenger, messenger); + assertTrue(!messenger.equals(calc)); + assertTrue(messenger.hashCode() != calc.hashCode()); + assertTrue(!messenger.toString().equals(calc.toString())); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + } + + public void testNonStaticScript() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyRefreshableContext.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger)); + assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect.", desiredMessage, messenger.getMessage()); + + Refreshable refreshable = (Refreshable) messenger; + refreshable.refresh(); + + assertEquals("Message is incorrect after refresh.", desiredMessage, messenger.getMessage()); + assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount()); + } + + public void testScriptCompilationException() throws Exception { + try { + new ClassPathXmlApplicationContext("jrubyBrokenContext.xml", getClass()); + fail("Should throw exception for broken script file"); + } + catch (BeanCreationException ex) { + assertTrue(ex.contains(ScriptCompilationException.class)); + } + } + + public void testCtorWithNullScriptSourceLocator() throws Exception { + try { + new JRubyScriptFactory(null, new Class[]{Messenger.class}); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithEmptyScriptSourceLocator() throws Exception { + try { + new JRubyScriptFactory("", new Class[]{Messenger.class}); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithWhitespacedScriptSourceLocator() throws Exception { + try { + new JRubyScriptFactory("\n ", new Class[]{Messenger.class}); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithNullScriptInterfacesArray() throws Exception { + try { + new JRubyScriptFactory(RUBY_SCRIPT_SOURCE_LOCATOR, null); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorWithEmptyScriptInterfacesArray() throws Exception { + try { + new JRubyScriptFactory(RUBY_SCRIPT_SOURCE_LOCATOR, new Class[]{}); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testResourceScriptFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); + TestBean testBean = (TestBean) ctx.getBean("testBean"); + + Messenger messenger = (Messenger) ctx.getBean("messenger"); + assertEquals("Hello World!", messenger.getMessage()); + assertFalse(messenger instanceof Refreshable); + + TestBeanAwareMessenger messengerByType = (TestBeanAwareMessenger) ctx.getBean("messengerByType"); + assertEquals(testBean, messengerByType.getTestBean()); + + TestBeanAwareMessenger messengerByName = (TestBeanAwareMessenger) ctx.getBean("messengerByName"); + assertEquals(testBean, messengerByName.getTestBean()); + } + + public void testPrototypeScriptFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertNotSame(messenger, messenger2); + assertSame(messenger.getClass(), messenger2.getClass()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + } + + public void testInlineScriptFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); + Calculator calculator = (Calculator) ctx.getBean("calculator"); + assertNotNull(calculator); + assertFalse(calculator instanceof Refreshable); + } + + public void testRefreshableFromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger"); + assertEquals("Hello World!", messenger.getMessage()); + assertTrue("Messenger should be Refreshable", messenger instanceof Refreshable); + } + + public void testThatMultipleScriptInterfacesAreSupported() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("calculatingMessenger"); + assertEquals("Hello World!", messenger.getMessage()); + + // cool, now check that the Calculator interface is also exposed + Calculator calc = (Calculator) messenger; + assertEquals(0, calc.add(2, -2)); + } + + public void testWithComplexArg() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContext.xml", getClass()); + Printer printer = (Printer) ctx.getBean("printer"); + CountingPrintable printable = new CountingPrintable(); + printer.print(printable); + assertEquals(1, printable.count); + } + + public void testWithPrimitiveArgsInReturnTypeAndParameters() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContextForPrimitives.xml", getClass()); + PrimitiveAdder adder = (PrimitiveAdder) ctx.getBean("adder"); + assertEquals(2, adder.addInts(1, 1)); + assertEquals(4, adder.addShorts((short) 1, (short) 3)); + assertEquals(5, adder.addLongs(2L, 3L)); + assertEquals(5, new Float(adder.addFloats(2.0F, 3.1F)).intValue()); + assertEquals(5, new Double(adder.addDoubles(2.0, 3.1)).intValue()); + assertFalse(adder.resultIsPositive(-200, 1)); + assertEquals("ri", adder.concatenate('r', 'i')); + assertEquals('c', adder.echo('c')); + } + + public void testWithWrapperArgsInReturnTypeAndParameters() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContextForWrappers.xml", getClass()); + WrapperAdder adder = (WrapperAdder) ctx.getBean("adder"); + + assertEquals(new Integer(2), adder.addInts(new Integer(1), new Integer(1))); + assertEquals(Integer.class, adder.addInts(new Integer(1), new Integer(1)).getClass()); + assertEquals(new Short((short) 4), adder.addShorts(new Short((short) 1), new Short((short) 3))); + assertEquals(Short.class, adder.addShorts(new Short((short) 1), new Short((short) 3)).getClass()); + assertEquals(new Long(5L), adder.addLongs(new Long(2L), new Long(3L))); + assertEquals(Long.class, adder.addLongs(new Long(2L), new Long(3L)).getClass()); + assertEquals(5, adder.addFloats(new Float(2.0F), new Float(3.1F)).intValue()); + assertEquals(Float.class, adder.addFloats(new Float(2.0F), new Float(3.1F)).getClass()); + assertEquals(5, new Double(adder.addDoubles(new Double(2.0), new Double(3.1)).intValue()).intValue()); + assertEquals(Double.class, adder.addDoubles(new Double(2.0), new Double(3.1)).getClass()); + assertFalse(adder.resultIsPositive(new Integer(-200), new Integer(1)).booleanValue()); + assertEquals(Boolean.class, adder.resultIsPositive(new Integer(-200), new Integer(1)).getClass()); + assertEquals("ri", adder.concatenate(new Character('r'), new Character('i'))); + assertEquals(String.class, adder.concatenate(new Character('r'), new Character('i')).getClass()); + assertEquals(new Character('c'), adder.echo(new Character('c'))); + assertEquals(Character.class, adder.echo(new Character('c')).getClass()); + Integer[] numbers = new Integer[]{new Integer(1), new Integer(2), new Integer(3), new Integer(4), new Integer(5)}; + assertEquals("12345", adder.concatArrayOfIntegerWrappers(numbers)); + assertEquals(String.class, adder.concatArrayOfIntegerWrappers(numbers).getClass()); + + Short[] shorts = adder.populate(new Short((short) 1), new Short((short) 2)); + assertEquals(2, shorts.length); + assertNotNull(shorts[0]); + assertEquals(new Short((short) 1), shorts[0]); + assertNotNull(shorts[1]); + assertEquals(new Short((short) 2), shorts[1]); + + String[][] lol = adder.createListOfLists("1", "2", "3"); + assertNotNull(lol); + assertEquals(3, lol.length); + assertEquals("1", lol[0][0]); + assertEquals("2", lol[1][0]); + assertEquals("3", lol[2][0]); + + Map singleValueMap = adder.toMap("key", "value"); + assertNotNull(singleValueMap); + assertEquals(1, singleValueMap.size()); + assertEquals("key", singleValueMap.keySet().iterator().next()); + assertEquals("value", singleValueMap.values().iterator().next()); + + String[] expectedStrings = new String[]{"1", "2", "3"}; + Map map = adder.toMap("key", expectedStrings); + assertNotNull(map); + assertEquals(1, map.size()); + assertEquals("key", map.keySet().iterator().next()); + String[] strings = (String[]) map.values().iterator().next(); + for (int i = 0; i < expectedStrings.length; ++i) { + assertEquals(expectedStrings[i], strings[i]); + } + } + + public void testAOP() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-aop.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + assertEquals(new StringBuffer("Hello World!").reverse().toString(), messenger.getMessage()); + } + + + private static final class CountingPrintable implements Printable { + + public int count; + + public String getContent() { + this.count++; + return "Hello World!"; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Messenger.rb b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Messenger.rb new file mode 100644 index 00000000000..73268f03825 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Messenger.rb @@ -0,0 +1,21 @@ +require 'java' + +class RubyMessenger + include org.springframework.scripting.Messenger + + def setMessage(message) + @@message = message + end + + def getMessage + @@message + end + + def setTestBean(testBean) + @@testBean = testBean + end + + def getTestBean + @@testBean + end +end diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/PrimitiveAdder.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/PrimitiveAdder.java new file mode 100644 index 00000000000..1110206e149 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/PrimitiveAdder.java @@ -0,0 +1,25 @@ +package org.springframework.scripting.jruby; + +/** + * http://opensource.atlassian.com/projects/spring/browse/SPR-3026 + * + * @author Rick Evans + */ +public interface PrimitiveAdder { + + int addInts(int x, int y); + + short addShorts(short x, short y); + + long addLongs(long x, long y); + + float addFloats(float x, float y); + + double addDoubles(double x, double y); + + boolean resultIsPositive(int x, int y); + + String concatenate(char c, char d); + + char echo(char c); +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printable.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printable.java new file mode 100644 index 00000000000..6fb529871cd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printable.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.jruby; + +/** + * @author Rob Harrop + * @since 2.0.2 + */ +public interface Printable { + + String getContent(); +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.java new file mode 100644 index 00000000000..d4fb494bbbf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.jruby; + +/** + * @author Rob Harrop + * @since 2.0.2 + */ +public interface Printer { + + void print(Printable arg); +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.rb b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.rb new file mode 100644 index 00000000000..7f622462615 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/Printer.rb @@ -0,0 +1,9 @@ +require 'java' + +class RubyPrinter + include org.springframework.scripting.jruby.Printer + + def print(obj) + puts obj.getContent + end +end diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/WrapperAdder.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/WrapperAdder.java new file mode 100644 index 00000000000..2656c8a60e2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/WrapperAdder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.jruby; + +import java.util.Map; + +/** + * http://opensource.atlassian.com/projects/spring/browse/SPR-3038 + * + * @author Rick Evans + */ +public interface WrapperAdder { + + Integer addInts(Integer x, Integer y); + + Short addShorts(Short x, Short y); + + Long addLongs(Long x, Long y); + + Float addFloats(Float x, Float y); + + Double addDoubles(Double x, Double y); + + Boolean resultIsPositive(Integer x, Integer y); + + String concatenate(Character c, Character d); + + Character echo(Character c); + + String concatArrayOfIntegerWrappers(Integer[] numbers); + + Short[] populate(Short one, Short two); + + String[][] createListOfLists(String one, String second, String third); + + Map toMap(String key, Object value); + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByBeanNameAutoProxyCreator.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByBeanNameAutoProxyCreator.xml new file mode 100644 index 00000000000..39aab62b466 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByBeanNameAutoProxyCreator.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByProxyFactoryBean.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByProxyFactoryBean.xml new file mode 100644 index 00000000000..fffce34d77f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/advisedByProxyFactoryBean.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-aop.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-aop.xml new file mode 100644 index 00000000000..6fa5b5b64f5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-aop.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-with-xsd.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-with-xsd.xml new file mode 100644 index 00000000000..13f5d3c9aa0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jruby-with-xsd.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + +require 'java' + +class RubyCalculator + include org.springframework.scripting.Calculator + + def add(x, y) + x + y + end +end + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyBrokenContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyBrokenContext.xml new file mode 100644 index 00000000000..947cf0d8215 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyBrokenContext.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContext.xml new file mode 100644 index 00000000000..11f4fb56f0a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContext.xml @@ -0,0 +1,36 @@ + + + + + + + + + + inline: +require 'java' + +class RubyCalculator + include org.springframework.scripting.Calculator + + def add(x, y) + x + y + end +end + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForPrimitives.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForPrimitives.xml new file mode 100644 index 00000000000..06b4e73ab58 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForPrimitives.xml @@ -0,0 +1,53 @@ + + + + + + + + + + 0 + end + + def concatenate(c, d) + return ("" << c) << d; + end + + def echo(c) + c + end + +end + ]]> + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForWrappers.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForWrappers.xml new file mode 100644 index 00000000000..f4ed0d736da --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyContextForWrappers.xml @@ -0,0 +1,73 @@ + + + + + + + + + + 0 + end + + def concatenate(c, d) + return ("" << c) << d; + end + + def echo(c) + c + end + + def concatArrayOfIntegerWrappers(numbers) + buffer = "" + numbers.each do |number| + buffer << number.to_s + end + return buffer + end + + def populate(x, y) + [x, y] + end + + def createListOfLists(x, y, z) + [[x], [y], [z]] + end + + def toMap(key, value) + {key => value} + end + +end + ]]> + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyRefreshableContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyRefreshableContext.xml new file mode 100644 index 00000000000..2b9c694a383 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/jruby/jrubyRefreshableContext.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/RefreshableScriptTargetSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/RefreshableScriptTargetSourceTests.java new file mode 100644 index 00000000000..dd39e655765 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/RefreshableScriptTargetSourceTests.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.support; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.factory.BeanFactory; + +/** + * @author Rick Evans + */ +public class RefreshableScriptTargetSourceTests extends TestCase { + + public void testCreateWithNullScriptSource() throws Exception { + MockControl mockFactory = MockControl.createNiceControl(BeanFactory.class); + mockFactory.replay(); + try { + new RefreshableScriptTargetSource((BeanFactory) mockFactory.getMock(), "a.bean", null, null, false); + fail("Must have failed when passed a null ScriptSource."); + } + catch (IllegalArgumentException expected) { + } + mockFactory.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ResourceScriptSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ResourceScriptSourceTests.java new file mode 100644 index 00000000000..94e8c606e8f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ResourceScriptSourceTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.support; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ResourceScriptSourceTests extends TestCase { + + public void testCtorWithNullResource() throws Exception { + try { + new ResourceScriptSource(null); + fail("Must have thrown exception by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testDoesNotPropagateFatalExceptionOnResourceThatCannotBeResolvedToAFile() throws Exception { + MockControl mock = MockControl.createControl(Resource.class); + Resource resource = (Resource) mock.getMock(); + resource.lastModified(); + mock.setThrowable(new IOException()); + mock.replay(); + + ResourceScriptSource scriptSource = new ResourceScriptSource(resource); + long lastModified = scriptSource.retrieveLastModifiedTime(); + assertEquals(0, lastModified); + mock.verify(); + } + + public void testBeginsInModifiedState() throws Exception { + MockControl mock = MockControl.createControl(Resource.class); + Resource resource = (Resource) mock.getMock(); + mock.replay(); + + ResourceScriptSource scriptSource = new ResourceScriptSource(resource); + assertTrue(scriptSource.isModified()); + mock.verify(); + } + + public void testLastModifiedWorksWithResourceThatDoesNotSupportFileBasedReading() throws Exception { + MockControl mock = MockControl.createControl(Resource.class); + Resource resource = (Resource) mock.getMock(); + // underlying File is asked for so that the last modified time can be checked... + resource.lastModified(); + mock.setReturnValue(100, 2); + // does not support File-based reading; delegates to InputStream-style reading... + resource.getFile(); + mock.setThrowable(new FileNotFoundException()); + resource.getInputStream(); + mock.setReturnValue(new ByteArrayInputStream(new byte[0])); + // And then mock the file changing; i.e. the File says it has been modified + resource.lastModified(); + mock.setReturnValue(200); + mock.replay(); + + ResourceScriptSource scriptSource = new ResourceScriptSource(resource); + assertTrue("ResourceScriptSource must start off in the 'isModified' state (it obviously isn't).", scriptSource.isModified()); + scriptSource.getScriptAsString(); + assertFalse("ResourceScriptSource must not report back as being modified if the underlying File resource is not reporting a changed lastModified time.", scriptSource.isModified()); + // Must now report back as having been modified + assertTrue("ResourceScriptSource must report back as being modified if the underlying File resource is reporting a changed lastModified time.", scriptSource.isModified()); + mock.verify(); + } + + public void testLastModifiedWorksWithResourceThatDoesNotSupportFileBasedAccessAtAll() throws Exception { + Resource resource = new ByteArrayResource(new byte[0]); + ResourceScriptSource scriptSource = new ResourceScriptSource(resource); + assertTrue("ResourceScriptSource must start off in the 'isModified' state (it obviously isn't).", scriptSource.isModified()); + scriptSource.getScriptAsString(); + assertFalse("ResourceScriptSource must not report back as being modified if the underlying File resource is not reporting a changed lastModified time.", scriptSource.isModified()); + // Must now continue to report back as not having been modified 'cos the Resource does not support access as a File (and so the lastModified date cannot be determined). + assertFalse("ResourceScriptSource must not report back as being modified if the underlying File resource is not reporting a changed lastModified time.", scriptSource.isModified()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ScriptFactoryPostProcessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ScriptFactoryPostProcessorTests.java new file mode 100644 index 00000000000..8aebff6f7b7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/ScriptFactoryPostProcessorTests.java @@ -0,0 +1,277 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.support; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.scripting.Messenger; +import org.springframework.scripting.ScriptCompilationException; +import org.springframework.scripting.groovy.GroovyScriptFactory; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ScriptFactoryPostProcessorTests extends TestCase { + + private static final String MESSAGE_TEXT = "Bingo"; + + private static final String MESSENGER_BEAN_NAME = "messenger"; + + private static final String PROCESSOR_BEAN_NAME = "processor"; + + private static final String CHANGED_SCRIPT = "package org.springframework.scripting.groovy\n" + + "import org.springframework.scripting.Messenger\n" + + "class GroovyMessenger implements Messenger {\n" + + " private String message = \"Bingo\"\n" + + " public String getMessage() {\n" + + // quote the returned message (this is the change)... + " return \"'\" + this.message + \"'\"\n" + + " }\n" + + " public void setMessage(String message) {\n" + + " this.message = message\n" + + " }\n" + + "}"; + + private static final String EXPECTED_CHANGED_MESSAGE_TEXT = "'" + MESSAGE_TEXT + "'"; + + private static final int DEFAULT_SECONDS_TO_PAUSE = 1; + + private static final String DELEGATING_SCRIPT = "inline:package org.springframework.scripting;\n" + + "class DelegatingMessenger implements Messenger {\n" + + " private Messenger wrappedMessenger;\n" + + " public String getMessage() {\n" + + " return this.wrappedMessenger.getMessage()\n" + + " }\n" + + " public void setMessenger(Messenger wrappedMessenger) {\n" + + " this.wrappedMessenger = wrappedMessenger\n" + + " }\n" + + "}"; + + + public void testDoesNothingWhenPostProcessingNonScriptFactoryTypeBeforeInstantiation() throws Exception { + assertNull(new ScriptFactoryPostProcessor().postProcessBeforeInstantiation(getClass(), "a.bean")); + } + + public void testThrowsExceptionIfGivenNonAbstractBeanFactoryImplementation() throws Exception { + MockControl mock = MockControl.createControl(BeanFactory.class); + mock.replay(); + try { + new ScriptFactoryPostProcessor().setBeanFactory((BeanFactory) mock.getMock()); + fail("Must have thrown exception by this point."); + } + catch (IllegalStateException expected) { + } + mock.verify(); + } + + public void testChangeScriptWithRefreshableBeanFunctionality() throws Exception { + BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(true); + BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean(); + + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition); + ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition); + ctx.refresh(); + + Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + assertEquals(MESSAGE_TEXT, messenger.getMessage()); + // cool; now let's change the script and check the refresh behaviour... + pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE); + StaticScriptSource source = getScriptSource(ctx); + source.setScript(CHANGED_SCRIPT); + Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + // the updated script surrounds the message in quotes before returning... + assertEquals(EXPECTED_CHANGED_MESSAGE_TEXT, refreshedMessenger.getMessage()); + } + + public void testChangeScriptWithNoRefreshableBeanFunctionality() throws Exception { + BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(false); + BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean(); + + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition); + ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition); + ctx.refresh(); + + Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + assertEquals(MESSAGE_TEXT, messenger.getMessage()); + // cool; now let's change the script and check the refresh behaviour... + pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE); + StaticScriptSource source = getScriptSource(ctx); + source.setScript(CHANGED_SCRIPT); + Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + assertEquals("Script seems to have been refreshed (must not be as no refreshCheckDelay set on ScriptFactoryPostProcessor)", + MESSAGE_TEXT, refreshedMessenger.getMessage()); + } + + public void testRefreshedScriptReferencePropagatesToCollaborators() throws Exception { + BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(true); + BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean(); + BeanDefinitionBuilder collaboratorBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultMessengerService.class); + collaboratorBuilder.addPropertyReference(MESSENGER_BEAN_NAME, MESSENGER_BEAN_NAME); + + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition); + ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition); + final String collaboratorBeanName = "collaborator"; + ctx.registerBeanDefinition(collaboratorBeanName, collaboratorBuilder.getBeanDefinition()); + ctx.refresh(); + + Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + assertEquals(MESSAGE_TEXT, messenger.getMessage()); + // cool; now let's change the script and check the refresh behaviour... + pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE); + StaticScriptSource source = getScriptSource(ctx); + source.setScript(CHANGED_SCRIPT); + Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + // the updated script surrounds the message in quotes before returning... + assertEquals(EXPECTED_CHANGED_MESSAGE_TEXT, refreshedMessenger.getMessage()); + // ok, is this change reflected in the reference that the collaborator has? + DefaultMessengerService collaborator = (DefaultMessengerService) ctx.getBean(collaboratorBeanName); + assertEquals(EXPECTED_CHANGED_MESSAGE_TEXT, collaborator.getMessage()); + } + + public void testReferencesAcrossAContainerHierarchy() throws Exception { + GenericApplicationContext businessContext = new GenericApplicationContext(); + businessContext.registerBeanDefinition("messenger", BeanDefinitionBuilder.rootBeanDefinition(StubMessenger.class).getBeanDefinition()); + businessContext.refresh(); + + BeanDefinitionBuilder scriptedBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class); + scriptedBeanBuilder.addConstructorArgValue(DELEGATING_SCRIPT); + scriptedBeanBuilder.addPropertyReference("messenger", "messenger"); + + GenericApplicationContext presentationCtx = new GenericApplicationContext(businessContext); + presentationCtx.registerBeanDefinition("needsMessenger", scriptedBeanBuilder.getBeanDefinition()); + presentationCtx.registerBeanDefinition("scriptProcessor", createScriptFactoryPostProcessor(true)); + presentationCtx.refresh(); + } + + public void testScriptHavingAReferenceToAnotherBean() throws Exception { + // just tests that the (singleton) script-backed bean is able to be instantiated with references to its collaborators + new ClassPathXmlApplicationContext("org/springframework/scripting/support/groovyReferences.xml"); + } + + public void testForRefreshedScriptHavingErrorPickedUpOnFirstCall() throws Exception { + BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(true); + BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean(); + BeanDefinitionBuilder collaboratorBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultMessengerService.class); + collaboratorBuilder.addPropertyReference(MESSENGER_BEAN_NAME, MESSENGER_BEAN_NAME); + + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition); + ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition); + final String collaboratorBeanName = "collaborator"; + ctx.registerBeanDefinition(collaboratorBeanName, collaboratorBuilder.getBeanDefinition()); + ctx.refresh(); + + Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + assertEquals(MESSAGE_TEXT, messenger.getMessage()); + // cool; now let's change the script and check the refresh behaviour... + pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE); + StaticScriptSource source = getScriptSource(ctx); + // needs The Sundays compiler; must NOT throw any exception here... + source.setScript("I keep hoping you are the same as me, and I'll send you letters and come to your house for tea"); + Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME); + try { + refreshedMessenger.getMessage(); + fail("Must have thrown an Exception (invalid script)"); + } + catch (FatalBeanException expected) { + assertTrue(expected.contains(ScriptCompilationException.class)); + } + } + + public void testPrototypeScriptedBean() throws Exception { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.registerBeanDefinition("messenger", BeanDefinitionBuilder.rootBeanDefinition(StubMessenger.class).getBeanDefinition()); + + BeanDefinitionBuilder scriptedBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class); + scriptedBeanBuilder.setSingleton(false); + scriptedBeanBuilder.addConstructorArgValue(DELEGATING_SCRIPT); + scriptedBeanBuilder.addPropertyReference("messenger", "messenger"); + + final String BEAN_WITH_DEPENDENCY_NAME = "needsMessenger"; + ctx.registerBeanDefinition(BEAN_WITH_DEPENDENCY_NAME, scriptedBeanBuilder.getBeanDefinition()); + ctx.registerBeanDefinition("scriptProcessor", createScriptFactoryPostProcessor(true)); + ctx.refresh(); + + Messenger messenger1 = (Messenger) ctx.getBean(BEAN_WITH_DEPENDENCY_NAME); + Messenger messenger2 = (Messenger) ctx.getBean(BEAN_WITH_DEPENDENCY_NAME); + assertNotSame(messenger1, messenger2); + } + + private static StaticScriptSource getScriptSource(GenericApplicationContext ctx) throws Exception { + ScriptFactoryPostProcessor processor = (ScriptFactoryPostProcessor) ctx.getBean(PROCESSOR_BEAN_NAME); + BeanDefinition bd = processor.scriptBeanFactory.getBeanDefinition("scriptedObject.messenger"); + return (StaticScriptSource) bd.getConstructorArgumentValues().getIndexedArgumentValue(0, StaticScriptSource.class).getValue(); + } + + private static BeanDefinition createScriptFactoryPostProcessor(boolean isRefreshable) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ScriptFactoryPostProcessor.class); + if (isRefreshable) { + builder.addPropertyValue("defaultRefreshCheckDelay", new Long(1)); + } + return builder.getBeanDefinition(); + } + + private static BeanDefinition createScriptedGroovyBean() { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class); + builder.addConstructorArgValue("inline:package org.springframework.scripting;\n" + + "class GroovyMessenger implements Messenger {\n" + + " private String message = \"Bingo\"\n" + + " public String getMessage() {\n" + + " return this.message\n" + + " }\n" + + " public void setMessage(String message) {\n" + + " this.message = message\n" + + " }\n" + + "}"); + builder.addPropertyValue("message", MESSAGE_TEXT); + return builder.getBeanDefinition(); + } + + private static void pauseToLetRefreshDelayKickIn(int secondsToPause) { + try { + Thread.sleep(secondsToPause * 1000); + } + catch (InterruptedException ignored) { + } + } + + + public static class DefaultMessengerService { + + private Messenger messenger; + + public void setMessenger(Messenger messenger) { + this.messenger = messenger; + } + + public String getMessage() { + return this.messenger.getMessage(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StaticScriptSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StaticScriptSourceTests.java new file mode 100644 index 00000000000..c9e6babddc6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StaticScriptSourceTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.support; + +import junit.framework.TestCase; + +/** + * Unit tests for the StaticScriptSource class. + * + * @author Rick Evans + */ +public final class StaticScriptSourceTests extends TestCase { + + private static final String SCRIPT_TEXT = "print($hello) if $true;"; + + + public void testCreateWithNullScript() throws Exception { + try { + new StaticScriptSource(null); + fail("Must have failed when passed a null script string."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCreateWithEmptyScript() throws Exception { + try { + new StaticScriptSource(""); + fail("Must have failed when passed an empty script string."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCreateWithWhitespaceOnlyScript() throws Exception { + try { + new StaticScriptSource(" \n\n\t \t\n"); + fail("Must have failed when passed a whitespace-only script string."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testIsModifiedIsTrueByDefault() throws Exception { + StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT); + assertTrue("Script must be flagged as 'modified' when first created.", source.isModified()); + } + + public void testGettingScriptTogglesIsModified() throws Exception { + StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT); + source.getScriptAsString(); + assertFalse("Script must be flagged as 'not modified' after script is read.", source.isModified()); + } + + public void testGettingScriptViaToStringDoesNotToggleIsModified() throws Exception { + StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT); + boolean isModifiedState = source.isModified(); + source.toString(); + assertEquals("Script's 'modified' flag must not change after script is read via toString().", isModifiedState, source.isModified()); + } + + public void testIsModifiedToggledWhenDifferentScriptIsSet() throws Exception { + StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT); + source.setScript("use warnings;"); + assertTrue("Script must be flagged as 'modified' when different script is passed in.", source.isModified()); + } + + public void testIsModifiedNotToggledWhenSameScriptIsSet() throws Exception { + StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT); + source.setScript(SCRIPT_TEXT); + assertFalse("Script must not be flagged as 'modified' when same script is passed in.", source.isModified()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StubMessenger.java b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StubMessenger.java new file mode 100644 index 00000000000..3a4ffb70436 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/StubMessenger.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scripting.support; + +import org.springframework.scripting.ConfigurableMessenger; + +/** + * @author Rick Evans + */ +public final class StubMessenger implements ConfigurableMessenger { + + private String message = "I used to be smart... now I'm just stupid."; + + public void setMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/groovyReferences.xml b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/groovyReferences.xml new file mode 100644 index 00000000000..20bc7ee8c9b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/scripting/support/groovyReferences.xml @@ -0,0 +1,32 @@ + + + + + + + + + + inline:package org.springframework.scripting; + +import org.springframework.scripting.Messenger + +class DelegatingMessenger implements Messenger { + + private Messenger wrappedMessenger; + + public String getMessage() { + this.wrappedMessenger.getMessage(); + } + + public void setMessenger(Messenger wrappedMessenger) { + this.wrappedMessenger = wrappedMessenger; + } +} + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/AbstractSpr3350SingleSpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/AbstractSpr3350SingleSpringContextTests.java new file mode 100644 index 00000000000..1bc157cba60 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/AbstractSpr3350SingleSpringContextTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test; + +import org.springframework.beans.Pet; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ApplicationContext; + +/** + * Abstract JUnit 3.8 based unit test which verifies new functionality requested + * in SPR-3350. + * + * @author Sam Brannen + * @since 2.5 + */ +public abstract class AbstractSpr3350SingleSpringContextTests extends AbstractDependencyInjectionSpringContextTests { + + private Pet cat; + + + public AbstractSpr3350SingleSpringContextTests() { + super(); + } + + public AbstractSpr3350SingleSpringContextTests(String name) { + super(name); + } + + public final void setCat(final Pet cat) { + this.cat = cat; + } + + /** + * Forcing concrete subclasses to provide a config path appropriate to the + * configured + * {@link #createBeanDefinitionReader(org.springframework.context.support.GenericApplicationContext) BeanDefinitionReader}. + * + * @see org.springframework.test.AbstractSingleSpringContextTests#getConfigPath() + */ + protected abstract String getConfigPath(); + + /** + *

+ * Test which addresses the following issue raised in SPR-3350: + *

+ *

+ * {@link AbstractSingleSpringContextTests} always uses an + * {@link XmlBeanDefinitionReader} internally when creating the + * {@link ApplicationContext} inside + * {@link #createApplicationContext(String[])}. It would be nice to have + * the bean definition reader creation in a separate method so that + * subclasses can choose that individually without having to copy-n-paste + * code from createApplicationContext() to do the context creation and + * refresh. Consider JavaConfig where an Annotation based reader can be + * plugged in. + *

+ */ + public final void testApplicationContextNotAutoCreated() { + assertNotNull("The cat field should have been autowired.", this.cat); + assertEquals("Garfield", this.cat.getName()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests-context.properties b/org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests-context.properties new file mode 100644 index 00000000000..307a4e93df2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests-context.properties @@ -0,0 +1,2 @@ +cat.(class)=org.springframework.beans.Pet +cat.$0=Garfield diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests.java new file mode 100644 index 00000000000..d0da3c8e5ad --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/PropertiesBasedSpr3350SingleSpringContextTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test; + +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.support.GenericApplicationContext; + +/** + * Concrete implementation of {@link AbstractSpr3350SingleSpringContextTests} + * which configures a {@link PropertiesBeanDefinitionReader} instead of the + * default {@link XmlBeanDefinitionReader}. + * + * @author Sam Brannen + * @since 2.5 + */ +public class PropertiesBasedSpr3350SingleSpringContextTests extends AbstractSpr3350SingleSpringContextTests { + + public PropertiesBasedSpr3350SingleSpringContextTests() { + super(); + } + + public PropertiesBasedSpr3350SingleSpringContextTests(String name) { + super(name); + } + + /** + * Creates a new {@link PropertiesBeanDefinitionReader}. + * + * @see org.springframework.test.AbstractSingleSpringContextTests#createBeanDefinitionReader(org.springframework.context.support.GenericApplicationContext) + */ + protected final BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) { + return new PropertiesBeanDefinitionReader(context); + } + + /** + * Returns + * "PropertiesBasedSpr3350SingleSpringContextTests-context.properties". + */ + protected final String getConfigPath() { + return "PropertiesBasedSpr3350SingleSpringContextTests-context.properties"; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264DependencyInjectionSpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264DependencyInjectionSpringContextTests.java new file mode 100644 index 00000000000..7cf3e27b328 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264DependencyInjectionSpringContextTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test; + +/** + * JUnit 3.8 based unit test which verifies new functionality requested in SPR-3264. + * + * @author Sam Brannen + * @since 2.5 + * @see Spr3264SingleSpringContextTests + */ +public class Spr3264DependencyInjectionSpringContextTests extends AbstractDependencyInjectionSpringContextTests { + + public Spr3264DependencyInjectionSpringContextTests() { + super(); + } + + public Spr3264DependencyInjectionSpringContextTests(String name) { + super(name); + } + + /** + *

+ * Test which addresses the following issue raised in SPR-3264: + *

+ *

+ * AbstractDependencyInjectionSpringContextTests will try to apply + * auto-injection; this can be disabled but it has to be done manually + * inside the onSetUp... + *

+ */ + public void testInjectDependenciesThrowsIllegalStateException() { + + // Re-assert issues covered by Spr3264SingleSpringContextTests as a + // safety net. + assertNull("The ApplicationContext should NOT be automatically created if no 'locations' are defined.", + this.applicationContext); + assertEquals("Verifying the ApplicationContext load count.", 0, super.getLoadCount()); + + // Assert changes to AbstractDependencyInjectionSpringContextTests: + new AssertThrows(IllegalStateException.class) { + + public void test() throws Exception { + Spr3264DependencyInjectionSpringContextTests.super.injectDependencies(); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264SingleSpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264SingleSpringContextTests.java new file mode 100644 index 00000000000..d6286ecd1cb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/Spr3264SingleSpringContextTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test; + +/** + * JUnit 3.8 based unit test which verifies new functionality requested in SPR-3264. + * + * @author Sam Brannen + * @since 2.5 + * @see Spr3264DependencyInjectionSpringContextTests + */ +public class Spr3264SingleSpringContextTests extends AbstractSingleSpringContextTests { + + public Spr3264SingleSpringContextTests() { + super(); + } + + public Spr3264SingleSpringContextTests(String name) { + super(name); + } + + /** + *

+ * Test which addresses the following issue raised in SPR-3264: + *

+ *

+ * AbstractSingleSpringContextTests always expects an application context to + * be created even if no files/locations are specified which can lead to NPE + * problems or force an appCtx to be instantiated even if not needed. + *

+ */ + public void testApplicationContextNotAutoCreated() { + assertNull("The ApplicationContext should NOT be automatically created if no 'locations' are defined.", + super.applicationContext); + assertEquals("Verifying the ApplicationContext load count.", 0, super.getLoadCount()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests-context.xml b/org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests-context.xml new file mode 100644 index 00000000000..72360454848 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests-context.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests.java new file mode 100644 index 00000000000..8143c775115 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/XmlBasedSpr3350SingleSpringContextTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test; + +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; + +/** + * Concrete implementation of {@link AbstractSpr3350SingleSpringContextTests} + * which is based on the default {@link XmlBeanDefinitionReader}. + * + * @author Sam Brannen + * @since 2.5 + */ +public class XmlBasedSpr3350SingleSpringContextTests extends AbstractSpr3350SingleSpringContextTests { + + public XmlBasedSpr3350SingleSpringContextTests() { + super(); + } + + public XmlBasedSpr3350SingleSpringContextTests(String name) { + super(name); + } + + /** + * Returns "XmlBasedSpr3350SingleSpringContextTests-context.xml". + */ + protected final String getConfigPath() { + return "XmlBasedSpr3350SingleSpringContextTests-context.xml"; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/jdbc/JdbcTestUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/jdbc/JdbcTestUtilsTests.java new file mode 100644 index 00000000000..35346bc253e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/jdbc/JdbcTestUtilsTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.jdbc; + +import junit.framework.TestCase; + +import java.util.List; +import java.util.ArrayList; + +/** + * Unit tests for {@link JdbcTestUtils}. + * + * @author Thomas Risberg + * @since 2.5.4 + */ +public class JdbcTestUtilsTests extends TestCase { + + public void testContainsDelimiters() { + assertTrue("test with ';' is wrong", !JdbcTestUtils.containsSqlScriptDelimiters("select 1\n select ';'", ';')); + assertTrue("test with delimiter ; is wrong", JdbcTestUtils.containsSqlScriptDelimiters("select 1; select 2", ';')); + assertTrue("test with '\\n' is wrong", !JdbcTestUtils.containsSqlScriptDelimiters("select 1; select '\\n\n';", '\n')); + assertTrue("test with delimiter \\n is wrong", JdbcTestUtils.containsSqlScriptDelimiters("select 1\n select 2", '\n')); + } + + public void testSplitSqlScriptDelimitedWithSemicolon() { + String statement1 = "insert into customer (id, name) \n" + + "values (1, 'Rod ; Johnson'), (2, 'Adrian \n Collier')"; + String statement2 = "insert into orders(id, order_date, customer_id) \n" + + "values (1, '2008-01-02', 2)"; + String statement3 = "insert into orders(id, order_date, customer_id) " + + "values (1, '2008-01-02', 2)"; + char delim = ';'; + String script = statement1 + delim + statement2 + delim + statement3; + List statements = new ArrayList(); + JdbcTestUtils.splitSqlScript(script, delim, statements); + assertEquals("wrong number of statements", 3, statements.size()); + assertEquals("statement 1 not split correctly", statement1, statements.get(0)); + assertEquals("statement 2 not split correctly", statement2, statements.get(1)); + assertEquals("statement 3 not split correctly", statement3, statements.get(2)); + + } + + public void testSplitSqlScriptDelimitedWithNewLine() { + String statement1 = "insert into customer (id, name) " + + "values (1, 'Rod ; Johnson'), (2, 'Adrian ; Collier')"; + String statement2 = "insert into orders(id, order_date, customer_id) " + + "values (1, '2008-01-02', 2)"; + String statement3 = "insert into orders(id, order_date, customer_id) " + + "values (1, '2008-01-02', 2)"; + char delim = '\n'; + String script = statement1 + delim + statement2 + delim + statement3; + List statements = new ArrayList(); + JdbcTestUtils.splitSqlScript(script, delim, statements); + assertEquals("wrong number of statements", 3, statements.size()); + assertEquals("statement 1 not split correctly", statement1, statements.get(0)); + assertEquals("statement 2 not split correctly", statement2, statements.get(1)); + assertEquals("statement 3 not split correctly", statement3, statements.get(2)); + + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/transaction/TransactionTestUtils.java b/org.springframework.testsuite/src/test/java/org/springframework/test/transaction/TransactionTestUtils.java new file mode 100644 index 00000000000..fb7bd3bd626 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/transaction/TransactionTestUtils.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.transaction; + +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * Collection of JDK 1.4+ utilities for tests involving transactions. Intended + * for internal use within the Spring testing suite. + * + *

All assert*() methods throw {@link AssertionError}s. + * + * @author Sam Brannen + * @since 2.5 + */ +public abstract class TransactionTestUtils { + + /** + * Convenience method for determining if a transaction is active for the + * current {@link Thread}. + * @return true if a transaction is currently active + */ + public static boolean inTransaction() { + return TransactionSynchronizationManager.isActualTransactionActive(); + } + + /** + * Asserts whether or not a transaction is active for the current + * {@link Thread}. + * @param transactionExpected whether or not a transaction is expected + * @throws AssertionError if the supplied assertion fails + * @see #inTransaction() + */ + public static void assertInTransaction(boolean transactionExpected) { + if (transactionExpected) { + assertCondition(inTransaction(), "The current thread should be associated with a transaction."); + } + else { + assertCondition(!inTransaction(), "The current thread should not be associated with a transaction"); + } + } + + /** + * Fails by throwing an AssertionError with the supplied + * message. + * @param message the exception message to use + * @see #assertCondition(boolean,String) + */ + private static void fail(String message) throws AssertionError { + throw new AssertionError(message); + } + + /** + * Assert the provided boolean condition, throwing + * AssertionError with the supplied message if + * the test result is false. + * @param condition a boolean expression + * @param message the exception message to use if the assertion fails + * @throws AssertionError if condition is false + * @see #fail(String) + */ + private static void assertCondition(boolean condition, String message) throws AssertionError { + if (!condition) { + fail(message); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java new file mode 100644 index 00000000000..41b98ce8df7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java @@ -0,0 +1,194 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.util; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; +import org.springframework.test.util.subpackage.Person; + +/** + * JUnit 3.8 based unit tests for {@link ReflectionTestUtils}. + * + * @author Sam Brannen + * @author Juergen Hoeller + */ +public class ReflectionTestUtilsTests extends TestCase { + + protected static final Float PI = new Float((float) 22 / 7); + + + public void testSetField() throws Exception { + final Person person = new Person(); + + // Standard + + ReflectionTestUtils.setField(person, "id", new Long(99), long.class); + ReflectionTestUtils.setField(person, "name", "Tom"); + ReflectionTestUtils.setField(person, "age", new Integer(42)); + ReflectionTestUtils.setField(person, "eyeColor", "blue", String.class); + ReflectionTestUtils.setField(person, "likesPets", Boolean.TRUE); + ReflectionTestUtils.setField(person, "favoriteNumber", PI, Number.class); + + assertEquals("Verifying that the person's ID (private field in a superclass) was set.", 99, person.getId()); + assertEquals("Verifying that the person's name (protected field) was set.", "Tom", person.getName()); + assertEquals("Verifying that the person's age (private field) was set.", 42, person.getAge()); + assertEquals("Verifying that the person's eye color (package private field) was set.", "blue", + person.getEyeColor()); + assertEquals("Verifying that the person's 'likes pets' flag (package private boolean field) was set.", true, + person.likesPets()); + assertEquals("Verifying that the person's 'favorite number' (package field) was set.", PI, + person.getFavoriteNumber()); + + assertEquals(new Long(99), ReflectionTestUtils.getField(person, "id")); + assertEquals("Tom", ReflectionTestUtils.getField(person, "name")); + assertEquals(new Integer(42), ReflectionTestUtils.getField(person, "age")); + assertEquals("blue", ReflectionTestUtils.getField(person, "eyeColor")); + assertEquals(Boolean.TRUE, ReflectionTestUtils.getField(person, "likesPets")); + assertEquals(PI, ReflectionTestUtils.getField(person, "favoriteNumber")); + + // Null - non-primitives + + ReflectionTestUtils.setField(person, "name", null, String.class); + ReflectionTestUtils.setField(person, "eyeColor", null, String.class); + ReflectionTestUtils.setField(person, "favoriteNumber", null, Number.class); + + assertNull("Verifying that the person's name (protected field) was set.", person.getName()); + assertNull("Verifying that the person's eye color (package private field) was set.", person.getEyeColor()); + assertNull("Verifying that the person's 'favorite number' (package field) was set.", person.getFavoriteNumber()); + + // Null - primitives + + new AssertThrows(IllegalArgumentException.class, + "Calling setField() with NULL for a primitive type should throw an IllegalArgumentException.") { + + public void test() throws Exception { + ReflectionTestUtils.setField(person, "id", null, long.class); + } + }.runTest(); + + new AssertThrows(IllegalArgumentException.class, + "Calling setField() with NULL for a primitive type should throw an IllegalArgumentException.") { + + public void test() throws Exception { + ReflectionTestUtils.setField(person, "age", null, int.class); + } + }.runTest(); + + new AssertThrows(IllegalArgumentException.class, + "Calling setField() with NULL for a primitive type should throw an IllegalArgumentException.") { + + public void test() throws Exception { + ReflectionTestUtils.setField(person, "likesPets", null, boolean.class); + } + }.runTest(); + } + + public void testInvokeSetterMethod() throws Exception { + final Person person = new Person(); + + // Standard - properties + + ReflectionTestUtils.invokeSetterMethod(person, "id", new Long(99), long.class); + ReflectionTestUtils.invokeSetterMethod(person, "name", "Tom"); + ReflectionTestUtils.invokeSetterMethod(person, "age", new Integer(42)); + ReflectionTestUtils.invokeSetterMethod(person, "eyeColor", "blue", String.class); + ReflectionTestUtils.invokeSetterMethod(person, "likesPets", Boolean.TRUE); + ReflectionTestUtils.invokeSetterMethod(person, "favoriteNumber", PI, Number.class); + + assertEquals("Verifying that the person's ID (protected method in a superclass) was set.", 99, person.getId()); + assertEquals("Verifying that the person's name (private method) was set.", "Tom", person.getName()); + assertEquals("Verifying that the person's age (protected method) was set.", 42, person.getAge()); + assertEquals("Verifying that the person's eye color (package private method) was set.", "blue", + person.getEyeColor()); + assertEquals("Verifying that the person's 'likes pets' flag (protected method for a boolean) was set.", true, + person.likesPets()); + assertEquals("Verifying that the person's 'favorite number' (protected method for a Number) was set.", PI, + person.getFavoriteNumber()); + + assertEquals(new Long(99), ReflectionTestUtils.invokeGetterMethod(person, "id")); + assertEquals("Tom", ReflectionTestUtils.invokeGetterMethod(person, "name")); + assertEquals(new Integer(42), ReflectionTestUtils.invokeGetterMethod(person, "age")); + assertEquals("blue", ReflectionTestUtils.invokeGetterMethod(person, "eyeColor")); + assertEquals(Boolean.TRUE, ReflectionTestUtils.invokeGetterMethod(person, "likesPets")); + assertEquals(PI, ReflectionTestUtils.invokeGetterMethod(person, "favoriteNumber")); + + // Standard - setter methods + + ReflectionTestUtils.invokeSetterMethod(person, "setId", new Long(1), long.class); + ReflectionTestUtils.invokeSetterMethod(person, "setName", "Jerry", String.class); + ReflectionTestUtils.invokeSetterMethod(person, "setAge", new Integer(33), int.class); + ReflectionTestUtils.invokeSetterMethod(person, "setEyeColor", "green", String.class); + ReflectionTestUtils.invokeSetterMethod(person, "setLikesPets", Boolean.FALSE, boolean.class); + ReflectionTestUtils.invokeSetterMethod(person, "setFavoriteNumber", new Integer(42), Number.class); + + assertEquals("Verifying that the person's ID (protected method in a superclass) was set.", 1, person.getId()); + assertEquals("Verifying that the person's name (private method) was set.", "Jerry", person.getName()); + assertEquals("Verifying that the person's age (protected method) was set.", 33, person.getAge()); + assertEquals("Verifying that the person's eye color (package private method) was set.", "green", + person.getEyeColor()); + assertEquals("Verifying that the person's 'likes pets' flag (protected method for a boolean) was set.", false, + person.likesPets()); + assertEquals("Verifying that the person's 'favorite number' (protected method for a Number) was set.", + new Integer(42), person.getFavoriteNumber()); + + assertEquals(new Long(1), ReflectionTestUtils.invokeGetterMethod(person, "getId")); + assertEquals("Jerry", ReflectionTestUtils.invokeGetterMethod(person, "getName")); + assertEquals(new Integer(33), ReflectionTestUtils.invokeGetterMethod(person, "getAge")); + assertEquals("green", ReflectionTestUtils.invokeGetterMethod(person, "getEyeColor")); + assertEquals(Boolean.FALSE, ReflectionTestUtils.invokeGetterMethod(person, "likesPets")); + assertEquals(new Integer(42), ReflectionTestUtils.invokeGetterMethod(person, "getFavoriteNumber")); + + // Null - non-primitives + + ReflectionTestUtils.invokeSetterMethod(person, "name", null, String.class); + ReflectionTestUtils.invokeSetterMethod(person, "eyeColor", null, String.class); + ReflectionTestUtils.invokeSetterMethod(person, "favoriteNumber", null, Number.class); + + assertNull("Verifying that the person's name (private method) was set.", person.getName()); + assertNull("Verifying that the person's eye color (package private method) was set.", person.getEyeColor()); + assertNull("Verifying that the person's 'favorite number' (protected method for a Number) was set.", + person.getFavoriteNumber()); + + // Null - primitives + + new AssertThrows(RuntimeException.class, + "Calling invokeSetterMethod() with NULL for a primitive type should throw an IllegalArgumentException.") { + + public void test() throws Exception { + ReflectionTestUtils.invokeSetterMethod(person, "id", null, long.class); + } + }.runTest(); + + new AssertThrows(RuntimeException.class, + "Calling invokeSetterMethod() with NULL for a primitive type should throw an IllegalArgumentException.") { + + public void test() throws Exception { + ReflectionTestUtils.invokeSetterMethod(person, "age", null, int.class); + } + }.runTest(); + + new AssertThrows(RuntimeException.class, + "Calling invokeSetterMethod() with NULL for a primitive type should throw an IllegalArgumentException.") { + + public void test() throws Exception { + ReflectionTestUtils.invokeSetterMethod(person, "likesPets", null, boolean.class); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java b/org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java new file mode 100644 index 00000000000..7831653bf3e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.util.subpackage; + +/** + * Abstract base class for persistent entities; intended for use in + * unit tests. + * + * @author Sam Brannen + * @since 2.5 + */ +public abstract class PersistentEntity { + + private long id; + + + public final long getId() { + return this.id; + } + + protected final void setId(long id) { + this.id = id; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/Person.java b/org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/Person.java new file mode 100644 index 00000000000..0fec1a026ea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/test/util/subpackage/Person.java @@ -0,0 +1,98 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.util.subpackage; + +import org.springframework.core.style.ToStringCreator; + +/** + * Concrete subclass of {@link PersistentEntity} representing a person + * entity; intended for use in unit tests. + * + * @author Sam Brannen + * @since 2.5 + */ +public class Person extends PersistentEntity { + + protected String name; + + private int age; + + String eyeColor; + + boolean likesPets = false; + + private Number favoriteNumber; + + + public final String getName() { + return this.name; + } + + private final void setName(final String name) { + this.name = name; + } + + public final int getAge() { + return this.age; + } + + protected final void setAge(final int age) { + this.age = age; + } + + public final String getEyeColor() { + return this.eyeColor; + } + + final void setEyeColor(final String eyeColor) { + this.eyeColor = eyeColor; + } + + public final boolean likesPets() { + return this.likesPets; + } + + protected final void setLikesPets(final boolean likesPets) { + this.likesPets = likesPets; + } + + public final Number getFavoriteNumber() { + return this.favoriteNumber; + } + + protected final void setFavoriteNumber(Number favoriteNumber) { + this.favoriteNumber = favoriteNumber; + } + + public String toString() { + return new ToStringCreator(this) + + .append("id", this.getId()) + + .append("name", this.name) + + .append("age", this.age) + + .append("eyeColor", this.eyeColor) + + .append("likesPets", this.likesPets) + + .append("favoriteNumber", this.favoriteNumber) + + .toString(); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/CallCountingTransactionManager.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/CallCountingTransactionManager.java new file mode 100644 index 00000000000..d5c2531fbde --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/CallCountingTransactionManager.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import org.springframework.transaction.support.AbstractPlatformTransactionManager; +import org.springframework.transaction.support.DefaultTransactionStatus; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class CallCountingTransactionManager extends AbstractPlatformTransactionManager { + + public TransactionDefinition lastDefinition; + public int begun; + public int commits; + public int rollbacks; + public int inflight; + + protected Object doGetTransaction() { + return new Object(); + } + + protected void doBegin(Object transaction, TransactionDefinition definition) { + this.lastDefinition = definition; + ++begun; + ++inflight; + } + + protected void doCommit(DefaultTransactionStatus status) { + ++commits; + --inflight; + } + + protected void doRollback(DefaultTransactionStatus status) { + ++rollbacks; + --inflight; + } + + public void clear() { + begun = commits = rollbacks = inflight = 0; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/JndiJtaTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/JndiJtaTransactionManagerTests.java new file mode 100644 index 00000000000..c78fdcf43cb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/JndiJtaTransactionManagerTests.java @@ -0,0 +1,243 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import javax.transaction.Status; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.jndi.ExpectedLookupTemplate; +import org.springframework.transaction.jta.JtaTransactionManager; +import org.springframework.transaction.jta.UserTransactionAdapter; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 05.08.2005 + */ +public class JndiJtaTransactionManagerTests extends TestCase { + + public void testJtaTransactionManagerWithDefaultJndiLookups1() throws Exception { + doTestJtaTransactionManagerWithDefaultJndiLookups("java:comp/TransactionManager", true, true); + } + + public void testJtaTransactionManagerWithDefaultJndiLookups2() throws Exception { + doTestJtaTransactionManagerWithDefaultJndiLookups("java:/TransactionManager", true, true); + } + + public void testJtaTransactionManagerWithDefaultJndiLookupsAndNoTmFound() throws Exception { + doTestJtaTransactionManagerWithDefaultJndiLookups("java:/tm", false, true); + } + + public void testJtaTransactionManagerWithDefaultJndiLookupsAndNoUtFound() throws Exception { + doTestJtaTransactionManagerWithDefaultJndiLookups("java:/TransactionManager", true, false); + } + + private void doTestJtaTransactionManagerWithDefaultJndiLookups(String tmName, boolean tmFound, boolean defaultUt) + throws Exception { + + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + if (defaultUt) { + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + } + utControl.replay(); + + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + if (!defaultUt) { + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 2); + tm.begin(); + tmControl.setVoidCallable(1); + tm.commit(); + tmControl.setVoidCallable(1); + } + tmControl.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(); + ExpectedLookupTemplate jndiTemplate = new ExpectedLookupTemplate(); + if (defaultUt) { + jndiTemplate.addObject("java:comp/UserTransaction", ut); + } + jndiTemplate.addObject(tmName, tm); + ptm.setJndiTemplate(jndiTemplate); + ptm.afterPropertiesSet(); + + if (tmFound) { + assertEquals(tm, ptm.getTransactionManager()); + } + else { + assertNull(ptm.getTransactionManager()); + } + + if (defaultUt) { + assertEquals(ut, ptm.getUserTransaction()); + } + else { + assertTrue(ptm.getUserTransaction() instanceof UserTransactionAdapter); + UserTransactionAdapter uta = (UserTransactionAdapter) ptm.getUserTransaction(); + assertEquals(tm, uta.getTransactionManager()); + } + + TransactionTemplate tt = new TransactionTemplate(ptm); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + }); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionManagerWithCustomJndiLookups() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + + JtaTransactionManager ptm = new JtaTransactionManager(); + ptm.setUserTransactionName("jndi-ut"); + ptm.setTransactionManagerName("jndi-tm"); + ExpectedLookupTemplate jndiTemplate = new ExpectedLookupTemplate(); + jndiTemplate.addObject("jndi-ut", ut); + jndiTemplate.addObject("jndi-tm", tm); + ptm.setJndiTemplate(jndiTemplate); + ptm.afterPropertiesSet(); + + assertEquals(ut, ptm.getUserTransaction()); + assertEquals(tm, ptm.getTransactionManager()); + + TransactionTemplate tt = new TransactionTemplate(ptm); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + }); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithNotCacheUserTransaction() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl ut2Control = MockControl.createControl(UserTransaction.class); + UserTransaction ut2 = (UserTransaction) ut2Control.getMock(); + ut2.getStatus(); + ut2Control.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut2.getStatus(); + ut2Control.setReturnValue(Status.STATUS_ACTIVE, 2); + ut2.begin(); + ut2Control.setVoidCallable(1); + ut2.commit(); + ut2Control.setVoidCallable(1); + ut2Control.replay(); + + JtaTransactionManager ptm = new JtaTransactionManager(); + ptm.setJndiTemplate(new ExpectedLookupTemplate("java:comp/UserTransaction", ut)); + ptm.setCacheUserTransaction(false); + ptm.afterPropertiesSet(); + + assertEquals(ut, ptm.getUserTransaction()); + + TransactionTemplate tt = new TransactionTemplate(ptm); + assertEquals(JtaTransactionManager.SYNCHRONIZATION_ALWAYS, ptm.getTransactionSynchronization()); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + }); + + ptm.setJndiTemplate(new ExpectedLookupTemplate("java:comp/UserTransaction", ut2)); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + }); + assertTrue(!TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + utControl.verify(); + ut2Control.verify(); + } + + /** + * Prevent any side-effects due to this test modifying ThreadLocals that might + * affect subsequent tests when all tests are run in the same JVM, as with Eclipse. + */ + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/JtaTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/JtaTransactionManagerTests.java new file mode 100644 index 00000000000..6d23128081e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/JtaTransactionManagerTests.java @@ -0,0 +1,1574 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.NotSupportedException; +import javax.transaction.RollbackException; +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.transaction.jta.JtaTransactionManager; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationAdapter; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 12.05.2003 + */ +public class JtaTransactionManagerTests extends TestCase { + + public void testJtaTransactionManagerWithCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCommit(false); + synchControl.setVoidCallable(1); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCommit(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setName("txName"); + + assertEquals(JtaTransactionManager.SYNCHRONIZATION_ALWAYS, ptm.getTransactionSynchronization()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + assertEquals("txName", TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithCommitAndSynchronizationOnActual() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCommit(false); + synchControl.setVoidCallable(1); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCommit(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronization(JtaTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithCommitAndSynchronizationNever() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronization(JtaTransactionManager.SYNCHRONIZATION_NEVER); + ptm.afterPropertiesSet(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithRollback() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.setTransactionTimeout(10); + utControl.setVoidCallable(1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setTimeout(10); + tt.setName("txName"); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + assertEquals("txName", TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithRollbackAndSynchronizationOnActual() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.setTransactionTimeout(10); + utControl.setVoidCallable(1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronization(JtaTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + tt.setTimeout(10); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithRollbackAndSynchronizationNever() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.setTransactionTimeout(10); + utControl.setVoidCallable(1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronizationName("SYNCHRONIZATION_NEVER"); + tt.setTimeout(10); + ptm.afterPropertiesSet(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndRollbackOnly() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndException() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + throw new IllegalStateException("I want a rollback"); + } + }); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndCommitException() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCommit(false); + synchControl.setThrowable(new OptimisticLockingFailureException("")); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + } + }); + fail("Should have thrown OptimisticLockingFailureException"); + } + catch (OptimisticLockingFailureException ex) { + // expected + } + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndRollbackOnlyAndNoGlobalRollback() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + ptm.setGlobalRollbackOnParticipationFailure(false); + TransactionTemplate tt = new TransactionTemplate(ptm); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndExceptionAndNoGlobalRollback() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + ptm.setGlobalRollbackOnParticipationFailure(false); + TransactionTemplate tt = new TransactionTemplate(ptm); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + throw new IllegalStateException("I want a rollback"); + } + }); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndJtaSynchronization() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockJtaTransaction tx = new MockJtaTransaction(); + + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + tm.getTransaction(); + tmControl.setReturnValue(tx, 1); + + utControl.replay(); + tmControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut, tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNotNull(tx.getSynchronization()); + tx.getSynchronization().beforeCompletion(); + tx.getSynchronization().afterCompletion(Status.STATUS_ROLLEDBACK); + + utControl.verify(); + tmControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndSynchronizationOnActual() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronization(JtaTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithExistingTransactionAndSynchronizationNever() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronization(JtaTransactionManager.SYNCHRONIZATION_NEVER); + ptm.afterPropertiesSet(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithExistingAndPropagationSupports() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationSupports() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + utControl.replay(); + + MockControl synchControl = MockControl.createControl(TransactionSynchronization.class); + final TransactionSynchronization synch = (TransactionSynchronization) synchControl.getMock(); + synch.beforeCompletion(); + synchControl.setVoidCallable(1); + synch.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); + synchControl.setVoidCallable(1); + synchControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionSynchronizationManager.registerSynchronization(synch); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + synchControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationSupportsAndSynchronizationOnActual() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronization(JtaTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + ptm.afterPropertiesSet(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationSupportsAndSynchronizationNever() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + ptm.setTransactionSynchronization(JtaTransactionManager.SYNCHRONIZATION_NEVER); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + ptm.afterPropertiesSet(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationNotSupported() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.suspend(); + tmControl.setReturnValue(tx, 1); + tm.resume(tx); + tmControl.setVoidCallable(1); + utControl.replay(); + tmControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut, tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + status.setRollbackOnly(); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationRequiresNew() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 5); + tm.suspend(); + tmControl.setReturnValue(tx, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + tm.resume(tx); + tmControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + tmControl.replay(); + + final JtaTransactionManager ptm = newJtaTransactionManager(ut, tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + tt.setName("txName"); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertEquals("txName", TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + TransactionTemplate tt2 = new TransactionTemplate(ptm); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + tt2.setReadOnly(true); + tt2.setName("txName2"); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertEquals("txName2", TransactionSynchronizationManager.getCurrentTransactionName()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + }); + + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertEquals("txName", TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationRequiresNewWithinSupports() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + final JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + + TransactionTemplate tt2 = new TransactionTemplate(ptm); + tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + tt2.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + } + }); + + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationRequiresNewAndExisting() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + tm.suspend(); + tmControl.setReturnValue(tx, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + tm.resume(tx); + tmControl.setVoidCallable(1); + utControl.replay(); + tmControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut, tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationRequiresNewAndExistingWithSuspendException() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.suspend(); + tmControl.setThrowable(new SystemException()); + utControl.replay(); + tmControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut, tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationRequiresNewAndExistingWithBeginException() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + tm.suspend(); + tmControl.setReturnValue(tx, 1); + ut.begin(); + utControl.setThrowable(new SystemException()); + tm.resume(tx); + tmControl.setVoidCallable(1); + utControl.replay(); + tmControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut, tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + } + }); + fail("Should have thrown CannotCreateTransactionException"); + } + catch (CannotCreateTransactionException ex) { + // expected + } + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + tmControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationRequiresNewAndAdapter() throws Exception { + MockControl tmControl = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmControl.getMock(); + MockControl txControl = MockControl.createControl(Transaction.class); + Transaction tx = (Transaction) txControl.getMock(); + tm.getStatus(); + tmControl.setReturnValue(Status.STATUS_ACTIVE, 3); + tm.suspend(); + tmControl.setReturnValue(tx, 1); + tm.begin(); + tmControl.setVoidCallable(1); + tm.commit(); + tmControl.setVoidCallable(1); + tm.resume(tx); + tmControl.setVoidCallable(1); + tmControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(tm); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + } + }); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + tmControl.verify(); + } + + public void testJtaTransactionManagerWithPropagationRequiresNewAndSuspensionNotSupported() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + } + }); + fail("Should have thrown TransactionSuspensionNotSupportedException"); + } + catch (TransactionSuspensionNotSupportedException ex) { + // expected + } + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithIsolationLevel() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown InvalidIsolationLevelException"); + } + catch (InvalidIsolationLevelException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithSystemExceptionOnIsExisting() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setThrowable(new SystemException("system exception")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithNestedBegin() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + + utControl.verify(); + } + + public void testJtaTransactionManagerWithNotSupportedExceptionOnNestedBegin() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.begin(); + utControl.setThrowable(new NotSupportedException("not supported")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown NestedTransactionNotSupportedException"); + } + catch (NestedTransactionNotSupportedException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithUnsupportedOperationExceptionOnNestedBegin() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.begin(); + utControl.setThrowable(new UnsupportedOperationException("not supported")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown NestedTransactionNotSupportedException"); + } + catch (NestedTransactionNotSupportedException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithSystemExceptionOnBegin() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setThrowable(new SystemException("system exception")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + } + }); + fail("Should have thrown CannotCreateTransactionException"); + } + catch (CannotCreateTransactionException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithRollbackExceptionOnCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setThrowable(new RollbackException("unexpected rollback")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + assertTrue("Correct completion status", status == TransactionSynchronization.STATUS_ROLLED_BACK); + } + }); + } + }); + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithNoExceptionOnGlobalRollbackOnly() throws Exception { + doTestJtaTransactionManagerWithNoExceptionOnGlobalRollbackOnly(false); + } + + public void testJtaTransactionManagerWithNoExceptionOnGlobalRollbackOnlyAndFailEarly() throws Exception { + doTestJtaTransactionManagerWithNoExceptionOnGlobalRollbackOnly(true); + } + + private void doTestJtaTransactionManagerWithNoExceptionOnGlobalRollbackOnly(boolean failEarly) throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_MARKED_ROLLBACK, 3); + ut.begin(); + utControl.setVoidCallable(1); + if (failEarly) { + ut.rollback(); + } + else { + ut.commit(); + } + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager tm = newJtaTransactionManager(ut); + if (failEarly) { + tm.setFailEarlyOnGlobalRollbackOnly(true); + } + + TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); + boolean outerTransactionBoundaryReached = false; + try { + assertTrue("Is new transaction", ts.isNewTransaction()); + + TransactionTemplate tt = new TransactionTemplate(tm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + assertTrue("Correct completion status", status == TransactionSynchronization.STATUS_ROLLED_BACK); + } + }); + } + }); + + outerTransactionBoundaryReached = true; + tm.commit(ts); + + fail("Should have thrown UnexpectedRollbackException"); + } + catch (UnexpectedRollbackException ex) { + // expected + if (!outerTransactionBoundaryReached) { + tm.rollback(ts); + } + if (failEarly) { + assertFalse(outerTransactionBoundaryReached); + } + else { + assertTrue(outerTransactionBoundaryReached); + } + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithHeuristicMixedExceptionOnCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setThrowable(new HeuristicMixedException("heuristic exception")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + assertTrue("Correct completion status", status == TransactionSynchronization.STATUS_UNKNOWN); + } + }); + } + }); + fail("Should have thrown HeuristicCompletionException"); + } + catch (HeuristicCompletionException ex) { + // expected + assertTrue(ex.getOutcomeState() == HeuristicCompletionException.STATE_MIXED); + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithHeuristicRollbackExceptionOnCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setThrowable(new HeuristicRollbackException("heuristic exception")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + assertTrue("Correct completion status", status == TransactionSynchronization.STATUS_UNKNOWN); + } + }); + } + }); + fail("Should have thrown HeuristicCompletionException"); + } + catch (HeuristicCompletionException ex) { + // expected + assertTrue(ex.getOutcomeState() == HeuristicCompletionException.STATE_ROLLED_BACK); + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithSystemExceptionOnCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setThrowable(new SystemException("system exception")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + // something transactional + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + assertTrue("Correct completion status", status == TransactionSynchronization.STATUS_UNKNOWN); + } + }); + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithSystemExceptionOnRollback() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setThrowable(new SystemException("system exception")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + assertTrue("Correct completion status", status == TransactionSynchronization.STATUS_UNKNOWN); + } + }); + status.setRollbackOnly(); + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithIllegalStateExceptionOnRollbackOnly() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setThrowable(new IllegalStateException("no existing transaction")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + status.setRollbackOnly(); + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithSystemExceptionOnRollbackOnly() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 3); + ut.setRollbackOnly(); + utControl.setThrowable(new SystemException("system exception")); + utControl.replay(); + + try { + JtaTransactionManager ptm = newJtaTransactionManager(ut); + TransactionTemplate tt = new TransactionTemplate(ptm); + tt.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + status.setRollbackOnly(); + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + public void afterCompletion(int status) { + assertTrue("Correct completion status", status == TransactionSynchronization.STATUS_UNKNOWN); + } + }); + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithDoubleCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionStatus status = ptm.getTransaction(new DefaultTransactionDefinition()); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + // first commit + ptm.commit(status); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + // second commit attempt + ptm.commit(status); + fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithDoubleRollback() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionStatus status = ptm.getTransaction(new DefaultTransactionDefinition()); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + // first rollback + ptm.rollback(status); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + // second rollback attempt + ptm.rollback(status); + fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + + utControl.verify(); + } + + public void testJtaTransactionManagerWithRollbackAndCommit() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.begin(); + utControl.setVoidCallable(1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 1); + ut.rollback(); + utControl.setVoidCallable(1); + utControl.replay(); + + JtaTransactionManager ptm = newJtaTransactionManager(ut); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + TransactionStatus status = ptm.getTransaction(new DefaultTransactionDefinition()); + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + // first: rollback + ptm.rollback(status); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + try { + // second: commit attempt + ptm.commit(status); + fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + + utControl.verify(); + } + + + protected JtaTransactionManager newJtaTransactionManager(UserTransaction ut) { + return new JtaTransactionManager(ut); + } + + protected JtaTransactionManager newJtaTransactionManager(TransactionManager tm) { + return new JtaTransactionManager(tm); + } + + protected JtaTransactionManager newJtaTransactionManager(UserTransaction ut, TransactionManager tm) { + return new JtaTransactionManager(ut, tm); + } + + + /** + * Prevent any side-effects due to this test modifying ThreadLocals that might + * affect subsequent tests when all tests are run in the same JVM, as with Eclipse. + */ + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionName()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertNull(TransactionSynchronizationManager.getCurrentTransactionIsolationLevel()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/MockCallbackPreferringTransactionManager.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/MockCallbackPreferringTransactionManager.java new file mode 100644 index 00000000000..f810e715b9b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/MockCallbackPreferringTransactionManager.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager; +import org.springframework.transaction.support.SimpleTransactionStatus; +import org.springframework.transaction.support.TransactionCallback; + +/** + * @author Juergen Hoeller + */ +public class MockCallbackPreferringTransactionManager implements CallbackPreferringPlatformTransactionManager { + + private TransactionDefinition definition; + + private TransactionStatus status; + + + public Object execute(TransactionDefinition definition, TransactionCallback callback) throws TransactionException { + this.definition = definition; + this.status = new SimpleTransactionStatus(); + return callback.doInTransaction(this.status); + } + + public TransactionDefinition getDefinition() { + return this.definition; + } + + public TransactionStatus getStatus() { + return this.status; + } + + + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + throw new UnsupportedOperationException(); + } + + public void commit(TransactionStatus status) throws TransactionException { + throw new UnsupportedOperationException(); + } + + public void rollback(TransactionStatus status) throws TransactionException { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/MockJtaTransaction.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/MockJtaTransaction.java new file mode 100644 index 00000000000..c9c8709c48b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/MockJtaTransaction.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import javax.transaction.Status; +import javax.transaction.Synchronization; +import javax.transaction.xa.XAResource; + +/** + * @author Juergen Hoeller + * @since 31.08.2004 + */ +public class MockJtaTransaction implements javax.transaction.Transaction { + + private Synchronization synchronization; + + public int getStatus() { + return Status.STATUS_ACTIVE; + } + + public void registerSynchronization(Synchronization synchronization) { + this.synchronization = synchronization; + } + + public Synchronization getSynchronization() { + return synchronization; + } + + public boolean enlistResource(XAResource xaResource) { + return false; + } + + public boolean delistResource(XAResource xaResource, int i) { + return false; + } + + public void commit() { + } + + public void rollback() { + } + + public void setRollbackOnly() { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/TestTransactionManager.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TestTransactionManager.java new file mode 100644 index 00000000000..f64862b9389 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TestTransactionManager.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import org.springframework.transaction.support.AbstractPlatformTransactionManager; +import org.springframework.transaction.support.DefaultTransactionStatus; + +/** + * @author Juergen Hoeller + * @since 29.04.2003 + */ +class TestTransactionManager extends AbstractPlatformTransactionManager { + + private static final Object TRANSACTION = "transaction"; + + private final boolean existingTransaction; + + private final boolean canCreateTransaction; + + protected boolean begin = false; + + protected boolean commit = false; + + protected boolean rollback = false; + + protected boolean rollbackOnly = false; + + protected TestTransactionManager(boolean existingTransaction, boolean canCreateTransaction) { + this.existingTransaction = existingTransaction; + this.canCreateTransaction = canCreateTransaction; + setTransactionSynchronization(SYNCHRONIZATION_NEVER); + } + + protected Object doGetTransaction() { + return TRANSACTION; + } + + protected boolean isExistingTransaction(Object transaction) { + return existingTransaction; + } + + protected void doBegin(Object transaction, TransactionDefinition definition) { + if (!TRANSACTION.equals(transaction)) { + throw new IllegalArgumentException("Not the same transaction object"); + } + if (!this.canCreateTransaction) { + throw new CannotCreateTransactionException("Cannot create transaction"); + } + this.begin = true; + } + + protected void doCommit(DefaultTransactionStatus status) { + if (!TRANSACTION.equals(status.getTransaction())) { + throw new IllegalArgumentException("Not the same transaction object"); + } + this.commit = true; + } + + protected void doRollback(DefaultTransactionStatus status) { + if (!TRANSACTION.equals(status.getTransaction())) { + throw new IllegalArgumentException("Not the same transaction object"); + } + this.rollback = true; + } + + protected void doSetRollbackOnly(DefaultTransactionStatus status) { + if (!TRANSACTION.equals(status.getTransaction())) { + throw new IllegalArgumentException("Not the same transaction object"); + } + this.rollbackOnly = true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/TransactionSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TransactionSupportTests.java new file mode 100644 index 00000000000..a2ec8a3b7c5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TransactionSupportTests.java @@ -0,0 +1,284 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import junit.framework.TestCase; + +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.DefaultTransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * @author Juergen Hoeller + * @since 29.04.2003 + */ +public class TransactionSupportTests extends TestCase { + + public void testNoExistingTransaction() { + PlatformTransactionManager tm = new TestTransactionManager(false, true); + DefaultTransactionStatus status1 = (DefaultTransactionStatus) + tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_SUPPORTS)); + assertTrue("Must not have transaction", status1.getTransaction() == null); + + DefaultTransactionStatus status2 = (DefaultTransactionStatus) + tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED)); + assertTrue("Must have transaction", status2.getTransaction() != null); + assertTrue("Must be new transaction", status2.isNewTransaction()); + + try { + tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_MANDATORY)); + fail("Should not have thrown NoTransactionException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + } + + public void testExistingTransaction() { + PlatformTransactionManager tm = new TestTransactionManager(true, true); + DefaultTransactionStatus status1 = (DefaultTransactionStatus) + tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_SUPPORTS)); + assertTrue("Must have transaction", status1.getTransaction() != null); + assertTrue("Must not be new transaction", !status1.isNewTransaction()); + + DefaultTransactionStatus status2 = (DefaultTransactionStatus) + tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED)); + assertTrue("Must have transaction", status2.getTransaction() != null); + assertTrue("Must not be new transaction", !status2.isNewTransaction()); + + try { + DefaultTransactionStatus status3 = (DefaultTransactionStatus) + tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_MANDATORY)); + assertTrue("Must have transaction", status3.getTransaction() != null); + assertTrue("Must not be new transaction", !status3.isNewTransaction()); + } + catch (NoTransactionException ex) { + fail("Should not have thrown NoTransactionException"); + } + } + + public void testCommitWithoutExistingTransaction() { + TestTransactionManager tm = new TestTransactionManager(false, true); + TransactionStatus status = tm.getTransaction(null); + tm.commit(status); + assertTrue("triggered begin", tm.begin); + assertTrue("triggered commit", tm.commit); + assertTrue("no rollback", !tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + + public void testRollbackWithoutExistingTransaction() { + TestTransactionManager tm = new TestTransactionManager(false, true); + TransactionStatus status = tm.getTransaction(null); + tm.rollback(status); + assertTrue("triggered begin", tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("triggered rollback", tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + + public void testRollbackOnlyWithoutExistingTransaction() { + TestTransactionManager tm = new TestTransactionManager(false, true); + TransactionStatus status = tm.getTransaction(null); + status.setRollbackOnly(); + tm.commit(status); + assertTrue("triggered begin", tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("triggered rollback", tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + + public void testCommitWithExistingTransaction() { + TestTransactionManager tm = new TestTransactionManager(true, true); + TransactionStatus status = tm.getTransaction(null); + tm.commit(status); + assertTrue("no begin", !tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("no rollback", !tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + + public void testRollbackWithExistingTransaction() { + TestTransactionManager tm = new TestTransactionManager(true, true); + TransactionStatus status = tm.getTransaction(null); + tm.rollback(status); + assertTrue("no begin", !tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("no rollback", !tm.rollback); + assertTrue("triggered rollbackOnly", tm.rollbackOnly); + } + + public void testRollbackOnlyWithExistingTransaction() { + TestTransactionManager tm = new TestTransactionManager(true, true); + TransactionStatus status = tm.getTransaction(null); + status.setRollbackOnly(); + tm.commit(status); + assertTrue("no begin", !tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("no rollback", !tm.rollback); + assertTrue("triggered rollbackOnly", tm.rollbackOnly); + } + + public void testTransactionTemplate() { + TestTransactionManager tm = new TestTransactionManager(false, true); + TransactionTemplate template = new TransactionTemplate(tm); + template.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + } + }); + assertTrue("triggered begin", tm.begin); + assertTrue("triggered commit", tm.commit); + assertTrue("no rollback", !tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + + public void testTransactionTemplateWithCallbackPreference() { + MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager(); + TransactionTemplate template = new TransactionTemplate(ptm); + template.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + } + }); + assertSame(template, ptm.getDefinition()); + assertFalse(ptm.getStatus().isRollbackOnly()); + } + + public void testTransactionTemplateWithException() { + TestTransactionManager tm = new TestTransactionManager(false, true); + TransactionTemplate template = new TransactionTemplate(tm); + final RuntimeException ex = new RuntimeException("Some application exception"); + try { + template.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + throw ex; + } + }); + fail("Should have propagated RuntimeException"); + } + catch (RuntimeException caught) { + // expected + assertTrue("Correct exception", caught == ex); + assertTrue("triggered begin", tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("triggered rollback", tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + } + + public void testTransactionTemplateWithRollbackException() { + final TransactionSystemException tex = new TransactionSystemException("system exception"); + TestTransactionManager tm = new TestTransactionManager(false, true) { + protected void doRollback(DefaultTransactionStatus status) { + super.doRollback(status); + throw tex; + } + }; + TransactionTemplate template = new TransactionTemplate(tm); + final RuntimeException ex = new RuntimeException("Some application exception"); + try { + template.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + throw ex; + } + }); + fail("Should have propagated RuntimeException"); + } + catch (RuntimeException caught) { + // expected + assertTrue("Correct exception", caught == tex); + assertTrue("triggered begin", tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("triggered rollback", tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + } + + public void testTransactionTemplateWithError() { + TestTransactionManager tm = new TestTransactionManager(false, true); + TransactionTemplate template = new TransactionTemplate(tm); + try { + template.execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + throw new Error("Some application error"); + } + }); + fail("Should have propagated Error"); + } + catch (Error err) { + // expected + assertTrue("triggered begin", tm.begin); + assertTrue("no commit", !tm.commit); + assertTrue("triggered rollback", tm.rollback); + assertTrue("no rollbackOnly", !tm.rollbackOnly); + } + } + + public void testTransactionTemplateInitialization() { + TestTransactionManager tm = new TestTransactionManager(false, true); + TransactionTemplate template = new TransactionTemplate(); + template.setTransactionManager(tm); + assertTrue("correct transaction manager set", template.getTransactionManager() == tm); + + try { + template.setPropagationBehaviorName("TIMEOUT_DEFAULT"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + template.setPropagationBehaviorName("PROPAGATION_SUPPORTS"); + assertTrue("Correct propagation behavior set", template.getPropagationBehavior() == TransactionDefinition.PROPAGATION_SUPPORTS); + + try { + template.setPropagationBehavior(999); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + template.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY); + assertTrue("Correct propagation behavior set", template.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY); + + try { + template.setIsolationLevelName("TIMEOUT_DEFAULT"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + template.setIsolationLevelName("ISOLATION_SERIALIZABLE"); + assertTrue("Correct isolation level set", template.getIsolationLevel() == TransactionDefinition.ISOLATION_SERIALIZABLE); + + try { + template.setIsolationLevel(999); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + template.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); + assertTrue("Correct isolation level set", template.getIsolationLevel() == TransactionDefinition.ISOLATION_REPEATABLE_READ); + } + + protected void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerEventTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerEventTests.java new file mode 100644 index 00000000000..e2a96b972ac --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerEventTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CollectingReaderEventListener; +import org.springframework.beans.factory.parsing.ComponentDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Torsten Juergeleit + * @author Juergen Hoeller + */ +public class TxNamespaceHandlerEventTests extends TestCase { + + private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + + private CollectingReaderEventListener eventListener = new CollectingReaderEventListener(); + + + public void setUp() throws Exception { + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.setEventListener(this.eventListener); + reader.loadBeanDefinitions(new ClassPathResource("txNamespaceHandlerTests.xml", getClass())); + } + + public void testComponentEventReceived() { + ComponentDefinition component = this.eventListener.getComponentDefinition("txAdvice"); + assertTrue(component instanceof BeanComponentDefinition); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerTests.java new file mode 100644 index 00000000000..b83f83ebd4b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/TxNamespaceHandlerTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.ITestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.transaction.interceptor.TransactionAttribute; +import org.springframework.transaction.interceptor.TransactionAttributeSource; +import org.springframework.transaction.interceptor.TransactionInterceptor; + +/** + * @author Rob Harrop + * @author Adrian Colyer + */ +public class TxNamespaceHandlerTests extends TestCase { + + private ApplicationContext context; + + private Method getAgeMethod; + + private Method setAgeMethod; + + public void setUp() throws Exception { + this.context = new ClassPathXmlApplicationContext("txNamespaceHandlerTests.xml", getClass()); + this.getAgeMethod = ITestBean.class.getMethod("getAge", new Class[0]); + this.setAgeMethod = ITestBean.class.getMethod("setAge", new Class[] {int.class}); + } + + public void testIsProxy() throws Exception { + ITestBean bean = getTestBean(); + assertTrue("testBean is not a proxy", AopUtils.isAopProxy(bean)); + } + + public void testInvokeTransactional() throws Exception { + ITestBean testBean = getTestBean(); + CallCountingTransactionManager ptm = (CallCountingTransactionManager) context.getBean("transactionManager"); + + // try with transactional + assertEquals("Should not have any started transactions", 0, ptm.begun); + testBean.getName(); + assertTrue(ptm.lastDefinition.isReadOnly()); + assertEquals("Should have 1 started transaction", 1, ptm.begun); + assertEquals("Should have 1 committed transaction", 1, ptm.commits); + + // try with non-transaction + testBean.haveBirthday(); + assertEquals("Should not have started another transaction", 1, ptm.begun); + + // try with exceptional + try { + testBean.exceptional(new IllegalArgumentException("foo")); + fail("Should NEVER get here"); + } + catch (Throwable throwable) { + assertEquals("Should have another started transaction", 2, ptm.begun); + assertEquals("Should have 1 rolled back transaction", 1, ptm.rollbacks); + } + } + + public void testRollbackRules() { + TransactionInterceptor txInterceptor = (TransactionInterceptor) context.getBean("txRollbackAdvice"); + TransactionAttributeSource txAttrSource = txInterceptor.getTransactionAttributeSource(); + TransactionAttribute txAttr = txAttrSource.getTransactionAttribute(getAgeMethod,ITestBean.class); + assertTrue("should be configured to rollback on Exception",txAttr.rollbackOn(new Exception())); + + txAttr = txAttrSource.getTransactionAttribute(setAgeMethod, ITestBean.class); + assertFalse("should not rollback on RuntimeException",txAttr.rollbackOn(new RuntimeException())); + } + + private ITestBean getTestBean() { + return (ITestBean)context.getBean("testBean"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/AbstractTransactionAspectTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/AbstractTransactionAspectTests.java new file mode 100644 index 00000000000..790c0ee53cf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/AbstractTransactionAspectTests.java @@ -0,0 +1,599 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.transaction.CannotCreateTransactionException; +import org.springframework.transaction.MockCallbackPreferringTransactionManager; +import org.springframework.transaction.NoTransactionException; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.TransactionSystemException; +import org.springframework.transaction.UnexpectedRollbackException; +import org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo; + +/** + * Mock object based tests for transaction aspects. + * True unit test in that it tests how the transaction aspect uses + * the PlatformTransactionManager helper, rather than indirectly + * testing the helper implementation. + * + * This is a superclass to allow testing both the AOP Alliance MethodInterceptor + * and the AspectJ aspect. + * + * @author Rod Johnson + * @since 16.03.2003 + */ +public abstract class AbstractTransactionAspectTests extends TestCase { + + protected Method exceptionalMethod; + + protected Method getNameMethod; + + protected Method setNameMethod; + + + public AbstractTransactionAspectTests() { + try { + // Cache the methods we'll be testing + exceptionalMethod = ITestBean.class.getMethod("exceptional", new Class[] { Throwable.class }); + getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null); + setNameMethod = ITestBean.class.getMethod("setName", new Class[] { String.class} ); + } + catch (NoSuchMethodException ex) { + throw new RuntimeException("Shouldn't happen", ex); + } + } + + + public void testNoTransaction() throws Exception { + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + + // expect no calls + ptmControl.replay(); + + TestBean tb = new TestBean(); + TransactionAttributeSource tas = new MapTransactionAttributeSource(); + + // All the methods in this class use the advised() template method + // to obtain a transaction object, configured with the given PlatformTransactionManager + // and transaction attribute source + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + checkTransactionStatus(false); + itb.getName(); + checkTransactionStatus(false); + + ptmControl.verify(); + } + + /** + * Check that a transaction is created and committed. + */ + public void testTransactionShouldSucceed() throws Exception { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(getNameMethod, txatt); + + TransactionStatus status = transactionStatusForNewTransaction(); + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // expect a transaction + ptm.getTransaction(txatt); + ptmControl.setReturnValue(status, 1); + ptm.commit(status); + ptmControl.setVoidCallable(1); + ptmControl.replay(); + + TestBean tb = new TestBean(); + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + checkTransactionStatus(false); + itb.getName(); + checkTransactionStatus(false); + + ptmControl.verify(); + } + + /** + * Check that a transaction is created and committed using + * CallbackPreferringPlatformTransactionManager. + */ + public void testTransactionShouldSucceedWithCallbackPreference() throws Exception { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(getNameMethod, txatt); + + MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager(); + + TestBean tb = new TestBean(); + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + checkTransactionStatus(false); + itb.getName(); + checkTransactionStatus(false); + + assertSame(txatt, ptm.getDefinition()); + assertFalse(ptm.getStatus().isRollbackOnly()); + } + + public void testTransactionExceptionPropagatedWithCallbackPreference() throws Throwable { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(exceptionalMethod, txatt); + + MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager(); + + TestBean tb = new TestBean(); + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + checkTransactionStatus(false); + try { + itb.exceptional(new OptimisticLockingFailureException("")); + fail("Should have thrown OptimisticLockingFailureException"); + } + catch (OptimisticLockingFailureException ex) { + // expected + } + checkTransactionStatus(false); + + assertSame(txatt, ptm.getDefinition()); + assertFalse(ptm.getStatus().isRollbackOnly()); + } + + /** + * Check that two transactions are created and committed. + */ + public void testTwoTransactionsShouldSucceed() throws Exception { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + MapTransactionAttributeSource tas1 = new MapTransactionAttributeSource(); + tas1.register(getNameMethod, txatt); + MapTransactionAttributeSource tas2 = new MapTransactionAttributeSource(); + tas2.register(setNameMethod, txatt); + + TransactionStatus status = transactionStatusForNewTransaction(); + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // expect a transaction + ptm.getTransaction(txatt); + ptmControl.setReturnValue(status, 2); + ptm.commit(status); + ptmControl.setVoidCallable(2); + ptmControl.replay(); + + TestBean tb = new TestBean(); + ITestBean itb = (ITestBean) advised(tb, ptm, new TransactionAttributeSource[] {tas1, tas2}); + + checkTransactionStatus(false); + itb.getName(); + checkTransactionStatus(false); + itb.setName("myName"); + checkTransactionStatus(false); + + ptmControl.verify(); + } + + /** + * Check that a transaction is created and committed. + */ + public void testTransactionShouldSucceedWithNotNew() throws Exception { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(getNameMethod, txatt); + + MockControl statusControl = MockControl.createControl(TransactionStatus.class); + TransactionStatus status = (TransactionStatus) statusControl.getMock(); + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // expect a transaction + ptm.getTransaction(txatt); + ptmControl.setReturnValue(status, 1); + ptm.commit(status); + ptmControl.setVoidCallable(1); + ptmControl.replay(); + + TestBean tb = new TestBean(); + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + checkTransactionStatus(false); + // verification!? + itb.getName(); + checkTransactionStatus(false); + + ptmControl.verify(); + } + + public void testEnclosingTransactionWithNonTransactionMethodOnAdvisedInside() throws Throwable { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(exceptionalMethod, txatt); + + TransactionStatus status = transactionStatusForNewTransaction(); + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // Expect a transaction + ptm.getTransaction(txatt); + ptmControl.setReturnValue(status, 1); + ptm.commit(status); + ptmControl.setVoidCallable(1); + ptmControl.replay(); + + final String spouseName = "innerName"; + + TestBean outer = new TestBean() { + public void exceptional(Throwable t) throws Throwable { + TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); + assertTrue(ti.hasTransaction()); + assertEquals(spouseName, getSpouse().getName()); + } + }; + TestBean inner = new TestBean() { + public String getName() { + // Assert that we're in the inner proxy + TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); + assertFalse(ti.hasTransaction()); + return spouseName; + } + }; + + ITestBean outerProxy = (ITestBean) advised(outer, ptm, tas); + ITestBean innerProxy = (ITestBean) advised(inner, ptm, tas); + outer.setSpouse(innerProxy); + + checkTransactionStatus(false); + + // Will invoke inner.getName, which is non-transactional + outerProxy.exceptional(null); + + checkTransactionStatus(false); + + ptmControl.verify(); + } + + public void testEnclosingTransactionWithNestedTransactionOnAdvisedInside() throws Throwable { + final TransactionAttribute outerTxatt = new DefaultTransactionAttribute(); + final TransactionAttribute innerTxatt = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_NESTED); + + Method outerMethod = exceptionalMethod; + Method innerMethod = getNameMethod; + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(outerMethod, outerTxatt); + tas.register(innerMethod, innerTxatt); + + TransactionStatus outerStatus = transactionStatusForNewTransaction(); + TransactionStatus innerStatus = transactionStatusForNewTransaction(); + + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // Expect a transaction + ptm.getTransaction(outerTxatt); + ptmControl.setReturnValue(outerStatus, 1); + + ptm.getTransaction(innerTxatt); + ptmControl.setReturnValue(innerStatus, 1); + + ptm.commit(innerStatus); + ptmControl.setVoidCallable(1); + + ptm.commit(outerStatus); + ptmControl.setVoidCallable(1); + ptmControl.replay(); + + final String spouseName = "innerName"; + + TestBean outer = new TestBean() { + public void exceptional(Throwable t) throws Throwable { + TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); + assertTrue(ti.hasTransaction()); + assertEquals(outerTxatt, ti.getTransactionAttribute()); + assertEquals(spouseName, getSpouse().getName()); + } + }; + TestBean inner = new TestBean() { + public String getName() { + // Assert that we're in the inner proxy + TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); + // Has nested transaction + assertTrue(ti.hasTransaction()); + assertEquals(innerTxatt, ti.getTransactionAttribute()); + return spouseName; + } + }; + + ITestBean outerProxy = (ITestBean) advised(outer, ptm, tas); + ITestBean innerProxy = (ITestBean) advised(inner, ptm, tas); + outer.setSpouse(innerProxy); + + checkTransactionStatus(false); + + // Will invoke inner.getName, which is non-transactional + outerProxy.exceptional(null); + + checkTransactionStatus(false); + + ptmControl.verify(); + } + + public void testRollbackOnCheckedException() throws Throwable { + doTestRollbackOnException(new Exception(), true, false); + } + + public void testNoRollbackOnCheckedException() throws Throwable { + doTestRollbackOnException(new Exception(), false, false); + } + + public void testRollbackOnUncheckedException() throws Throwable { + doTestRollbackOnException(new RuntimeException(), true, false); + } + + public void testNoRollbackOnUncheckedException() throws Throwable { + doTestRollbackOnException(new RuntimeException(), false, false); + } + + public void testRollbackOnCheckedExceptionWithRollbackException() throws Throwable { + doTestRollbackOnException(new Exception(), true, true); + } + + public void testNoRollbackOnCheckedExceptionWithRollbackException() throws Throwable { + doTestRollbackOnException(new Exception(), false, true); + } + + public void testRollbackOnUncheckedExceptionWithRollbackException() throws Throwable { + doTestRollbackOnException(new RuntimeException(), true, true); + } + + public void testNoRollbackOnUncheckedExceptionWithRollbackException() throws Throwable { + doTestRollbackOnException(new RuntimeException(), false, true); + } + + /** + * Check that the given exception thrown by the target can produce the + * desired behavior with the appropriate transaction attribute. + * @param ex exception to be thrown by the target + * @param shouldRollback whether this should cause a transaction rollback + */ + protected void doTestRollbackOnException( + final Exception ex, final boolean shouldRollback, boolean rollbackException) throws Exception { + + TransactionAttribute txatt = new DefaultTransactionAttribute() { + public boolean rollbackOn(Throwable t) { + assertTrue(t == ex); + return shouldRollback; + } + }; + + Method m = exceptionalMethod; + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(m, txatt); + + MockControl statusControl = MockControl.createControl(TransactionStatus.class); + TransactionStatus status = (TransactionStatus) statusControl.getMock(); + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // Gets additional call(s) from TransactionControl + + ptm.getTransaction(txatt); + ptmControl.setReturnValue(status, 1); + + if (shouldRollback) { + ptm.rollback(status); + } + else { + ptm.commit(status); + } + TransactionSystemException tex = new TransactionSystemException("system exception"); + if (rollbackException) { + ptmControl.setThrowable(tex, 1); + } + else { + ptmControl.setVoidCallable(1); + } + ptmControl.replay(); + + TestBean tb = new TestBean(); + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + try { + itb.exceptional(ex); + fail("Should have thrown exception"); + } + catch (Throwable t) { + if (rollbackException) { + assertEquals("Caught wrong exception", tex, t ); + } + else { + assertEquals("Caught wrong exception", ex, t); + } + } + + ptmControl.verify(); + } + + /** + * Test that TransactionStatus.setRollbackOnly works. + */ + public void testProgrammaticRollback() throws Exception { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + Method m = getNameMethod; + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(m, txatt); + + TransactionStatus status = transactionStatusForNewTransaction(); + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + + ptm.getTransaction(txatt); + ptmControl.setReturnValue(status, 1); + ptm.commit(status); + ptmControl.setVoidCallable(1); + ptmControl.replay(); + + final String name = "jenny"; + TestBean tb = new TestBean() { + public String getName() { + TransactionStatus txStatus = TransactionInterceptor.currentTransactionStatus(); + txStatus.setRollbackOnly(); + return name; + } + }; + + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + // verification!? + assertTrue(name.equals(itb.getName())); + + ptmControl.verify(); + } + + /** + * @return a TransactionStatus object configured for a new transaction + */ + private TransactionStatus transactionStatusForNewTransaction() { + MockControl statusControl = MockControl.createControl(TransactionStatus.class); + return (TransactionStatus) statusControl.getMock(); + } + + /** + * Simulate a transaction infrastructure failure. + * Shouldn't invoke target method. + */ + public void testCannotCreateTransaction() throws Exception { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + Method m = getNameMethod; + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(m, txatt); + + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // Expect a transaction + ptm.getTransaction(txatt); + CannotCreateTransactionException ex = new CannotCreateTransactionException("foobar", null); + ptmControl.setThrowable(ex); + ptmControl.replay(); + + TestBean tb = new TestBean() { + public String getName() { + throw new UnsupportedOperationException( + "Shouldn't have invoked target method when couldn't create transaction for transactional method"); + } + }; + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + try { + itb.getName(); + fail("Shouldn't have invoked method"); + } + catch (CannotCreateTransactionException thrown) { + assertTrue(thrown == ex); + } + ptmControl.verify(); + } + + /** + * Simulate failure of the underlying transaction infrastructure to commit. + * Check that the target method was invoked, but that the transaction + * infrastructure exception was thrown to the client + */ + public void testCannotCommitTransaction() throws Exception { + TransactionAttribute txatt = new DefaultTransactionAttribute(); + + Method m = setNameMethod; + MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); + tas.register(m, txatt); + Method m2 = getNameMethod; + // No attributes for m2 + + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + + TransactionStatus status = transactionStatusForNewTransaction(); + ptm.getTransaction(txatt); + ptmControl.setReturnValue(status); + UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null); + ptm.commit(status); + ptmControl.setThrowable(ex); + ptmControl.replay(); + + TestBean tb = new TestBean(); + ITestBean itb = (ITestBean) advised(tb, ptm, tas); + + String name = "new name"; + try { + itb.setName(name); + fail("Shouldn't have succeeded"); + } + catch (UnexpectedRollbackException thrown) { + assertTrue(thrown == ex); + } + + // Should have invoked target and changed name + assertTrue(itb.getName() == name); + ptmControl.verify(); + } + + protected void checkTransactionStatus(boolean expected) { + try { + TransactionInterceptor.currentTransactionStatus(); + if (!expected) { + fail("Should have thrown NoTransactionException"); + } + } + catch (NoTransactionException ex) { + if (expected) { + fail("Should have current TransactionStatus"); + } + } + } + + + protected Object advised( + Object target, PlatformTransactionManager ptm, TransactionAttributeSource[] tas) throws Exception { + + return advised(target, ptm, new CompositeTransactionAttributeSource(tas)); + } + + /** + * Subclasses must implement this to create an advised object based on the + * given target. In the case of AspectJ, the advised object will already + * have been created, as there's no distinction between target and proxy. + * In the case of Spring's own AOP framework, a proxy must be created + * using a suitably configured transaction interceptor + * @param target target if there's a distinct target. If not (AspectJ), + * return target. + * @return transactional advised object + */ + protected abstract Object advised( + Object target, PlatformTransactionManager ptm, TransactionAttributeSource tas) throws Exception; + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java new file mode 100644 index 00000000000..f83009c4668 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java @@ -0,0 +1,225 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; + +import junit.framework.TestCase; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.easymock.MockControl; + +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.support.StaticMethodMatcherPointcut; +import org.springframework.aop.target.HotSwappableTargetSource; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.transaction.CallCountingTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; + +/** + * Test cases for AOP transaction management. + * + * @author Rod Johnson + * @since 23.04.2003 + */ +public class BeanFactoryTransactionTests extends TestCase { + + private XmlBeanFactory factory; + + public void setUp() { + this.factory = new XmlBeanFactory(new ClassPathResource("transactionalBeanFactory.xml", getClass())); + } + + public void testGetsAreNotTransactionalWithProxyFactory1() throws NoSuchMethodException { + ITestBean testBean = (ITestBean) factory.getBean("proxyFactory1"); + assertTrue("testBean is a dynamic proxy", Proxy.isProxyClass(testBean.getClass())); + doTestGetsAreNotTransactional(testBean, ITestBean.class); + } + + public void testGetsAreNotTransactionalWithProxyFactory2DynamicProxy() throws NoSuchMethodException { + this.factory.preInstantiateSingletons(); + ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2DynamicProxy"); + assertTrue("testBean is a dynamic proxy", Proxy.isProxyClass(testBean.getClass())); + doTestGetsAreNotTransactional(testBean, ITestBean.class); + } + + public void testGetsAreNotTransactionalWithProxyFactory2Cglib() throws NoSuchMethodException { + ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2Cglib"); + assertTrue("testBean is CGLIB advised", AopUtils.isCglibProxy(testBean)); + doTestGetsAreNotTransactional(testBean, TestBean.class); + } + + public void testProxyFactory2Lazy() throws NoSuchMethodException { + ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2Lazy"); + assertFalse(factory.containsSingleton("target")); + assertEquals(666, testBean.getAge()); + assertTrue(factory.containsSingleton("target")); + } + + public void testCglibTransactionProxyImplementsNoInterfaces() throws NoSuchMethodException { + ImplementsNoInterfaces ini = (ImplementsNoInterfaces) factory.getBean("cglibNoInterfaces"); + assertTrue("testBean is CGLIB advised", AopUtils.isCglibProxy(ini)); + String newName = "Gordon"; + + // Install facade + CallCountingTransactionManager ptm = new CallCountingTransactionManager(); + PlatformTransactionManagerFacade.delegate = ptm; + + ini.setName(newName); + assertEquals(newName, ini.getName()); + assertEquals(2, ptm.commits); + } + + public void testGetsAreNotTransactionalWithProxyFactory3() throws NoSuchMethodException { + ITestBean testBean = (ITestBean) factory.getBean("proxyFactory3"); + assertTrue("testBean is a full proxy", testBean instanceof DerivedTestBean); + InvocationCounterPointcut txnCounter = (InvocationCounterPointcut) factory.getBean("txnInvocationCounterPointcut"); + InvocationCounterInterceptor preCounter = (InvocationCounterInterceptor) factory.getBean("preInvocationCounterInterceptor"); + InvocationCounterInterceptor postCounter = (InvocationCounterInterceptor) factory.getBean("postInvocationCounterInterceptor"); + txnCounter.counter = 0; + preCounter.counter = 0; + postCounter.counter = 0; + doTestGetsAreNotTransactional(testBean, TestBean.class); + // Can't assert it's equal to 4 as the pointcut may be optimized and only invoked once + assertTrue(0 < txnCounter.counter && txnCounter.counter <= 4); + assertEquals(4, preCounter.counter); + assertEquals(4, postCounter.counter); + } + + private void doTestGetsAreNotTransactional(final ITestBean testBean, final Class proxyClass) { + // Install facade + MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class); + PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock(); + // Expect no methods + ptmControl.replay(); + PlatformTransactionManagerFacade.delegate = ptm; + + assertTrue("Age should not be " + testBean.getAge(), testBean.getAge() == 666); + // Check no calls + ptmControl.verify(); + + // Install facade expecting a call + MockControl statusControl = MockControl.createControl(TransactionStatus.class); + final TransactionStatus ts = (TransactionStatus) statusControl.getMock(); + ptm = new PlatformTransactionManager() { + private boolean invoked; + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + if (invoked) { + throw new IllegalStateException("getTransaction should not get invoked more than once"); + } + invoked = true; + if (!((definition.getName().indexOf(proxyClass.getName()) != -1) && + (definition.getName().indexOf("setAge") != -1))) { + throw new IllegalStateException( + "transaction name should contain class and method name: " + definition.getName()); + } + return ts; + } + public void commit(TransactionStatus status) throws TransactionException { + assertTrue(status == ts); + } + public void rollback(TransactionStatus status) throws TransactionException { + throw new IllegalStateException("rollback should not get invoked"); + } + }; + PlatformTransactionManagerFacade.delegate = ptm; + + // TODO same as old age to avoid ordering effect for now + int age = 666; + testBean.setAge(age); + assertTrue(testBean.getAge() == age); + ptmControl.verify(); + } + + public void testGetBeansOfTypeWithAbstract() { + Map beansOfType = factory.getBeansOfType(ITestBean.class, true, true); + } + + /** + * Check that we fail gracefully if the user doesn't set any transaction attributes. + */ + public void testNoTransactionAttributeSource() { + try { + XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("noTransactionAttributeSource.xml", getClass())); + ITestBean testBean = (ITestBean) bf.getBean("noTransactionAttributeSource"); + fail("Should require TransactionAttributeSource to be set"); + } + catch (FatalBeanException ex) { + // Ok + } + } + + /** + * Test that we can set the target to a dynamic TargetSource. + */ + public void testDynamicTargetSource() throws NoSuchMethodException { + // Install facade + CallCountingTransactionManager txMan = new CallCountingTransactionManager(); + PlatformTransactionManagerFacade.delegate = txMan; + + TestBean tb = (TestBean) factory.getBean("hotSwapped"); + assertEquals(666, tb.getAge()); + int newAge = 557; + tb.setAge(newAge); + assertEquals(newAge, tb.getAge()); + + TestBean target2 = new TestBean(); + target2.setAge(65); + HotSwappableTargetSource ts = (HotSwappableTargetSource) factory.getBean("swapper"); + ts.swap(target2); + assertEquals(target2.getAge(), tb.getAge()); + tb.setAge(newAge); + assertEquals(newAge, target2.getAge()); + + assertEquals(0, txMan.inflight); + assertEquals(2, txMan.commits); + assertEquals(0, txMan.rollbacks); + } + + + public static class InvocationCounterPointcut extends StaticMethodMatcherPointcut { + + int counter = 0; + + public boolean matches(Method method, Class clazz) { + counter++; + return true; + } + } + + + public static class InvocationCounterInterceptor implements MethodInterceptor { + + int counter = 0; + + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + counter++; + return methodInvocation.proceed(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/ImplementsNoInterfaces.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/ImplementsNoInterfaces.java new file mode 100644 index 00000000000..90f0361eed7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/ImplementsNoInterfaces.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import org.springframework.beans.TestBean; + +/** + * Test for CGLIB proxying that implements no interfaces + * and has one dependency. + * + * @author Rod Johnson + */ +public class ImplementsNoInterfaces { + + private TestBean testBean; + + public void setDependency(TestBean testBean) { + this.testBean = testBean; + } + + public String getName() { + return testBean.getName(); + } + + public void setName(String name) { + testBean.setName(name); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java new file mode 100644 index 00000000000..35ef3bf103e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Inherits fallback behavior from AbstractFallbackTransactionAttributeSource. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class MapTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource { + + /** Map from Method or Clazz to TransactionAttribute */ + private final Map attributeMap = new HashMap(); + + public void register(Method m, TransactionAttribute txAtt) { + this.attributeMap.put(m, txAtt); + } + + public void register(Class clazz, TransactionAttribute txAtt) { + this.attributeMap.put(clazz, txAtt); + } + + + protected TransactionAttribute findTransactionAttribute(Method method) { + return (TransactionAttribute) this.attributeMap.get(method); + } + + protected TransactionAttribute findTransactionAttribute(Class clazz) { + return (TransactionAttribute) this.attributeMap.get(clazz); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/PlatformTransactionManagerFacade.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/PlatformTransactionManagerFacade.java new file mode 100644 index 00000000000..78360642277 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/PlatformTransactionManagerFacade.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; + +/** + * Used for testing only (for example, when we must replace the + * behavior of a PlatformTransactionManager bean we don't have access to). + * + *

Allows behavior of an entire class to change with static delegate change. + * Not multi-threaded. + * + * @author Rod Johnson + * @since 26.04.2003 + */ +public class PlatformTransactionManagerFacade implements PlatformTransactionManager { + + /** + * This member can be changed to change behavior class-wide. + */ + public static PlatformTransactionManager delegate; + + public TransactionStatus getTransaction(TransactionDefinition definition) { + return delegate.getTransaction(definition); + } + + public void commit(TransactionStatus status) { + delegate.commit(status); + } + + public void rollback(TransactionStatus status) { + delegate.rollback(status); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RollbackRuleTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RollbackRuleTests.java new file mode 100644 index 00000000000..789ff37a158 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RollbackRuleTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.beans.FatalBeanException; +import org.springframework.mail.MailSendException; + +/** + * Unit tests for the {@link RollbackRuleAttribute} class. + * + * @author Rod Johnson + * @author Rick Evans + * @since 09.04.2003 + */ +public class RollbackRuleTests extends TestCase { + + public void testFoundImmediatelyWithString() { + RollbackRuleAttribute rr = new RollbackRuleAttribute("java.lang.Exception"); + assertTrue(rr.getDepth(new Exception()) == 0); + } + + public void testFoundImmediatelyWithClass() { + RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class); + assertTrue(rr.getDepth(new Exception()) == 0); + } + + public void testNotFound() { + RollbackRuleAttribute rr = new RollbackRuleAttribute("javax.servlet.ServletException"); + assertTrue(rr.getDepth(new MailSendException("")) == -1); + } + + public void testAncestry() { + RollbackRuleAttribute rr = new RollbackRuleAttribute("java.lang.Exception"); + // Exception -> Runtime -> NestedRuntime -> MailException -> MailSendException + assertTrue(rr.getDepth(new MailSendException("")) == 4); + } + + public void testAlwaysTrueForThrowable() { + RollbackRuleAttribute rr = new RollbackRuleAttribute("java.lang.Throwable"); + assertTrue(rr.getDepth(new MailSendException("")) > 0); + assertTrue(rr.getDepth(new ServletException()) > 0); + assertTrue(rr.getDepth(new FatalBeanException(null,null)) > 0); + assertTrue(rr.getDepth(new RuntimeException()) > 0); + } + + public void testCtorArgMustBeAThrowableClassWithNonThrowableType() { + try { + new RollbackRuleAttribute(StringBuffer.class); + fail("Cannot construct a RollbackRuleAttribute with a non-Throwable type"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorArgMustBeAThrowableClassWithNullThrowableType() { + try { + new RollbackRuleAttribute((Class) null); + fail("Cannot construct a RollbackRuleAttribute with a null-Throwable type"); + } + catch (IllegalArgumentException expected) { + } + } + + public void testCtorArgExceptionStringNameVersionWithNull() { + try { + new RollbackRuleAttribute((String) null); + fail("Cannot construct a RollbackRuleAttribute with a null-Throwable type"); + } + catch (IllegalArgumentException expected) { + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java new file mode 100644 index 00000000000..b147c23a912 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttributeTests.java @@ -0,0 +1,162 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.rmi.RemoteException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.mail.MailSendException; +import org.springframework.transaction.TransactionDefinition; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + * @since 09.04.2003 + */ +public class RuleBasedTransactionAttributeTests extends TestCase { + + public void testDefaultRule() { + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(); + assertTrue(rta.rollbackOn(new RuntimeException())); + assertTrue(rta.rollbackOn(new MailSendException(""))); + assertFalse(rta.rollbackOn(new Exception())); + assertFalse(rta.rollbackOn(new ServletException())); + } + + /** + * Test one checked exception that should roll back. + */ + public void testRuleForRollbackOnChecked() { + List list = new LinkedList(); + list.add(new RollbackRuleAttribute("javax.servlet.ServletException")); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list); + + assertTrue(rta.rollbackOn(new RuntimeException())); + assertTrue(rta.rollbackOn(new MailSendException(""))); + assertFalse(rta.rollbackOn(new Exception())); + // Check that default behaviour is overridden + assertTrue(rta.rollbackOn(new ServletException())); + } + + public void testRuleForCommitOnUnchecked() { + List list = new LinkedList(); + list.add(new NoRollbackRuleAttribute("org.springframework.mail.MailSendException")); + list.add(new RollbackRuleAttribute("javax.servlet.ServletException")); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list); + + assertTrue(rta.rollbackOn(new RuntimeException())); + // Check default behaviour is overridden + assertFalse(rta.rollbackOn(new MailSendException(""))); + assertFalse(rta.rollbackOn(new Exception())); + // Check that default behaviour is overridden + assertTrue(rta.rollbackOn(new ServletException())); + } + + public void testRuleForSelectiveRollbackOnCheckedWithString() { + List l = new LinkedList(); + l.add(new RollbackRuleAttribute("java.rmi.RemoteException")); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, l); + doTestRuleForSelectiveRollbackOnChecked(rta); + } + + public void testRuleForSelectiveRollbackOnCheckedWithClass() { + List l = Collections.singletonList(new RollbackRuleAttribute(RemoteException.class)); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, l); + doTestRuleForSelectiveRollbackOnChecked(rta); + } + + private void doTestRuleForSelectiveRollbackOnChecked(RuleBasedTransactionAttribute rta) { + assertTrue(rta.rollbackOn(new RuntimeException())); + // Check default behaviour is overridden + assertFalse(rta.rollbackOn(new Exception())); + // Check that default behaviour is overridden + assertTrue(rta.rollbackOn(new RemoteException())); + } + + /** + * Check that a rule can cause commit on a ServletException + * when Exception prompts a rollback. + */ + public void testRuleForCommitOnSubclassOfChecked() { + List list = new LinkedList(); + // Note that it's important to ensure that we have this as + // a FQN: otherwise it will match everything! + list.add(new RollbackRuleAttribute("java.lang.Exception")); + list.add(new NoRollbackRuleAttribute("ServletException")); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list); + + assertTrue(rta.rollbackOn(new RuntimeException())); + assertTrue(rta.rollbackOn(new Exception())); + // Check that default behaviour is overridden + assertFalse(rta.rollbackOn(new ServletException())); + } + + public void testRollbackNever() { + List list = new LinkedList(); + list.add(new NoRollbackRuleAttribute("Throwable")); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list); + + assertFalse(rta.rollbackOn(new Throwable())); + assertFalse(rta.rollbackOn(new RuntimeException())); + assertFalse(rta.rollbackOn(new MailSendException(""))); + assertFalse(rta.rollbackOn(new Exception())); + assertFalse(rta.rollbackOn(new ServletException())); + } + + public void testToStringMatchesEditor() { + List list = new LinkedList(); + list.add(new NoRollbackRuleAttribute("Throwable")); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list); + + TransactionAttributeEditor tae = new TransactionAttributeEditor(); + tae.setAsText(rta.toString()); + rta = (RuleBasedTransactionAttribute) tae.getValue(); + + assertFalse(rta.rollbackOn(new Throwable())); + assertFalse(rta.rollbackOn(new RuntimeException())); + assertFalse(rta.rollbackOn(new MailSendException(""))); + assertFalse(rta.rollbackOn(new Exception())); + assertFalse(rta.rollbackOn(new ServletException())); + } + + /** + * See this forum post. + */ + public void testConflictingRulesToDetermineExactContract() { + List list = new LinkedList(); + list.add(new NoRollbackRuleAttribute(MyBusinessWarningException.class)); + list.add(new RollbackRuleAttribute(MyBusinessException.class)); + RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list); + + assertTrue(rta.rollbackOn(new MyBusinessException())); + assertFalse(rta.rollbackOn(new MyBusinessWarningException())); + } + + + public static class MyBusinessException extends Exception {} + + + public static final class MyBusinessWarningException extends MyBusinessException {} + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeEditorTests.java new file mode 100644 index 00000000000..993bcf80fab --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeEditorTests.java @@ -0,0 +1,173 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.mail.MailSendException; +import org.springframework.transaction.TransactionDefinition; + +/** + * Tests to check conversion from String to TransactionAttribute. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 26.04.2003 + */ +public class TransactionAttributeEditorTests extends TestCase { + + public void testNull() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText(null); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertTrue(ta == null); + } + + public void testEmptyString() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText(""); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertTrue(ta == null); + } + + public void testValidPropagationCodeOnly() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText("PROPAGATION_REQUIRED"); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertTrue(ta != null); + assertTrue(ta.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED); + assertTrue(ta.getIsolationLevel() == TransactionDefinition.ISOLATION_DEFAULT); + assertTrue(!ta.isReadOnly()); + } + + public void testInvalidPropagationCodeOnly() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + try { + pe.setAsText("XXPROPAGATION_REQUIRED"); + fail("Should have failed with bogus propagation code"); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testValidPropagationCodeAndIsolationCode() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText("PROPAGATION_REQUIRED, ISOLATION_READ_UNCOMMITTED"); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertTrue(ta != null); + assertTrue(ta.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED); + assertTrue(ta.getIsolationLevel() == TransactionDefinition.ISOLATION_READ_UNCOMMITTED); + } + + public void testValidPropagationAndIsolationCodesAndInvalidRollbackRule() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + try { + pe.setAsText("PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED,XXX"); + fail("Should have failed with bogus rollback rule"); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testValidPropagationCodeAndIsolationCodeAndRollbackRules1() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText("PROPAGATION_MANDATORY,ISOLATION_REPEATABLE_READ,timeout_10,-ServletException,+MailSendException"); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertNotNull(ta); + assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_MANDATORY); + assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_REPEATABLE_READ); + assertEquals(ta.getTimeout(), 10); + assertFalse(ta.isReadOnly()); + assertTrue(ta.rollbackOn(new RuntimeException())); + assertFalse(ta.rollbackOn(new Exception())); + // Check for our bizarre customized rollback rules + assertTrue(ta.rollbackOn(new ServletException())); + assertTrue(!ta.rollbackOn(new MailSendException(""))); + } + + public void testValidPropagationCodeAndIsolationCodeAndRollbackRules2() { + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText("+ServletException,readOnly,ISOLATION_READ_COMMITTED,-MailSendException,PROPAGATION_SUPPORTS"); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertNotNull(ta); + assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_SUPPORTS); + assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_READ_COMMITTED); + assertEquals(ta.getTimeout(), TransactionDefinition.TIMEOUT_DEFAULT); + assertTrue(ta.isReadOnly()); + assertTrue(ta.rollbackOn(new RuntimeException())); + assertFalse(ta.rollbackOn(new Exception())); + // Check for our bizarre customized rollback rules + assertFalse(ta.rollbackOn(new ServletException())); + assertTrue(ta.rollbackOn(new MailSendException(""))); + } + + public void testDefaultTransactionAttributeToString() { + DefaultTransactionAttribute source = new DefaultTransactionAttribute(); + source.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + source.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); + source.setTimeout(10); + source.setReadOnly(true); + + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText(source.toString()); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertEquals(ta, source); + assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_SUPPORTS); + assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_REPEATABLE_READ); + assertEquals(ta.getTimeout(), 10); + assertTrue(ta.isReadOnly()); + assertTrue(ta.rollbackOn(new RuntimeException())); + assertFalse(ta.rollbackOn(new Exception())); + + source.setTimeout(9); + assertNotSame(ta, source); + source.setTimeout(10); + assertEquals(ta, source); + } + + public void testRuleBasedTransactionAttributeToString() { + RuleBasedTransactionAttribute source = new RuleBasedTransactionAttribute(); + source.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); + source.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); + source.setTimeout(10); + source.setReadOnly(true); + source.getRollbackRules().add(new RollbackRuleAttribute("IllegalArgumentException")); + source.getRollbackRules().add(new NoRollbackRuleAttribute("IllegalStateException")); + + TransactionAttributeEditor pe = new TransactionAttributeEditor(); + pe.setAsText(source.toString()); + TransactionAttribute ta = (TransactionAttribute) pe.getValue(); + assertEquals(ta, source); + assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_SUPPORTS); + assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_REPEATABLE_READ); + assertEquals(ta.getTimeout(), 10); + assertTrue(ta.isReadOnly()); + assertTrue(ta.rollbackOn(new IllegalArgumentException())); + assertFalse(ta.rollbackOn(new IllegalStateException())); + + source.getRollbackRules().clear(); + assertNotSame(ta, source); + source.getRollbackRules().add(new RollbackRuleAttribute("IllegalArgumentException")); + source.getRollbackRules().add(new NoRollbackRuleAttribute("IllegalStateException")); + assertEquals(ta, source); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisorTests.java new file mode 100644 index 00000000000..8911d31bb12 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisorTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.util.Properties; + +import org.springframework.util.SerializationTestUtils; + +import junit.framework.TestCase; + +/** + * + * @author Rod Johnson + */ +public class TransactionAttributeSourceAdvisorTests extends TestCase { + + public TransactionAttributeSourceAdvisorTests(String s) { + super(s); + } + + public void testSerializability() throws Exception { + TransactionInterceptor ti = new TransactionInterceptor(); + ti.setTransactionAttributes(new Properties()); + TransactionAttributeSourceAdvisor tas = new TransactionAttributeSourceAdvisor(ti); + SerializationTestUtils.serializeAndDeserialize(tas); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceEditorTests.java new file mode 100644 index 00000000000..1c74ff2e096 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceEditorTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.transaction.TransactionDefinition; + +/** + * Format is + * FQN.Method=tx attribute representation + * + * @author Rod Johnson + * @since 26.04.2003 + */ +public class TransactionAttributeSourceEditorTests extends TestCase { + + public void testNull() throws Exception { + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + pe.setAsText(null); + TransactionAttributeSource tas = (TransactionAttributeSource) pe.getValue(); + + Method m = Object.class.getMethod("hashCode", (Class[]) null); + assertTrue(tas.getTransactionAttribute(m, null) == null); + } + + public void testInvalid() throws Exception { + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + try { + pe.setAsText("foo=bar"); + fail(); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testMatchesSpecific() throws Exception { + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + // TODO need FQN? + pe.setAsText( + "java.lang.Object.hashCode=PROPAGATION_REQUIRED\n" + + "java.lang.Object.equals=PROPAGATION_MANDATORY\n" + + "java.lang.Object.*it=PROPAGATION_SUPPORTS\n" + + "java.lang.Object.notify=PROPAGATION_SUPPORTS\n" + + "java.lang.Object.not*=PROPAGATION_REQUIRED"); + TransactionAttributeSource tas = (TransactionAttributeSource) pe.getValue(); + + checkTransactionProperties(tas, Object.class.getMethod("hashCode", (Class[]) null), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("equals", new Class[] { Object.class }), + TransactionDefinition.PROPAGATION_MANDATORY); + checkTransactionProperties(tas, Object.class.getMethod("wait", (Class[]) null), + TransactionDefinition.PROPAGATION_SUPPORTS); + checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class }), + TransactionDefinition.PROPAGATION_SUPPORTS); + checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class, int.class }), + TransactionDefinition.PROPAGATION_SUPPORTS); + checkTransactionProperties(tas, Object.class.getMethod("notify", (Class[]) null), + TransactionDefinition.PROPAGATION_SUPPORTS); + checkTransactionProperties(tas, Object.class.getMethod("notifyAll", (Class[]) null), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("toString", (Class[]) null), -1); + } + + public void testMatchesAll() throws Exception { + TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor(); + pe.setAsText("java.lang.Object.*=PROPAGATION_REQUIRED"); + TransactionAttributeSource tas = (TransactionAttributeSource) pe.getValue(); + + checkTransactionProperties(tas, Object.class.getMethod("hashCode", (Class[]) null), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("equals", new Class[] { Object.class }), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("wait", (Class[]) null), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class }), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class, int.class }), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("notify", (Class[]) null), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("notifyAll", (Class[]) null), + TransactionDefinition.PROPAGATION_REQUIRED); + checkTransactionProperties(tas, Object.class.getMethod("toString", (Class[]) null), + TransactionDefinition.PROPAGATION_REQUIRED); + } + + private void checkTransactionProperties(TransactionAttributeSource tas, Method method, int propagationBehavior) { + TransactionAttribute ta = tas.getTransactionAttribute(method, null); + if (propagationBehavior >= 0) { + assertTrue(ta != null); + assertTrue(ta.getIsolationLevel() == TransactionDefinition.ISOLATION_DEFAULT); + assertTrue(ta.getPropagationBehavior() == propagationBehavior); + } + else { + assertTrue(ta == null); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceTests.java new file mode 100644 index 00000000000..5ffe826a9b7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionAttributeSourceTests.java @@ -0,0 +1,146 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.transaction.TransactionDefinition; + +/** + * Unit tests for the various {@link TransactionAttributeSource} implementations. + * + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @author Rick Evans + * @since 15.10.2003 + * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean + */ +public final class TransactionAttributeSourceTests extends TestCase { + + public void testMatchAlwaysTransactionAttributeSource() throws Exception { + MatchAlwaysTransactionAttributeSource tas = new MatchAlwaysTransactionAttributeSource(); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNotNull(ta); + assertTrue(TransactionDefinition.PROPAGATION_REQUIRED == ta.getPropagationBehavior()); + + tas.setTransactionAttribute(new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS)); + ta = tas.getTransactionAttribute( + ServletException.class.getMethod("getMessage", (Class[]) null), ServletException.class); + assertNotNull(ta); + assertTrue(TransactionDefinition.PROPAGATION_SUPPORTS == ta.getPropagationBehavior()); + } + + public void testMethodMapTransactionAttributeSource() throws NoSuchMethodException { + MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); + Map methodMap = new HashMap(); + methodMap.put(Object.class.getName() + ".hashCode", "PROPAGATION_REQUIRED"); + methodMap.put(Object.class.getName() + ".toString", + new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS)); + tas.setMethodMap(methodMap); + tas.afterPropertiesSet(); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior()); + ta = tas.getTransactionAttribute(Object.class.getMethod("toString", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_SUPPORTS, ta.getPropagationBehavior()); + } + + public void testMethodMapTransactionAttributeSourceWithLazyInit() throws NoSuchMethodException { + MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource(); + Map methodMap = new HashMap(); + methodMap.put(Object.class.getName() + ".hashCode", "PROPAGATION_REQUIRED"); + methodMap.put(Object.class.getName() + ".toString", + new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS)); + tas.setMethodMap(methodMap); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior()); + ta = tas.getTransactionAttribute(Object.class.getMethod("toString", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_SUPPORTS, ta.getPropagationBehavior()); + } + + public void testNameMatchTransactionAttributeSource() throws NoSuchMethodException { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + Map methodMap = new HashMap(); + methodMap.put("hashCode", "PROPAGATION_REQUIRED"); + methodMap.put("toString", new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS)); + tas.setNameMap(methodMap); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior()); + ta = tas.getTransactionAttribute(Object.class.getMethod("toString", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_SUPPORTS, ta.getPropagationBehavior()); + } + + public void testNameMatchTransactionAttributeSourceWithStarAtStartOfMethodName() throws NoSuchMethodException { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + Properties attributes = new Properties(); + attributes.put("*ashCode", "PROPAGATION_REQUIRED"); + tas.setProperties(attributes); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior()); + } + + public void testNameMatchTransactionAttributeSourceWithStarAtEndOfMethodName() throws NoSuchMethodException { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + Properties attributes = new Properties(); + attributes.put("hashCod*", "PROPAGATION_REQUIRED"); + tas.setProperties(attributes); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior()); + } + + public void testNameMatchTransactionAttributeSourceMostSpecificMethodNameIsDefinitelyMatched() throws NoSuchMethodException { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + Properties attributes = new Properties(); + attributes.put("*", "PROPAGATION_REQUIRED"); + attributes.put("hashCode", "PROPAGATION_MANDATORY"); + tas.setProperties(attributes); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNotNull(ta); + assertEquals(TransactionDefinition.PROPAGATION_MANDATORY, ta.getPropagationBehavior()); + } + + public void testNameMatchTransactionAttributeSourceWithEmptyMethodName() throws NoSuchMethodException { + NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); + Properties attributes = new Properties(); + attributes.put("", "PROPAGATION_MANDATORY"); + tas.setProperties(attributes); + TransactionAttribute ta = tas.getTransactionAttribute( + Object.class.getMethod("hashCode", (Class[]) null), null); + assertNull(ta); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionInterceptorTests.java new file mode 100644 index 00000000000..fbe4b9f6cee --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/TransactionInterceptorTests.java @@ -0,0 +1,126 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.interceptor; + +import java.io.Serializable; +import java.util.Properties; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.util.SerializationTestUtils; + +/** + * Mock object based tests for TransactionInterceptor. + * + * @author Rod Johnson + * @since 16.03.2003 + */ +public class TransactionInterceptorTests extends AbstractTransactionAspectTests { + + protected Object advised(Object target, PlatformTransactionManager ptm, TransactionAttributeSource[] tas) throws Exception { + TransactionInterceptor ti = new TransactionInterceptor(); + ti.setTransactionManager(ptm); + ti.setTransactionAttributeSources(tas); + + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(0, ti); + return pf.getProxy(); + } + + /** + * Template method to create an advised object given the + * target object and transaction setup. + * Creates a TransactionInterceptor and applies it. + */ + protected Object advised(Object target, PlatformTransactionManager ptm, TransactionAttributeSource tas) { + TransactionInterceptor ti = new TransactionInterceptor(); + ti.setTransactionManager(ptm); + assertEquals(ptm, ti.getTransactionManager()); + ti.setTransactionAttributeSource(tas); + assertEquals(tas, ti.getTransactionAttributeSource()); + + ProxyFactory pf = new ProxyFactory(target); + pf.addAdvice(0, ti); + return pf.getProxy(); + } + +/** + * A TransactionInterceptor should be serializable if its + * PlatformTransactionManager is. + */ + public void testSerializableWithAttributeProperties() throws Exception { + TransactionInterceptor ti = new TransactionInterceptor(); + Properties props = new Properties(); + props.setProperty("methodName", "PROPAGATION_REQUIRED"); + ti.setTransactionAttributes(props); + PlatformTransactionManager ptm = new SerializableTransactionManager(); + ti.setTransactionManager(ptm); + ti = (TransactionInterceptor) SerializationTestUtils.serializeAndDeserialize(ti); + + // Check that logger survived deserialization + assertNotNull(ti.logger); + assertTrue(ti.getTransactionManager() instanceof SerializableTransactionManager); + assertNotNull(ti.getTransactionAttributeSource()); + } + + public void testSerializableWithCompositeSource() throws Exception { + NameMatchTransactionAttributeSource tas1 = new NameMatchTransactionAttributeSource(); + Properties props = new Properties(); + props.setProperty("methodName", "PROPAGATION_REQUIRED"); + tas1.setProperties(props); + + NameMatchTransactionAttributeSource tas2 = new NameMatchTransactionAttributeSource(); + props = new Properties(); + props.setProperty("otherMethodName", "PROPAGATION_REQUIRES_NEW"); + tas2.setProperties(props); + + TransactionInterceptor ti = new TransactionInterceptor(); + ti.setTransactionAttributeSources(new TransactionAttributeSource[] {tas1, tas2}); + PlatformTransactionManager ptm = new SerializableTransactionManager(); + ti.setTransactionManager(ptm); + ti = (TransactionInterceptor) SerializationTestUtils.serializeAndDeserialize(ti); + + assertTrue(ti.getTransactionManager() instanceof SerializableTransactionManager); + assertTrue(ti.getTransactionAttributeSource() instanceof CompositeTransactionAttributeSource); + CompositeTransactionAttributeSource ctas = (CompositeTransactionAttributeSource) ti.getTransactionAttributeSource(); + assertTrue(ctas.getTransactionAttributeSources()[0] instanceof NameMatchTransactionAttributeSource); + assertTrue(ctas.getTransactionAttributeSources()[1] instanceof NameMatchTransactionAttributeSource); + } + + + /** + * We won't use this: we just want to know it's serializable. + */ + public static class SerializableTransactionManager implements PlatformTransactionManager, Serializable { + + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + throw new UnsupportedOperationException(); + } + + public void commit(TransactionStatus status) throws TransactionException { + throw new UnsupportedOperationException(); + } + + public void rollback(TransactionStatus status) throws TransactionException { + throw new UnsupportedOperationException(); + } + + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/noTransactionAttributeSource.xml b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/noTransactionAttributeSource.xml new file mode 100644 index 00000000000..09c860fffd5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/noTransactionAttributeSource.xml @@ -0,0 +1,23 @@ + + + + + + + + custom + 666 + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/transactionalBeanFactory.xml b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/transactionalBeanFactory.xml new file mode 100644 index 00000000000..942a13ddbef --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/interceptor/transactionalBeanFactory.xml @@ -0,0 +1,137 @@ + + + + + + + dependency + + + + + custom + 666 + + + + + + + + + + + + org.springframework.beans.ITestBean.s*=PROPAGATION_MANDATORY + org.springframework.beans.ITestBean.setAg*=PROPAGATION_REQUIRED + org.springframework.beans.ITestBean.set*= PROPAGATION_SUPPORTS , readOnly + + + + + + + org.springframework.beans.ITestBean + + + + txInterceptor + target + + + + + + + + + PROPAGATION_MANDATORY + PROPAGATION_REQUIRED , readOnly + PROPAGATION_SUPPORTS + + + + + + + + + + + true + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + PROPAGATION_REQUIRED + + + + + + + + + + + + + + + + PROPAGATION_MANDATORY + PROPAGATION_REQUIRED + PROPAGATION_SUPPORTS + + + true + false + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/MockUOWManager.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/MockUOWManager.java new file mode 100644 index 00000000000..94ca9025802 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/MockUOWManager.java @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.jta; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.transaction.Synchronization; + +import com.ibm.wsspi.uow.UOWAction; +import com.ibm.wsspi.uow.UOWActionException; +import com.ibm.wsspi.uow.UOWException; +import com.ibm.wsspi.uow.UOWManager; + +/** + * @author Juergen Hoeller + */ +public class MockUOWManager implements UOWManager { + + private int type = UOW_TYPE_GLOBAL_TRANSACTION; + + private boolean joined; + + private int timeout; + + private boolean rollbackOnly; + + private int status = UOW_STATUS_NONE; + + private final Map resources = new HashMap(); + + private final List synchronizations = new LinkedList(); + + + public void runUnderUOW(int type, boolean join, UOWAction action) throws UOWActionException, UOWException { + this.type = type; + this.joined = join; + try { + this.status = UOW_STATUS_ACTIVE; + action.run(); + this.status = (this.rollbackOnly ? UOW_STATUS_ROLLEDBACK : UOW_STATUS_COMMITTED); + } + catch (Error err) { + this.status = UOW_STATUS_ROLLEDBACK; + throw err; + } + catch (RuntimeException ex) { + this.status = UOW_STATUS_ROLLEDBACK; + throw ex; + } + catch (Exception ex) { + this.status = UOW_STATUS_ROLLEDBACK; + throw new UOWActionException(ex); + } + } + + public int getUOWType() { + return this.type; + } + + public boolean getJoined() { + return this.joined; + } + + public long getLocalUOWId() { + return 0; + } + + public void setUOWTimeout(int uowType, int timeout) { + this.timeout = timeout; + } + + public int getUOWTimeout() { + return this.timeout; + } + + public void setRollbackOnly() { + this.rollbackOnly = true; + } + + public boolean getRollbackOnly() { + return this.rollbackOnly; + } + + public void setUOWStatus(int status) { + this.status = status; + } + + public int getUOWStatus() { + return this.status; + } + + public void putResource(Object key, Object value) { + this.resources.put(key, value); + } + + public Object getResource(Object key) throws NullPointerException { + return this.resources.get(key); + } + + public void registerInterposedSynchronization(Synchronization sync) { + this.synchronizations.add(sync); + } + + public List getSynchronizations() { + return this.synchronizations; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java new file mode 100644 index 00000000000..8c80f0f0131 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java @@ -0,0 +1,629 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.jta; + +import javax.transaction.RollbackException; +import javax.transaction.Status; +import javax.transaction.UserTransaction; + +import com.ibm.wsspi.uow.UOWAction; +import com.ibm.wsspi.uow.UOWException; +import com.ibm.wsspi.uow.UOWManager; +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.mock.jndi.ExpectedLookupTemplate; +import org.springframework.transaction.IllegalTransactionStateException; +import org.springframework.transaction.NestedTransactionNotSupportedException; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.TransactionSystemException; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * @author Juergen Hoeller + */ +public class WebSphereUowTransactionManagerTests extends TestCase { + + public void testUowManagerFoundInJndi() { + MockUOWManager manager = new MockUOWManager(); + ExpectedLookupTemplate jndiTemplate = + new ExpectedLookupTemplate(WebSphereUowTransactionManager.DEFAULT_UOW_MANAGER_NAME, manager); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(); + ptm.setJndiTemplate(jndiTemplate); + ptm.afterPropertiesSet(); + + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return "result"; + } + })); + + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testUowManagerAndUserTransactionFoundInJndi() throws Exception { + MockControl utControl = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utControl.getMock(); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); + ut.getStatus(); + utControl.setReturnValue(Status.STATUS_ACTIVE, 2); + ut.begin(); + utControl.setVoidCallable(1); + ut.commit(); + utControl.setVoidCallable(1); + utControl.replay(); + + MockUOWManager manager = new MockUOWManager(); + ExpectedLookupTemplate jndiTemplate = new ExpectedLookupTemplate(); + jndiTemplate.addObject(WebSphereUowTransactionManager.DEFAULT_USER_TRANSACTION_NAME, ut); + jndiTemplate.addObject(WebSphereUowTransactionManager.DEFAULT_UOW_MANAGER_NAME, manager); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(); + ptm.setJndiTemplate(jndiTemplate); + ptm.afterPropertiesSet(); + + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + TransactionStatus ts = ptm.getTransaction(definition); + ptm.commit(ts); + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return "result"; + } + })); + + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testPropagationMandatoryFailsInCaseOfNoExistingTransaction() { + MockUOWManager manager = new MockUOWManager(); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY); + + try { + ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return "result"; + } + }); + fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + } + + public void testNewTransactionSynchronizationUsingPropagationSupports() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_SUPPORTS, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS); + } + + public void testNewTransactionSynchronizationUsingPropagationNotSupported() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_NOT_SUPPORTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS); + } + + public void testNewTransactionSynchronizationUsingPropagationNever() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_NEVER, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS); + } + + public void testNewTransactionSynchronizationUsingPropagationSupportsAndSynchOnActual() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_SUPPORTS, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + } + + public void testNewTransactionSynchronizationUsingPropagationNotSupportedAndSynchOnActual() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_NOT_SUPPORTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + } + + public void testNewTransactionSynchronizationUsingPropagationNeverAndSynchOnActual() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_NEVER, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + } + + public void testNewTransactionSynchronizationUsingPropagationSupportsAndSynchNever() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_SUPPORTS, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER); + } + + public void testNewTransactionSynchronizationUsingPropagationNotSupportedAndSynchNever() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_NOT_SUPPORTED, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER); + } + + public void testNewTransactionSynchronizationUsingPropagationNeverAndSynchNever() { + doTestNewTransactionSynchronization( + TransactionDefinition.PROPAGATION_NEVER, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER); + } + + private void doTestNewTransactionSynchronization(int propagationBehavior, final int synchMode) { + MockUOWManager manager = new MockUOWManager(); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + ptm.setTransactionSynchronization(synchMode); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + definition.setPropagationBehavior(propagationBehavior); + definition.setReadOnly(true); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + if (synchMode == WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + else { + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_LOCAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testNewTransactionWithCommitUsingPropagationRequired() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_REQUIRED, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS); + } + + public void testNewTransactionWithCommitUsingPropagationRequiresNew() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_REQUIRES_NEW, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS); + } + + public void testNewTransactionWithCommitUsingPropagationNested() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_NESTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS); + } + + public void testNewTransactionWithCommitUsingPropagationRequiredAndSynchOnActual() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_REQUIRED, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + } + + public void testNewTransactionWithCommitUsingPropagationRequiresNewAndSynchOnActual() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_REQUIRES_NEW, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + } + + public void testNewTransactionWithCommitUsingPropagationNestedAndSynchOnActual() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_NESTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION); + } + + public void testNewTransactionWithCommitUsingPropagationRequiredAndSynchNever() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_REQUIRED, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER); + } + + public void testNewTransactionWithCommitUsingPropagationRequiresNewAndSynchNever() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_REQUIRES_NEW, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER); + } + + public void testNewTransactionWithCommitUsingPropagationNestedAndSynchNever() { + doTestNewTransactionWithCommit( + TransactionDefinition.PROPAGATION_NESTED, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER); + } + + private void doTestNewTransactionWithCommit(int propagationBehavior, final int synchMode) { + MockUOWManager manager = new MockUOWManager(); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + ptm.setTransactionSynchronization(synchMode); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + definition.setPropagationBehavior(propagationBehavior); + definition.setReadOnly(true); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + if (synchMode != WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + else { + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + } + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testNewTransactionWithCommitAndTimeout() { + MockUOWManager manager = new MockUOWManager(); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + definition.setTimeout(10); + definition.setReadOnly(true); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(10, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testNewTransactionWithCommitException() { + final RollbackException rex = new RollbackException(); + MockUOWManager manager = new MockUOWManager() { + public void runUnderUOW(int type, boolean join, UOWAction action) throws UOWException { + throw new UOWException(rex); + } + }; + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + try { + ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + return "result"; + } + }); + fail("Should have thrown TransactionSystemException"); + } + catch (TransactionSystemException ex) { + // expected + assertTrue(ex.getCause() instanceof UOWException); + assertSame(rex, ex.getRootCause()); + assertSame(rex, ex.getMostSpecificCause()); + } + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + } + + public void testNewTransactionWithRollback() { + MockUOWManager manager = new MockUOWManager(); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + try { + ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + throw new OptimisticLockingFailureException(""); + } + }); + fail("Should have thrown OptimisticLockingFailureException"); + } + catch (OptimisticLockingFailureException ex) { + // expected + } + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testNewTransactionWithRollbackOnly() { + MockUOWManager manager = new MockUOWManager(); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + status.setRollbackOnly(); + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertTrue(manager.getRollbackOnly()); + } + + public void testExistingNonSpringTransaction() { + MockUOWManager manager = new MockUOWManager(); + manager.setUOWStatus(UOWManager.UOW_STATUS_ACTIVE); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertTrue(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testPropagationNeverFailsInCaseOfExistingTransaction() { + MockUOWManager manager = new MockUOWManager(); + manager.setUOWStatus(UOWManager.UOW_STATUS_ACTIVE); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER); + + try { + ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return "result"; + } + }); + fail("Should have thrown IllegalTransactionStateException"); + } + catch (IllegalTransactionStateException ex) { + // expected + } + } + + public void testPropagationNestedFailsInCaseOfExistingTransaction() { + MockUOWManager manager = new MockUOWManager(); + manager.setUOWStatus(UOWManager.UOW_STATUS_ACTIVE); + WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); + + try { + ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + return "result"; + } + }); + fail("Should have thrown NestedTransactionNotSupportedException"); + } + catch (NestedTransactionNotSupportedException ex) { + // expected + } + } + + public void testExistingTransactionWithParticipationUsingPropagationRequired() { + doTestExistingTransactionWithParticipation(TransactionDefinition.PROPAGATION_REQUIRED); + } + + public void testExistingTransactionWithParticipationUsingPropagationSupports() { + doTestExistingTransactionWithParticipation(TransactionDefinition.PROPAGATION_SUPPORTS); + } + + public void testExistingTransactionWithParticipationUsingPropagationMandatory() { + doTestExistingTransactionWithParticipation(TransactionDefinition.PROPAGATION_MANDATORY); + } + + private void doTestExistingTransactionWithParticipation(int propagationBehavior) { + MockUOWManager manager = new MockUOWManager(); + final WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + final DefaultTransactionDefinition definition2 = new DefaultTransactionDefinition(); + definition2.setPropagationBehavior(propagationBehavior); + definition2.setReadOnly(true); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertEquals("result2", ptm.execute(definition2, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + return "result2"; + } + })); + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + assertTrue(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testExistingTransactionWithSuspensionUsingPropagationRequiresNew() { + doTestExistingTransactionWithSuspension(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + } + + public void testExistingTransactionWithSuspensionUsingPropagationNotSupported() { + doTestExistingTransactionWithSuspension(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + } + + private void doTestExistingTransactionWithSuspension(final int propagationBehavior) { + MockUOWManager manager = new MockUOWManager(); + final WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + final DefaultTransactionDefinition definition2 = new DefaultTransactionDefinition(); + definition2.setPropagationBehavior(propagationBehavior); + definition2.setReadOnly(true); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertEquals("result2", ptm.execute(definition2, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertEquals(propagationBehavior == TransactionDefinition.PROPAGATION_REQUIRES_NEW, + TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + return "result2"; + } + })); + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + if (propagationBehavior == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { + assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType()); + } + else { + assertEquals(UOWManager.UOW_TYPE_LOCAL_TRANSACTION, manager.getUOWType()); + } + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + + public void testExistingTransactionUsingPropagationNotSupported() { + MockUOWManager manager = new MockUOWManager(); + final WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager); + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); + final DefaultTransactionDefinition definition2 = new DefaultTransactionDefinition(); + definition2.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); + definition2.setReadOnly(true); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals("result", ptm.execute(definition, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + assertEquals("result2", ptm.execute(definition2, new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + return "result2"; + } + })); + return "result"; + } + })); + + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); + assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); + + assertEquals(0, manager.getUOWTimeout()); + assertEquals(UOWManager.UOW_TYPE_LOCAL_TRANSACTION, manager.getUOWType()); + assertFalse(manager.getJoined()); + assertFalse(manager.getRollbackOnly()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/support/JtaTransactionManagerSerializationTests.java b/org.springframework.testsuite/src/test/java/org/springframework/transaction/support/JtaTransactionManagerSerializationTests.java new file mode 100644 index 00000000000..19513be7ee8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/support/JtaTransactionManagerSerializationTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.support; + +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.jndi.SimpleNamingContextBuilder; +import org.springframework.transaction.jta.JtaTransactionManager; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rod Johnson + */ +public class JtaTransactionManagerSerializationTests extends TestCase { + + public void testSerializable() throws Exception { + MockControl utMock = MockControl.createControl(UserTransaction.class); + UserTransaction ut = (UserTransaction) utMock.getMock(); + MockControl ut2Mock = MockControl.createControl(UserTransaction.class); + UserTransaction ut2 = (UserTransaction) ut2Mock.getMock(); + MockControl tmMock = MockControl.createControl(TransactionManager.class); + TransactionManager tm = (TransactionManager) tmMock.getMock(); + + JtaTransactionManager jtam = new JtaTransactionManager(); + jtam.setUserTransaction(ut); + jtam.setTransactionManager(tm); + jtam.setRollbackOnCommitFailure(true); + jtam.afterPropertiesSet(); + + SimpleNamingContextBuilder jndiEnv = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); + jndiEnv.bind(JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME, ut2); + JtaTransactionManager serializedJtatm = + (JtaTransactionManager) SerializationTestUtils.serializeAndDeserialize(jtam); + + // should do client-side lookup + assertNotNull("Logger must survive serialization", serializedJtatm.logger); + assertTrue("UserTransaction looked up on client", serializedJtatm.getUserTransaction() == ut2); + assertNull("TransactionManager didn't survive", serializedJtatm.getTransactionManager()); + assertEquals(true, serializedJtatm.isRollbackOnCommitFailure()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/transaction/txNamespaceHandlerTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/transaction/txNamespaceHandlerTests.xml new file mode 100644 index 00000000000..0a4b7e9f1c5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/transaction/txNamespaceHandlerTests.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/ModelMapTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ui/ModelMapTests.java new file mode 100644 index 00000000000..5d41de4f58d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/ModelMapTests.java @@ -0,0 +1,280 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ui; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.TestBean; +import org.springframework.test.AssertThrows; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public final class ModelMapTests extends TestCase { + + public void testNoArgCtorYieldsEmptyModel() throws Exception { + assertEquals(0, new ModelMap().size()); + } + + /* + * SPR-2185 - Null model assertion causes backwards compatibility issue + */ + public void testAddNullObjectWithExplicitKey() throws Exception { + ModelMap model = new ModelMap(); + model.addAttribute("foo", null); + assertTrue(model.containsKey("foo")); + assertNull(model.get("foo")); + } + + /* + * SPR-2185 - Null model assertion causes backwards compatibility issue + */ + public void testAddNullObjectViaCtorWithExplicitKey() throws Exception { + ModelMap model = new ModelMap("foo", null); + assertTrue(model.containsKey("foo")); + assertNull(model.get("foo")); + } + + public void testNamedObjectCtor() throws Exception { + ModelMap model = new ModelMap("foo", "bing"); + assertEquals(1, model.size()); + String bing = (String) model.get("foo"); + assertNotNull(bing); + assertEquals("bing", bing); + } + + public void testUnnamedCtorScalar() throws Exception { + ModelMap model = new ModelMap("foo", "bing"); + assertEquals(1, model.size()); + String bing = (String) model.get("foo"); + assertNotNull(bing); + assertEquals("bing", bing); + } + + public void testOneArgCtorWithScalar() throws Exception { + ModelMap model = new ModelMap("bing"); + assertEquals(1, model.size()); + String string = (String) model.get("string"); + assertNotNull(string); + assertEquals("bing", string); + } + + public void testOneArgCtorWithNull() throws Exception { + new AssertThrows(IllegalArgumentException.class, "Null model arguments added without a name being explicitly supplied are not allowed.") { + public void test() throws Exception { + new ModelMap(null); + } + }.runTest(); + } + + public void testOneArgCtorWithCollection() throws Exception { + ModelMap model = new ModelMap(new String[]{"foo", "boing"}); + assertEquals(1, model.size()); + String[] strings = (String[]) model.get("stringList"); + assertNotNull(strings); + assertEquals(2, strings.length); + assertEquals("foo", strings[0]); + assertEquals("boing", strings[1]); + } + + public void testOneArgCtorWithEmptyCollection() throws Exception { + ModelMap model = new ModelMap(new HashSet()); + // must not add if collection is empty... + assertEquals(0, model.size()); + } + + public void testAddObjectWithNull() throws Exception { + new AssertThrows(IllegalArgumentException.class, "Null model arguments added without a name being explicitly supplied are not allowed.") { + public void test() throws Exception { + ModelMap model = new ModelMap(); + model.addAttribute(null); + } + }.runTest(); + } + + public void testAddObjectWithEmptyArray() throws Exception { + ModelMap model = new ModelMap(new int[]{}); + assertEquals(1, model.size()); + int[] ints = (int[]) model.get("intList"); + assertNotNull(ints); + assertEquals(0, ints.length); + } + + public void testAddAllObjectsWithNullMap() throws Exception { + ModelMap model = new ModelMap(); + model.addAllAttributes((Map) null); + assertEquals(0, model.size()); + } + + public void testAddAllObjectsWithNullCollection() throws Exception { + ModelMap model = new ModelMap(); + model.addAllAttributes((Collection) null); + assertEquals(0, model.size()); + } + + public void testAddAllObjectsWithSparseArrayList() throws Exception { + new AssertThrows(IllegalArgumentException.class, "Null model arguments added without a name being explicitly supplied are not allowed.") { + public void test() throws Exception { + ModelMap model = new ModelMap(); + ArrayList list = new ArrayList(); + list.add("bing"); + list.add(null); + model.addAllAttributes(list); + } + }.runTest(); + } + + public void testAddMap() throws Exception { + Map map = new HashMap(); + map.put("one", "one-value"); + map.put("two", "two-value"); + ModelMap model = new ModelMap(); + model.addAttribute(map); + assertEquals(1, model.size()); + String key = StringUtils.uncapitalize(ClassUtils.getShortName(map.getClass())); + assertTrue(model.containsKey(key)); + } + + public void testAddObjectNoKeyOfSameTypeOverrides() throws Exception { + ModelMap model = new ModelMap(); + model.addAttribute("foo"); + model.addAttribute("bar"); + assertEquals(1, model.size()); + String bar = (String) model.get("string"); + assertEquals("bar", bar); + } + + public void testAddListOfTheSameObjects() throws Exception { + List beans = new ArrayList(); + beans.add(new TestBean("one")); + beans.add(new TestBean("two")); + beans.add(new TestBean("three")); + ModelMap model = new ModelMap(); + model.addAllAttributes(beans); + assertEquals(1, model.size()); + } + + public void testMergeMapWithOverriding() throws Exception { + Map beans = new HashMap(); + beans.put("one", new TestBean("one")); + beans.put("two", new TestBean("two")); + beans.put("three", new TestBean("three")); + ModelMap model = new ModelMap(); + model.put("one", new TestBean("oneOld")); + model.mergeAttributes(beans); + assertEquals(3, model.size()); + assertEquals("oneOld", ((TestBean) model.get("one")).getName()); + } + + public void testInnerClass() throws Exception { + ModelMap map = new ModelMap(); + SomeInnerClass inner = new SomeInnerClass(); + map.addAttribute(inner); + assertSame(inner, map.get("someInnerClass")); + } + + public void testInnerClassWithTwoUpperCaseLetters() throws Exception { + ModelMap map = new ModelMap(); + UKInnerClass inner = new UKInnerClass(); + map.addAttribute(inner); + assertSame(inner, map.get("UKInnerClass")); + } + + public void testAopCglibProxy() throws Exception { + ModelMap map = new ModelMap(); + ProxyFactory factory = new ProxyFactory(); + Date date = new Date(); + factory.setTarget(date); + factory.setProxyTargetClass(true); + map.addAttribute(factory.getProxy()); + assertTrue(map.containsKey("date")); + assertEquals(date, map.get("date")); + } + + public void testAopJdkProxy() throws Exception { + ModelMap map = new ModelMap(); + ProxyFactory factory = new ProxyFactory(); + Map target = new HashMap(); + factory.setTarget(target); + factory.addInterface(Map.class); + Object proxy = factory.getProxy(); + map.addAttribute(proxy); + assertSame(proxy, map.get("map")); + } + + public void testAopJdkProxyWithMultipleInterfaces() throws Exception { + ModelMap map = new ModelMap(); + Map target = new HashMap(); + ProxyFactory factory = new ProxyFactory(); + factory.setTarget(target); + factory.addInterface(Serializable.class); + factory.addInterface(Cloneable.class); + factory.addInterface(Comparable.class); + factory.addInterface(Map.class); + Object proxy = factory.getProxy(); + map.addAttribute(proxy); + assertSame(proxy, map.get("map")); + } + + public void testAopJdkProxyWithDetectedInterfaces() throws Exception { + ModelMap map = new ModelMap(); + Map target = new HashMap(); + ProxyFactory factory = new ProxyFactory(target); + Object proxy = factory.getProxy(); + map.addAttribute(proxy); + assertSame(proxy, map.get("map")); + } + + public void testRawJdkProxy() throws Exception { + ModelMap map = new ModelMap(); + Object proxy = Proxy.newProxyInstance( + getClass().getClassLoader(), + new Class[] {Map.class}, + new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) { + return "proxy"; + } + }); + map.addAttribute(proxy); + assertSame(proxy, map.get("map")); + } + + + private static class SomeInnerClass { + } + + + private static class UKInnerClass { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/DataSourceReport.jasper b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/DataSourceReport.jasper new file mode 100644 index 0000000000000000000000000000000000000000..8414447e09db656cb73537e527808a0856f81a0d GIT binary patch literal 18664 zcmeHOdwg6~o&TMi*EE@?ZTf^l4Y8$3+9rJ=kCsQ0Che5TgGtgtDyBCxH_dG)GsB&m z7qVIu1>X-qK|!miSnayvLJQ(*Sx^*36vYKsfdzG0cXic$xSw5J_WL{Mz9uut47z?k z`^V<&bwtx;K&YU1hfjF~ic>9%guis)f|Qg1cWt^I~&>PhojeI#k@h|&^gSdTt#^iPbA zn$tGbsliD-b*Q!9w#?Ka3|#08v^tV{HhT@dfwXChHqD3Ih@J(4v39&>BiIn3@JQOW z)8pN`g^ffQ-{i!2sv|v-vLn12*ZMPh9LsyX`^|(sHbjffL#ec7^y!$X+h#g7L`%(V zS2C^J9dce*I&B*k56t#YjF0QqOph^z;l>cvn%M!<~up))p64SlhYujV!z(BSgpilzKWDPrO zQ{#ampcx|!1@xMPF{)1_?XGmnwyC+uJavpbmJxHN_S-W_!=`mb=E`B1R+%tt-Ap=I zSBwG}P~K1s<(#Ff&2cFO{RWU;q}X-BHk06P#w^6FJAvbpY#OCnu&m9;pF_l&aotQg zl(1=i5%hhMm8T#p4rIw8IZz#*2^>simI;JCo?C2>E{UqLifJW{qEuls!^+BZ1~R@C zKcR$OD^qW3L_^tLBCVf$8u8mIGWdi3*z$^Gln+BOOYumQ{H;UwH~2q|lZKvRcxE-3!M)@!RWfyg(xnp^8a8Ibq;D7W?CRCV;T@))Tj$U31Ix@6d=O--L64Ih%gG z-a7i!9sl`D02^|FWr*=uHS1whWk+Vq*7LU7v|x{soHT4Ru4jZzVTtN+Pud#Slgx6Z zvIeU-pV`VHR5>QKtyI(fnWSmAC6nnXBLSw7DtA8=YUgyuGO}4{=;8{?AG-q-+EyaR zb|#H+Sb^O*T$VTdNm&4Q#K+8J!a^S{4rraInUxCB2+Xr-V-bc9uCimA$+lFUAS<$# zHp|jy81D4-Po91Iqxzj?eAeYzaJD?l@~Lv5RgFoTOWf3eF>QC5MlwL~g)p=u>GY9t z-8vFACXHk})f&uB(*6yY<3>9z8iVCxmOe57OKsTgw9s!s*AOk2(qP!}vHhk!);nof zqd2oDEz?u+v9!f}?jHlQ)Y(y5zPPO>jmvlmCf1~?8?y9B`)t%rN3oGjHQ2XaRv^qT7E z(-W?0T0D<3%c3ZS*6>S zv)4uJ$mQ>}hMRNuS;HFI@hu(vagsqwu#$e|dK-r%eZd^G76+PwClHqHxrl|VwDLV2 ztk{{%0aoiZ1VL4!H5bqlNFi(IS?2^6Z7GpO^VoA~Ks&F5Rb&r1lIk+8ti68>=96`~ zR0gsK?wX<7Mq(cur|b}&>C9jO+9e%8S5cr78YE_nrzedl&V@%vS!<_oCY?3e6=&}m z&Ux0hSj}(^c5jMb#CISbjrB zT|k4>bGz#HCN%p3Nhbnq0ML9KLkWB}@UPm&~y zCtwF9ytxDA*lc*?S3U8pdHG#~u6ravt=E()9i9=AxcS@E+NsWzI%?NlP$eeHOk(z^)hxGfC{n>jYzQoiyi2Ke2vN) zBeX}#2EBar=uw|Rglt?UG7uRRbk8F)fuQ?sAARjP&o9_2Txlue73w5IE%c)mZd``# zhh@h~!S#8@D=1nxoY^-5}yK!mcy2i-f8G_RR37`hXws1Ofm zm$LxKbAD{zFIm-9Bh3j1!5WSfg%HGOTnJBND)yW2Zs-n0cwuZH^c z=={XU-Q4BCZ`FL8%h`@!;f-m^rn-!<(%YEN2+RL~eTb&H4pWN#PQhVjsV<|c3VvG5$fhT(xY2DQ9#0)&$BZ=)N13JMyJR>DC02QeBkfXVxKW^= zh&sSoS_?5I;xIsHF6LGAxr5{V$BqfU9aF_ z?7u(^CB52_09F}2Sd`jq+%hxB@Y#N99g2NYNB##%dTgqx*rxV5W06J>0*YN_8s|~$ zit^gd=N|28{!PZ!>E&RKjU}4MS*ZlRaYz_yC$P25*K90PerB$)^9HKV;TcKUyoq%* z11Z4P-hjEi2X9Du+_Z5}dG19iv{F2G*LEIVBOdAJ zs~moBs#A}Tae88imT(`k^ITJjJav&_>z0jM3-}GV8BrNBr-?^KXyv$>QkNA2>Ha{E zyt~1zipwOpA1K1-?ntm~e!8Vb3TsZzTQvo4BZ4QdoDl4OCn(lhB6qnM_(ZEg{D*ip zK9Q8kDWsvyRNRtzI#xSF#7WtitZj@VfP)j5fa?cwGi>fHw2xYEzC0f0*mY4_?X?;0#PB9J!79BAo#b!h7U=l=oN&P5Ur-Ff<|an=7_Lq_AQloo{u8yH6qdD7H7 zau`mwoa8%FWloNg0Tys0UdEsA7JSyVk1SZFURi+6k>%h-kP| zu-flMizu+R#DS;ex+L5Zb@8*QN?uadUnIAi>k_O1+;9C6zvtW{Ah?ANV$t4?wkU8?zLUJ1il$+SRm|nkW`#32)~U8I z+&;QR)caxou>baxI9_4Z(1oj;H7p@!0_ob{GE>vcri`um5Yy=}WX zV>nYeN#2x7qa982HGFWTGo5*ZvFPxgHbyZv+||}G&>OqTrg}M@Nsn%XkA^g=P{lk&nJ-xBcVZ^49o;Jl>0UPgJ z)jI1V8EaFG5@Go*i+eb7=PK?E4h=ECbm3c|LgR|0*7nA7f*xOdVPu%e4YL~02sw6c&6sllB_7kJzY5F-mEjAYLlY%(|X}gpN zGel1INbqc{Mad8scJxLEyL+5GL=YyNL4^(j)Jg;xz@exITp|;w(u-+U>)W%2;osq@FnNxXcnKkY!v$d4;#xnD~? z68~RH@y)q8Z!5V4&~J8%Z<)8TKWU1u5h*^VxPR2aeD(vtE8jm?%&eU7ZQHhCD-1y% z<)8!>>~c3MJ3beLCoimc=Ox19_|IAED=t*E^woaV84w7+w8*XkYd?;4`NHgvT03W1 zNrb?<<$UK@U}g7i>`%9HB|9UA?FMs>Lh?_zNTAI};-BcKyGdV|*W~5*1H$i(=XrAb ze8IDVIVAs>>RjNw<}Ass^#s5%w^~sz2GDq&UbQZV+RO4#^{*C0VN`2hIjV~apgNxy z<>4uhs7q$q=e*v>3=y;`$5MLoj?-09^}~lAUUBfdWu$fCgJ`(TD))u2p6xLtvG9FIVmfo_ zWfHgWR0!|IT%Klr5Hkfj;IC;1+E4t;%KxYg4Lt8SVrP8)vH$+!mocw}ekN$0AI2yu z3~$+T-nOkkdI@=fMqzAOat6xc3Xg0S8^snSpk7Vdn)qg3ik83`B#1 zR_1l9m`u>xyq*Gqji6WM4a<#s1+C5-(b4Nhxq|BaUN@8ww8n2N6u%VORUlR>L=i7= zE!62n(1OD9f@v7BE0m(3mQv4AU3v(rR`dBwB-a-4oJi`U_XvwVpwXsOrkyT`%NL7!F7DsQxx>ruIeARz8i2`WLA zJ2``WiJ-E^rhS6SJMg7an9iYwYAUC-VXC0Y1-R}#H%wKk)EK6aDm8~`fhuhbQ?)9! zgsDcAHis#!N?XIUP?ffasaBO<6Nc*{Azu)N`jDlI!n8z{c7~}=l`aX>QdPPv41K?x zacK|J3RT(_rj@GH6{c0Hv?okw(3w1LZ#z{LNAQhmh~5WE2UJ&xZWb~hSjtI))8yTA72OJg=V+}EeGnShJzLgSA-WxW>uahI zeHbHxIx0kWLbhgUrx1M<(|o-YqK|>@&UfM9;N^{x0(^-nozrmx`C=rJz+{}VYn6=4 z|BErjLR&?j!nyh#&b?U`eHt_ZP{`Xk^qFcpPM^hs5DFP+2k0-P z5V~WbIU`}ZhrYmI{<50h$^9}zs*q7hxGFjcDfKZ?t?l?XI|E+I{Wz%l`Vf7Q_ZpBu zHEM^#^GntA0R5GqD)w%S-qGR$>`V{SSLk##ouY@pVR{B%s==sjEVNGE(h9*HVS1Pz z;pM*yL|cI9qacBet7ZO=z}e*TR{aJ&#&f<|O(~{{{5mH@--i0h+SV-Wok>BmdvLx( z-({8fB)&bu(%;8?e4P`bAAqX^-$#Y$X+ibHzHkcB4>8SUt==RkQG;_wK^}dWeyq;; zSw6^T!94EJ&a7>Y^JmOx!vwGDOnX61dl5{ju2mqK2AE5O9VM6~eAP#lC~0g+IPJ8zq$$4Nx#~P>a<_og6g$?bsMVJ`PK7KeS=>;AJwCN z^+HtN)k{&m$*;EgM7RXoCfb8%1P8JgguR@0QWVc_kg^BfwG}uS!kI6^5^LxnP}70h2$qDiTdI^-Kc)ZulAyP zhhMz{)sOhqepHY7)j?E0?pFic-2e$BIt=`d0KcT<$(`W&%P9@gWk9-XfaP8E31Iw5 zj4Vg(ZkE-uVU)|DfTl$E>d)Y9p_l(w;x~@p41RCH?|t~)iQjSj?!)gP{5Yfb41Pa_ zkYT)7hu;u>WB5(tcLRR!$L|<^$ODS!@Ix+4TZ`Y|gLM3=@>6u8`)={OK>1gJ@=v&2 zrp7!SX#ZBA{dA!H-az}O1MPPN+TYuJFYP}`pFd5BoR2d=7n@DzR7pLaj~^-20#-PiH($EwDY^es$UjpjkMC~6B)+i;Q| zmjLNy)GqXDzeX)07dzg4H@%2jr@J&gg<6MKdz2Aru6yDneGf|kpSq{i`j@MP9HjmR zjS>m^fW-VMg?Y{()juiwpHcn2IY9o_19HVHUA2DRRX2Vf?4uO)59mCUXTYGZ2gAM* zrK3=$H-P!xLO0Rdz<_V3TjK%k{b+rNK0=Ss$HA0$(RaYy z&(NpoM;P%__-8NCJz&r;h%@1Ct)o+-ksbu2eo0(Sr@^cbi6ih}Ch2Qph8_dcepB2? zPk?d1BW{ITag3f4chNIo;2(;6VEdn==fn&2A{hB6nno{aHS`bKYWlfWkMdgjM{Pa* zvo=V-(ypX`)h6h7*xir*U+jb^tfn+z-)t{Y^NWI3+Sif zLV8JDELMt3#F?U9tP>rgQS25&Vvo35M8%ls7DvPtVp7D!jMyh`5c|cA;(&O+c&)fq z92CcdF76VB_?#FO_lU#dIgEZmq{Yi3qiMp{YQ%)LT1;y7D6bV$+IsPNZBSgNT`7)g z6XGU_-QWGc*tuf&6YzD8wd00)#cmF3$Mf>Uj>i@dJ04q_*a1L5?9|e(*g3WN#4do8 zF95Txoj<6s*!le>id|rWzv^tU^9L0ayZ1rtZid)>5Mp;5#O@A=-JKA-k3sA{4zc?b z#O`j0-De?oCm?p8huGZ%vAYjqcM@XvMTp&l5WBBH>`p`M9)Z|>6=L@dh}~llyKh76 zo`BeW4`TOyh~3i=yJsLsKZe*n3$c3vV)r7%?(ZRXFG1}731asPh~2LtcE5qx{X4|& zw;1(b5WC-LFn3ywCbZQk)uX&tE7R6%Rob8y(yr9P+Jwe;Z*T@-!|_Sv@`ATD_Wb_> Q?_GQCMcO9rTuxd41FwE+c>n+a literal 0 HcmV?d00001 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/DataSourceReport.jrxml b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/DataSourceReport.jrxml new file mode 100644 index 00000000000..2df89cfb9e7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/DataSourceReport.jrxml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <band height="70"> + <line> + <reportElement x="0" y="0" width="515" height="1"/> + <graphicElement/> + </line> + <textField isBlankWhenNull="true"> + <reportElement x="0" y="10" width="515" height="30"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Normal" size="22"/> + </textElement> + <textFieldExpression class="java.lang.String"><![CDATA[$P{ReportTitle}]]></textFieldExpression> + </textField> + <textField isBlankWhenNull="true"> + <reportElement x="0" y="40" width="515" height="20"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Normal" size="14"/> + </textElement> + <textFieldExpression class="java.lang.String"><![CDATA[$P{DataFile}]]></textFieldExpression> + </textField> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/JasperReportsUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/JasperReportsUtilsTests.java new file mode 100644 index 00000000000..62c1807259e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/JasperReportsUtilsTests.java @@ -0,0 +1,247 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ui.jasperreports; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +import junit.framework.TestCase; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRParameter; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JasperReport; +import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource; +import net.sf.jasperreports.engine.export.JRCsvExporterParameter; +import net.sf.jasperreports.engine.export.JRExportProgressMonitor; +import net.sf.jasperreports.engine.export.JRHtmlExporter; +import net.sf.jasperreports.engine.export.JRHtmlExporterParameter; +import net.sf.jasperreports.engine.export.JRPdfExporter; +import net.sf.jasperreports.engine.export.JRPdfExporterParameter; +import net.sf.jasperreports.engine.export.JRXlsExporterParameter; +import net.sf.jasperreports.engine.util.JRLoader; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +import org.springframework.core.io.ClassPathResource; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + * @since 18.11.2004 + */ +public class JasperReportsUtilsTests extends TestCase { + + public void testRenderAsCsvWithDataSource() throws Exception { + StringWriter writer = new StringWriter(); + JasperReportsUtils.renderAsCsv(getReport(), getParameters(), getDataSource(), writer); + String output = writer.getBuffer().toString(); + assertCsvOutputCorrect(output); + } + + public void testRenderAsCsvWithCollection() throws Exception { + StringWriter writer = new StringWriter(); + JasperReportsUtils.renderAsCsv(getReport(), getParameters(), getData(), writer); + String output = writer.getBuffer().toString(); + assertCsvOutputCorrect(output); + } + + public void testRenderAsCsvWithExporterParameters() throws Exception { + StringWriter writer = new StringWriter(); + Map exporterParameters = new HashMap(); + exporterParameters.put(JRCsvExporterParameter.FIELD_DELIMITER, "~"); + JasperReportsUtils.renderAsCsv(getReport(), getParameters(), getData(), writer, exporterParameters); + String output = writer.getBuffer().toString(); + assertCsvOutputCorrect(output); + assertTrue("Delimiter is incorrect", output.indexOf("~") > -1); + } + + public void testRenderAsHtmlWithDataSource() throws Exception { + StringWriter writer = new StringWriter(); + JasperReportsUtils.renderAsHtml(getReport(), getParameters(), getDataSource(), writer); + String output = writer.getBuffer().toString(); + assertHtmlOutputCorrect(output); + } + + public void testRenderAsHtmlWithCollection() throws Exception { + StringWriter writer = new StringWriter(); + JasperReportsUtils.renderAsHtml(getReport(), getParameters(), getData(), writer); + String output = writer.getBuffer().toString(); + assertHtmlOutputCorrect(output); + } + + public void testRenderAsHtmlWithExporterParameters() throws Exception { + StringWriter writer = new StringWriter(); + Map exporterParameters = new HashMap(); + String uri = "/my/uri"; + exporterParameters.put(JRHtmlExporterParameter.IMAGES_URI, uri); + JasperReportsUtils.renderAsHtml(getReport(), getParameters(), getData(), writer, exporterParameters); + String output = writer.getBuffer().toString(); + assertHtmlOutputCorrect(output); + assertTrue("URI not included", output.indexOf(uri) > -1); + } + + public void testRenderAsPdfWithDataSource() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + JasperReportsUtils.renderAsPdf(getReport(), getParameters(), getDataSource(), os); + byte[] output = os.toByteArray(); + assertPdfOutputCorrect(output); + } + + public void testRenderAsPdfWithCollection() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + JasperReportsUtils.renderAsPdf(getReport(), getParameters(), getData(), os); + byte[] output = os.toByteArray(); + assertPdfOutputCorrect(output); + } + + public void testRenderAsPdfWithExporterParameters() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + Map exporterParameters = new HashMap(); + exporterParameters.put(JRPdfExporterParameter.PDF_VERSION, JRPdfExporterParameter.PDF_VERSION_1_6.toString()); + JasperReportsUtils.renderAsPdf(getReport(), getParameters(), getData(), os, exporterParameters); + byte[] output = os.toByteArray(); + assertPdfOutputCorrect(output); + assertTrue(new String(output).indexOf("PDF-1.6") > -1); + } + + public void testRenderAsXlsWithDataSource() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + JasperReportsUtils.renderAsXls(getReport(), getParameters(), getDataSource(), os); + byte[] output = os.toByteArray(); + assertXlsOutputCorrect(output); + } + + public void testRenderAsXlsWithCollection() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + JasperReportsUtils.renderAsXls(getReport(), getParameters(), getData(), os); + byte[] output = os.toByteArray(); + assertXlsOutputCorrect(output); + } + + public void testRenderAsXlsWithExporterParameters() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + Map exporterParameters = new HashMap(); + + SimpleProgressMonitor monitor = new SimpleProgressMonitor(); + exporterParameters.put(JRXlsExporterParameter.PROGRESS_MONITOR, monitor); + + JasperReportsUtils.renderAsXls(getReport(), getParameters(), getData(), os, exporterParameters); + byte[] output = os.toByteArray(); + assertXlsOutputCorrect(output); + assertTrue(monitor.isInvoked()); + } + + public void testRenderWithWriter() throws Exception { + StringWriter writer = new StringWriter(); + JasperPrint print = JasperFillManager.fillReport(getReport(), getParameters(), getDataSource()); + JasperReportsUtils.render(new JRHtmlExporter(), print, writer); + String output = writer.getBuffer().toString(); + assertHtmlOutputCorrect(output); + } + + public void testRenderWithOutputStream() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + JasperPrint print = JasperFillManager.fillReport(getReport(), getParameters(), getDataSource()); + JasperReportsUtils.render(new JRPdfExporter(), print, os); + byte[] output = os.toByteArray(); + assertPdfOutputCorrect(output); + } + + private void assertCsvOutputCorrect(String output) { + assertTrue("Output length should be greater than 0", (output.length() > 0)); + assertTrue("Output should start with Dear Lord!", output.startsWith("Dear Lord!")); + assertTrue("Output should contain 'MeineSeite'", output.indexOf("MeineSeite") > -1); + } + + private void assertHtmlOutputCorrect(String output) { + assertTrue("Output length should be greater than 0", (output.length() > 0)); + assertTrue("Output should contain ", output.indexOf("") > -1); + assertTrue("Output should contain 'MeineSeite'", output.indexOf("MeineSeite") > -1); + } + + private void assertPdfOutputCorrect(byte[] output) throws Exception { + assertTrue("Output length should be greater than 0", (output.length > 0)); + + String translated = new String(output, "US-ASCII"); + assertTrue("Output should start with %PDF", translated.startsWith("%PDF")); + } + + private void assertXlsOutputCorrect(byte[] output) throws Exception { + HSSFWorkbook workbook = new HSSFWorkbook(new ByteArrayInputStream(output)); + HSSFSheet sheet = workbook.getSheetAt(0); + assertNotNull("Sheet should not be null", sheet); + HSSFRow row = sheet.getRow(3); + HSSFCell cell = row.getCell((short) 1); + assertNotNull("Cell should not be null", cell); + assertEquals("Cell content should be Dear Lord!", "Dear Lord!", cell.getStringCellValue()); + } + + private JasperReport getReport() throws Exception { + ClassPathResource resource = new ClassPathResource("DataSourceReport.jasper", getClass()); + return (JasperReport) JRLoader.loadObject(resource.getInputStream()); + } + + private Map getParameters() { + Map model = new HashMap(); + model.put("ReportTitle", "Dear Lord!"); + model.put(JRParameter.REPORT_LOCALE, Locale.GERMAN); + model.put(JRParameter.REPORT_RESOURCE_BUNDLE, + ResourceBundle.getBundle("org/springframework/ui/jasperreports/messages", Locale.GERMAN)); + return model; + } + + private JRDataSource getDataSource() { + return new JRBeanCollectionDataSource(getData()); + } + + private List getData() { + List list = new ArrayList(); + for (int x = 0; x < 10; x++) { + PersonBean bean = new PersonBean(); + bean.setId(x); + bean.setName("Rob Harrop"); + bean.setStreet("foo"); + list.add(bean); + } + return list; + } + + + private static class SimpleProgressMonitor implements JRExportProgressMonitor { + + private boolean invoked = false; + + public void afterPageExport() { + this.invoked = true; + } + + public boolean isInvoked() { + return invoked; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/PersonBean.java b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/PersonBean.java new file mode 100644 index 00000000000..c3f19cf3e95 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/PersonBean.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ui.jasperreports; + +/** + * @author Rob Harrop + */ +public class PersonBean { + + private int id; + + private String name; + + private String street; + + private String city; + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/ProductBean.java b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/ProductBean.java new file mode 100644 index 00000000000..4d83be1e923 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/ProductBean.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ui.jasperreports; + +/** + * @author Rob Harrop + */ +public class ProductBean { + + private int id; + + private String name; + + private float quantity; + + private float price; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public float getQuantity() { + return quantity; + } + + public void setQuantity(float quantity) { + this.quantity = quantity; + } + + public float getPrice() { + return price; + } + + public void setPrice(float price) { + this.price = price; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/messages_de.properties b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/messages_de.properties new file mode 100644 index 00000000000..4dd7d2be865 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/messages_de.properties @@ -0,0 +1 @@ +page=MeineSeite diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportChild.jasper b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportChild.jasper new file mode 100644 index 0000000000000000000000000000000000000000..cd8ad2052ff4771741b37d5adb79530cb41fa103 GIT binary patch literal 18449 zcmd^Gdw5*Mbw9Iut)#VV%h)ntJHiHI$+qMdj==_7Pb{-~AjvYwr1EO_%DVPycYXKD zmYf#`8Uln6NJ2vbiCb_;QtG^j&7-(ZXafn*6xxuGqzP%hx49hZ7Ny|<*8HxR7!f4th z8~bG=$-m1d15^^G>S%HzWyX#6h#j$MQTRaQaHQExHV+t<8Ht-mBcpL+YnbNiZat9+ zV_MV*sA#3? zq-7cja12QCDup3C4RilENUCH&63~hl;ELUA#S9CyS=_-{N2Q%iIoN8Bj2nrbByYjs zbjk=*)o3JoaKD8$#%#JY4CXbb$C@)Xwpnd#GxIGG1LH%A6>3S$_fofQrx5`KvTZK~ zW0)pw*lC+q?Ja0ug#F%y~-HeFtTe2-*JFa08L?ye3LlCwX0UOjN7P_Vu%Zf}h z-l=1+EPdd)$U`M0x~Md59yR1{lpQGrCEi!o7CkrU<2u)rrBb!NJctz}oD)3nm| zp7CVdU|AZbh58Lt+lbgkY$y_+G}6O#k#1)JYL~{M_po7&LAdY|gZhn$+=UI>He-VmHHiBrWjZ z0>5SJvyz8Rm|2@P6%dkkWlE)vI-`Isp& z#<>WP5aAs(2FGDQ_mAu55I4gm#h6vPt=dfQPJlge=$&qop;HDo=5jEV%ZqAm)|}w6 zSXedV(eWKOf#Ve^#Ve;r3gjlDNoF56K{cw;#L6`8K_XP!2q+{!&nVD)h3f)IJVEGjm23^|DYmtLJL0g z5pw;1k@Gw<%_4UGQa6=CU{}_{sTFo-zGwHerq}-4@kjpa*zH?jwBU`DePsII0VW1B zM`#UxsouKzyAQtkD~uR+Mx;n4UTXypZSpQQmA9qVZ@6NEP4jme@xum--P+#KxOr&O zNRdq;N!f_92aYV+GzS8VEUR7xuoCwrAjlKUWq>;In^7?3m}MmnN_m%UD?NTNovV4B z{Lt)C?LGPEukq+-|hTTeYycWEYAqk8qM;m)gd)$dt5Jp52 zQJ8NwR$gq&tA?wd>rErQFE=kif{2Jw2h6(Th3;f65?cV03DvQp)0n>s@3-v~Ut4Ch^T& zgz3-5H*w>4er#U%@NOCCfJzQ^HWw+US-9jXww(j#c@FV z7reVG2Ycau=)cj?;)Jrx7Zd-~h)! zhF>{m?H`pAhMm~k2~i!B5HEB{E}PDsJNE!~id$r`-6shhWQz1FM{nedOhe6V;=e%7 zAP*nZjDcms!Q(Upyar8xtD>N`t3A(ryD=BfIs1G(-QEo3K7e2P<|$>Z%QF+tB8|+f zE6bXR!C4HCO(oac(|IOafyv%`zRM~&S(%i6N4V84%;X<^UY+qO(B~g3UH_O8u3zs- zS`(1T6fBjhqs?Neyohk?9iO@BlGiIY2**g3@QgCl-po%8uo|UoOV~UYTME!+GVl<8 zY@4fw3GrGtN^PxFcLWZm-$*AXt*Fs$qArx!&j~uK13TtoDqzxsbIoi&SA2>Yp|V?l zpu3kVyB6dP-VGQU3wet^r!)LS8A2*+x^PZ?J$GZj0(UOg+lr#Es?i~lsYypIGliO+ z?UmDEB@RarL834Zq8bVjHKh9@Zx;ePuWE<0?7ZS!VB1fg>uLOtl(Xrj*xWTmdZw)C ziBB0~hFS>!~Zk&hQlm&awzbaR*ga)66ok;Tn6L_z0E|_k_BJ3 z8^gr)i|Mp&Ody>_Jt2llDfG>-`E9;+)VSm2_OQqz>b}@*HLT7^)J|H{nSo%K7MTfD z7bEc@E^T=c8Y4h7@0WQLBtU>4eg4o=l!;O)svI=U$qt%e+-nlXk$Rm!u3F!aPhYeL zXACukFsy4}V(-QA9`f_pWK@wj($>4XXOQ3ADPOx3&CSMFqP5nilf9z{5NOFEUbIH4 z+N~rYCzdPKwQ!y+GZdYxw%s3!e%coO}*~DRg(^v->V_+(R{tU9l;Oi-n~{g-YepzIP@qkTj995gg?jI9MWGY0Gbk z-j+j#T)^ip?CvzP6P71kIIfhkb4HDruSc}?_VjeL z4R-bRpcpNCrw_%EIVBS6%*sDzo*vWPa)W1k?)CSm)jir<23tl3dUyA?b-;Vg=0kS% zbJ#f`!z@20XRd*^{;s~kaL1rMyD!?+-!h7GBY1!TCp`0`o1+N}_qMf!L6fqCk}=^V z+>}aRG;bE^&ix%~2_vn$d)j%_Vvn8h_`cB4Kh**~x-Hx?FfbDCZE5f5#}0Ynkn~UC zBp);T$2q(k>gpfd-4gB^=3x!9^KQtr>`DG4BooyIT>~Rs*Y@=GcR(Vp?doY!`|C5G zx>BjiJhPWhDNyf@3B8z|$cbm!!Vap|; zqR3$O*Dt zn2Wv6#qJ4GRUYhxR^TrT^6rRbc@S6UK|CwjZZ%J$yiB1Cg4=%847pg#WQTUBrdXvO z5oI`DSbp#2cBrerXL&H@W!_km0dd{N4 z<^Cpq`Ve29mJ@ritv`D0hg7-6L(u_<|Gc0_Y?gxux%J%5H^V$?{aPmLZH&HNS+dMh zUhZLFK1_@)?;qoBaNe-pLo(<;;BiA-m{uY_3%MV^*~xa$;m+tYW6X>R8D~}?Ugrve zG6*aP7cQ4%Eyrdl|Ij3>p}k|CfcOozD<4(7z02#9WA)4PI~mR5%tdYhQE#5lB7N)C zOLjTR3k;|;3tl*zmc{M@y@I!&`h21%XK*TlSwa@@rAP&ZtS?u{K$p0RCtw1L6|p>c zB#rql89VNXm?{J~OVayrUYe7$5}t=k;bKqDD@E3f3;YFd6aM_=X{CZ5PQ{;D%hT?z zm^AwXE6B_@y;}3W?9HJJKWL(fPuSdT8OwdxVgOeQia!5fn-h0l~1TFCz^Z;M-D5x&ywMu{U z4fJK~f-cG#=%(TMUb^)FLDljwXhc@;1vM4RW_7-S6{_LR0fC?@)xbvz0w3J*Nz;fK z6Li60eT2dZu9F-JT3_shZni3Dk&7xLD-^WQec|i|r)q*0xb0s4-c8G;>=W4DHAKGpJUSBGeUdfFaB1y{DUglM69Y75aKs^fkgAzG}S zt_|UnJlWP2qKnkibs@S~J#~j@iF)b{(NgtveTbH+r-2YYgh&- z0|FdPs6(AWKHYLp6>;l=IuWAdL%E3T$Sx-wYxv=m7Q|pF{~- zsppqplB;8Ztqr~pUUgH5;xtiB2PuIiqbgO%CTCdB3Q9q8T{Ut_jzO}ZIJ!C0Tm}iG z<*j1{=`eKA!R0fML7HMIhGh)WQSeoF@tMRRy$6iY?aCGg;lbRlJ|h^Un+4?*A%k>_ z*Xo+RAl)WNrQJdLKyfaM*&}zgfOg$mOBkT=h$1?dy$;WuYN`XspJ*duLJV1k15Aao_m zgazr-pxo&!dmYD8WiJW+6|nmaR*)V6_FPjHq|aiU{^|}YxNuch9svdE9aB*Q#rI?a zY9))=%~GiO1L-5Iy%qG=5JRrSsu%i%u7dssOb1dZ-g5e46`iCnVM1t!EKEQSSLK;6 zL|>t=R?!{wIF|0=l;3St(5Wi=D8GT8I#^(4VWFO+r+9*=AxGXIl}T67GtlAe)>i!2 zJ_C`>-ywp~yqO_T4bs<{IX>N0c(F=xP5Yts2N#TEsz>}`Y*FOh^A_8Xm zIeMPadYU~vrzIe?Qy*n31l_a#b$em*Fpi6hV7&wcx-Bj3|Yh zuf#Ugz_l+x+hVx$rEuiS;leM6^In6kS`TP5mb4X1+Ci652d$)Cc-u>>XpkD{Mrwp> zT}@H+9;dZ5fm{S1InWVWNAJPtW3+)jfVl+SMDJ3Jp-ox<<~6Q9O_9bmrzzIB_B8GH zC}i4*u7P-LM=-Pl;Y|z1z=dlJZxAvo^!RM!>RR(jN(SgG9byKru1$MjBfv=yTm$fk z2Q~qm_P})j-|c}L0KV4)HvxRV2W|#<%mcRoywwA*0{G`1xXoMF283}$U0Ba9@cBCM zD@@y{8&5qn44#_QM^kh?-A?_eL=Mmi@HoIRie9&&*L^i+xLwb12TRE6+Pge(2f({M zuod7v9@y@Yvj_|(Y|LD2%`&ieEhgGV`!FRUpggR;S7Z4o3*hS7k9*)wfPdkEy8u4m zfnk83^1vQ|4|!l8z|VMKKfu5Az(Ifyd*Bej6CQX2z(+mMC*+FN<5-)CwH?6P4q|O_ zuzCWlPM|djR;R$~LtwQ9R;RJz&(Y_x`Y(VhrGOq|JuX2lA8e<T-vjuaz>oR+41V9j@4NW@48PyvcMkeD2S1ca#dY}Y!4Kc$iZp(}A@0HN zA^e`g?|J-Q#qW=pukvX+d1L8m`f~T9;(p)roxbPy@pFmlWBJ<0eC@-&_8wn*Yvbdz z;}m`EES<&-n*d$oLMt=gEzWpX1?YxT^u$>@`Au5F2)%|=^tYw^K+dC7?afNx_dUPp zQ9x%guwBl1vini`N(S@@pjP?r4Bp)js87xbTIqv;`d#Sg({%R6+Hahue?aqwQ}oTV zbmkO&`xN~ny1ol-gKpPeKtnFnA_xAH8rUhDPd-8ag0Z!)x(JqFh<*ojHGuTmyVraP zo2xAA4`3^a-VG6YFNEtD{@p^i!T#M1G5ZMJ1rhlWJ&30hbT35h;}Dhm>2dlb#N|`4 zV4s1=9H$rQ5s1wR_}tG!biROU>Pd*t7wLEORfy2zB0x_-jGh$p5Zi30Gx#rt-+(wh zD|+ZTh}84=4>B)8tX>l1^fE;26>*qeg?N2W+(tiyi2X?1N3TQ7ekzXB&mn5R5YNyX z5Vv277wFdzx!;J_=ywpi-;1~C4}nU0GZ3P;0(GJsEBxM{u5$b!Lpe00l|w^XIW(k| zSG!3}RqIe^!v92(Nf0m!Eun8K$V8Y)IPbXTn$8p>7A}r>JZZS_>FSd(*(JF?-bz+a`5qojHNeqj9 z!VnQLj%!+siNoT6I3^B?+eA{_BU0i%VT*^vq&P07#Z%&_ct*TWJTKlaUJ$p6SJCS= z@j>xNaff(I+#RSC9}a}XeNc{1LOFi)r>h)q*K_;?;*#MxxZ!On2Pp6~12byP84u0n;hlFyJ<6$Vr2`Iv^{ z98W?yo`G_lfpUBU%JD3e<2fkD^H7c#p&TzkIbMcxyaMHT70U5FD8~<>96y3`ybk5~ zDU{>qP!6b$cmvAuODM;$p&Y+~a{LZz@p~x8AD|p>LOI@oa-0*l1xmy{fl`QiP&@>& zKOUGPo(j~6X9Bh2`M?740#xADz+&-QV2Su+V5xX3a7mytusje7tPIoznxGu7!z&^g a!be+qk0tEc|F^n(xU&m&hNwP*vHlmupxvAR literal 0 HcmV?d00001 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportChild.jrxml b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportChild.jrxml new file mode 100644 index 00000000000..ede2a092214 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportChild.jrxml @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <band height="14"> + <staticText> + <reportElement x="0" y="2" width="60" height="10"/> + <textElement> + <font reportFont="Arial_Italic"/> + </textElement> + <text><![CDATA[Title]]></text> + </staticText> + <textField> + <reportElement x="0" y="2" width="325" height="10"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Bold"/> + </textElement> + <textFieldExpression class="java.lang.String"><![CDATA["Products ordered by people in " + $P{City}]]></textFieldExpression> + </textField> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportParent.jasper b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportParent.jasper new file mode 100644 index 0000000000000000000000000000000000000000..aba7bb207d4184ee67894cbc179354983bd7bb0c GIT binary patch literal 14261 zcmds7dvILkbw79YTCLWyE%^Z$gDk+7WLc6eY-~ipT6tx!Sv}a543-1pYWGUIc(r%A zdsh!a9y|giltNpeaq5JmKtobUNC3M@W->4&la^`2gtjwnXGoc3rtKe1I!&idrZ4w* zzVE(PyVkD5f01VIz2ED6=R5Cn?tS@ZRF^lYBdb|G`PrU()O=1eO)Y1bR=!8e&gogL z=eX!hh)xoJy9xoSiBnU`Sjg!a?TBir7Hx^&qb{nwy3w1|OkK_B_o*`(Z6Hn??P;Ux zf|e}I&g#n+waCdCH9Oavv`jrahl%U#iRMs7&FAl>Pf%dlq&;ilHlyZ&U?PIsY6P!| zQFz9%EMs9rHF1y_>Gg)-W#C9#N5lVR#w z78Cu^|fyDS~RtjLR5kPR=x-xR$QvN7P&~zUUY@MfG_mA*isk5)~XG zHsqyP3o6E`&SH@kjpZDyz&`vGX$}H4@=hJ-s5wp)Nb*Pre*2Uh{$OGDUXm6w`z1^^ zHGwH=)bmHA6vfFS4y?oOD&ZDGY>HE>Pb$YvV^N2gThw2PMV=@-i&z*~!q~joEEDad zejh}()o18pSxcMKOcqc*A2BjeQ2%hmFfy8&Wq5i%X2F7{7+wq5tLMklv(beaEuGfV zcISE+9$3!P+QdAxeQw_FZqoCUS)3&U)9rNSusEAC(y(*f6@X5ni%H@`I%En9&%HdU zemMt0svBfe4*qRq&HU8goc*t#1K5-UEJuvT<*P0h)eq(N?%Ti5qQ+xdW>K^B zl$uj43JX-HM-6j9&9KN-D;jJBJz=YfQT@EI$HI^&a~a(l%w&uuEe)X&M)`J_+~{)7 z)be@Q@X995n>zps^;ape(TuhLKXDYyWqre+&;>|GYF^KzO^ne7pIwUUd0{d&-#UxB zD+siImw{y_TdUw8o4TGs(^OX&?(zfgZ9nq^_475%>)JddTkx`WsTOF3u&A%fLrrMQ z*08Q+d<0(yS3F}Frx#T7bX;51G7)OlSe%51oX{7v2(6!oZ)1@@Jpo^?SrJ<2^eB8p8Q)_S>*7 zckvk%8%A_(2!Ftgd$nSgaf91 zm%s~~{X)Eie1RtP$Bdd1KJ2JWb3?&PY}_bDn+zJJX?L%c`Ljk$H=kl zux{q9+vnjv*_I1qAVv_-X{x2APq1^!Ptg_j3Ra*aB1Ciy1qNY3654{XsKvn-o*{HC zLgAc|*Ev|{_!{AR-ZI(Da0`BKiPMD`Da-h+#Ho>^?-XkX6AvQ3$sfTwA%jKNS1`+V zup?y9S;gArH}1T{4s1D#JjK6d&1r3g$Kd8`7mT!s0-%LWIhB2e0LjA*<=q(%!3b=2 zJ)N+5L-X+bn#jp^3e&%y6ouf^iP)6a@h`_q*YTyDgT9OW2^h^@XuSU6z)zt|3OzlW%*&;_MKlo5(+Hna^M&kbgwK7I!ecWEMy;6V)ka*&!i)^;y;DK+H-R`=c`Q%B z7zwEUCeHGcM!_r-f|Le6@RXBzBo;$zYF;KBr?{wLBH%($0*&dfq%kgrjqq^Z(_=`%qdY^*qB`o3O5U(M{v_4+??{_)`vDc z*^hj*ZkXz4kz>rOPT~`%Knh3QCc|-#hlD|vQ4#xi4JmlztT{I$Y=K3AQ^PPSv!cah zj|qc77cTt88Hh0V6d6)s8?Ogmp#qQHz^ID8LjjA{fq=4f!36}AX4VqY;|ZQ5x$8o0 zDg$*R+)lcXvQXW!p;vjPK^s>Sw5%x|o4E%n2qQZLBb&v%<;hJXWqUVO^EXiz_U!Ty>z737=W1Sa};yLCn#m(}H;V>bKD(W#PtK(Rmm5@4N&qZ3VC=e=H`CCJ%B;^7({lgDNyMB># zb2ctURqIGyD4yunixSbWVZv4}m|CQvl(t zR(Y~tlRyf}supcdM90Sx6Vu~^iNTTRL^P3{9vK{mL+~m%@SVa4tjHA`?G-~~qodKG ziP+dEN|0i9{@x7SoD&oH*KDxYj11l}Jv25sI$@P52KpDY*b9yfP7F>b$0id)QRe)Z ze~tq*Ih2TvPsF1D+PjvF9Zw9-An{UDR?^W6Ke%=FmhrKn!Fbe(S49mgZXf}bnTt(? zE%xL@R3bMWnH)XBt1k2C=GY*qlm4w*?bSo^!DMneJ~ntHngA=rQc)fi`WiR5I`3cS zP~}7{F)=w9k4^Ei&b7~cLN~1fzey_wwJDaIjvXBxOGLr?qp{IJ$w*&`)~>4B`y&kk z&pwPl_XGO1!wm#B&{k=-*3eehY|Z@RL-&8S`}`3{S@}ifnnL0W1{@%st~Mccha{v5 z8Bte61yRqYOi^NG4^yhR2>oH1HH$~fIsRsMz3?9_;ydHC&F$69VTh|?t`ui}um^e; z^#nCj-X8d^BTDi>zz@E>y$sf|dVApqtqwm>9&gTSOKo=PzGH7Eqx>BnVJ+dUSFm z5>1G(^FhJt=T<{hs)o33Xe>TCGFk?v0xSh|4rBvW0`#4#rqYr==Tu=wN7-EYj|CJ0 zE(*1k;Mr92p-@+8iHkx=5LVdBRS49$2-H`CR*FDFr6n!`VVe&=6qx6WV)yOhdJXtc zW0&xG>@eC$K*1blkn>V6B=8sM$U9DYE%|sIrlAfb=hHY^e}cKQVBE3 z1?97&cR&2|@&C9IZ+#-pTOUSbOO3Np@g2~evJOvUISRW3k#s!-QNO&MOYCj!ZM)lK zwW3GlS!1&u;@F33i{)N+VqIe=RhL5#oK6mi=rDN z;42bVPJ_OwG?D#;t4k`?ucS za`%sFC@_q#Z4i7(--}Obta&(5yc$R^=WaPHa0@R5ao@nt%Ys0^Dl>pcC2%V8^1pBW zRef;c13Lt1Irz^1efzsu*F)zO+TqVbruXjczX5Nh4<734zoBos|Iop{1N$4en#Z}* zML)seVj#Z5iL!xG5iB%NjY4fXrw}$>K2%j`-*WCoU0pI- zoL4Axl{ceY1gg+>Z-V22eNl1|0wvL?LRXfo_QlGIuOjGBMMnGO7Wz_;qJ?fPi>nX{ zT~V^5n~#(mbTc4@LZTco%}J_4J=HQpCfEvXa?*H?-<|MFp}p0@aiUxBbc+kBDDF~d zvpe9hf`cK2THSsxLh;Y`hYbqV-^9V{%?j0Ybe>R9slxlDFkM00LR3rJ!>EJ7tf2*`WG&{Xl% zAEu4+X@8hnsFnA)(-!$O5T>p2=_6sfOg`Nbrpx8ipn{LNkeADkQzp2U zqEK_HkjHm|$g|Qh99N;f4&R3r`~lV4O(so<2{q1&n^&l1_4>{eVH&2RAz*sUo-2eQ zAEx87`&I=ntN{YNMdyg@90h~Rn}8sVD>BjV6q-;&>aeu78HUs1#z;GF18>+`Y2?-oaqSCU64#iP<=Kd zNOxnC5@Qjh84%f?@3Rs?N`oqPzcdd)n)Rmo>_U*{F}27b1nC}yN-7gU%6Pr52?$aa z>cILRq+E4Io~b98-aw{Olz9aSJmb{18U{c>LknV%Hd72)i z`!U0><3aiaB+vd52D-4hBUVOI03^Dc(oo|vvXF04GwKzh#9yB+u^KhdLtquxLF9m) zYc|lQK_~!)23$dphUgLcEo=xe75Og&qNB`yVfqX`9-=(`HfZm`l%aS7{Z5EZ@({o3 zxG2s1uR0p&cPq{Iy}oFm--qI@-Zp}7mo<3kXB4Uv2}Y3qfa&GaD~aELJnNYdJxiYp z(Gp|YV5cCJb<>6srq9zCLi8j(2P>@R@TL%=-Cb_8lKmy3u!CQsKVlr7hgm>Y6QmbG zc*~F*tR}p>?U(5#Ui1|Nylp}H6G*Bf9Ag=v&;-umK`<{&Uz1$=I-m0EV81gpnz!@? z{`3NUSl~A8Wv}tFC3+oVC0|8BH#FJ->&PFJwcrlNf~Nqx6>*1C5qG#0afd?@ceoRA zhcgj(xDs)PBN2DF5pjnT5qG!{afbsDceoF6hw~73xDIiL;}Cba4cvo>z2Wq5y%Mdr zffs+^I^A`iuIf_Wpf8-Z2j#6d@YK@ggAW5bXhx zZUUKZ#ZjklSe=g1GR5dokn~yfzDRL;9nLzyUfd={w@nHVv*liUmpu6F?ZQz2(Ij>` zfhV|nd*!mdGLDr6d*u=f$L^LDuXz)iAM=_wqxo^Kc^J)4dQG1YT_Gg@F6=suv)zre zsW{sVPLaa?pP~nV%Y(qH7OjU_&Xrez52`@QwaUo0ui}0+M){9v6vgj0{O-h0$FG3j z1Nc3G-x>T~#P2oy-oo!){NBgwnDG|M9NZ>EJnf;!S!II~YYR6|H^e=&3j9_b`@3t4p+=Ml1RqdiG??XV23gqWi{k zboNbp~(Q|joON;`cU7`*bE!^c;P_-MB-g^%B;hL7H)vV3G)|9$ZB z&%wucz{ekgkMDwye+54NHTd|q;N#zckMD!-KL#Iv0zUo}9Q-G6?w`TOe*qtV25$Wu z`1lL(@jt=GUxJVS4JiLZ@4=0{uPF2Z7p9eZTtiB`!p8ZVzd3yT(E9jBHGK3YmE)tb z4aL^&$h~&ZZP1hnWhdRK>_T#}n{=fc5q=*Pl)VU__tOK)0eV=uk)BWn=qcqEI-?w> zv&sbFiP3AyaXP1r(p$`B5UohwcRq?afH<=yBKEvKRw1klmGw# literal 0 HcmV?d00001 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportParent.jrxml b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportParent.jrxml new file mode 100644 index 00000000000..f2f9c08d3f9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/ui/jasperreports/subReportParent.jrxml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + <band height="50"> + <line> + <reportElement x="0" y="0" width="515" height="1"/> + <graphicElement/> + </line> + <staticText> + <reportElement x="0" y="10" width="515" height="30"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Normal" size="22"/> + </textElement> + <text><![CDATA[Master Report]]></text> + </staticText> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/AssertTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/AssertTests.java new file mode 100644 index 00000000000..c910fb2daaa --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/AssertTests.java @@ -0,0 +1,184 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import junit.framework.TestCase; +import org.springframework.test.AssertThrows; + +import java.util.*; + +/** + * Unit tests for the {@link Assert} class. + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Rick Evans + */ +public class AssertTests extends TestCase { + + public void testInstanceOf() { + final Set set = new HashSet(); + Assert.isInstanceOf(HashSet.class, set); + new AssertThrows(IllegalArgumentException.class, "a hash map is not a set") { + public void test() throws Exception { + Assert.isInstanceOf(HashMap.class, set); + } + }.runTest(); + } + + public void testIsNullDoesNotThrowExceptionIfArgumentIsNullWithMessage() { + Assert.isNull(null, "Bla"); + } + + public void testIsNullDoesNotThrowExceptionIfArgumentIsNull() { + Assert.isNull(null); + } + + public void testIsNullThrowsExceptionIfArgumentIsNotNull() { + new AssertThrows(IllegalArgumentException.class, "object is not null") { + public void test() throws Exception { + Assert.isNull(new Object()); + } + }.runTest(); + } + + public void testIsNullThrowsExceptionIfArgumentIsNotNullWithMessage() { + new AssertThrows(IllegalArgumentException.class, "object is not null") { + public void test() throws Exception { + Assert.isNull(new Object(), "Bla"); + } + + protected void checkExceptionExpectations(Exception actualException) { + assertEquals("Bla", actualException.getMessage()); + super.checkExceptionExpectations(actualException); + } + }.runTest(); + } + + public void testIsTrueWithFalseExpressionThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.isTrue(false); + } + }.runTest(); + } + + public void testIsTrueWithTrueExpressionSunnyDay() throws Exception { + Assert.isTrue(true); + } + + public void testHasLengthWithNullStringThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.hasLength(null); + } + }.runTest(); + } + + public void testHasLengthWithEmptyStringThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.hasLength(""); + } + }.runTest(); + } + + public void testHasLengthWithWhitespaceOnlyStringDoesNotThrowException() throws Exception { + Assert.hasLength("\t "); + } + + public void testHasLengthSunnyDay() throws Exception { + Assert.hasLength("I Heart ..."); + } + + public void testDoesNotContainWithNullSearchStringDoesNotThrowException() throws Exception { + Assert.doesNotContain(null, "rod"); + } + + public void testDoesNotContainWithNullSubstringDoesNotThrowException() throws Exception { + Assert.doesNotContain("A cool chick's name is Brod. ", null); + } + + public void testDoesNotContainWithEmptySubstringDoesNotThrowException() throws Exception { + Assert.doesNotContain("A cool chick's name is Brod. ", ""); + } + + public void testAssertNotEmptyWithNullCollectionThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.notEmpty((Collection) null); + } + }.runTest(); + } + + public void testAssertNotEmptyWithEmptyCollectionThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.notEmpty(new ArrayList()); + } + }.runTest(); + } + + public void testAssertNotEmptyWithCollectionSunnyDay() throws Exception { + List collection = new ArrayList(); + collection.add(""); + Assert.notEmpty(collection); + } + + public void testAssertNotEmptyWithNullMapThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.notEmpty((Map) null); + } + }.runTest(); + } + + public void testAssertNotEmptyWithEmptyMapThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.notEmpty(new HashMap()); + } + }.runTest(); + } + + public void testAssertNotEmptyWithMapSunnyDay() throws Exception { + Map map = new HashMap(); + map.put("", ""); + Assert.notEmpty(map); + } + + public void testIsInstanceofClassWithNullInstanceThrowsException() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + Assert.isInstanceOf(String.class, null); + } + }.runTest(); + } + + public void testStateWithFalseExpressionThrowsException() throws Exception { + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + Assert.state(false); + } + }.runTest(); + } + + public void testStateWithTrueExpressionSunnyDay() throws Exception { + Assert.state(true); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/AutoPopulatingListTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/AutoPopulatingListTests.java new file mode 100644 index 00000000000..31cd8626eab --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/AutoPopulatingListTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.util.LinkedList; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AutoPopulatingListTests extends TestCase { + + public void testWithClass() throws Exception { + doTestWithClass(new AutoPopulatingList(TestBean.class)); + } + + public void testWithClassAndUserSuppliedBackingList() throws Exception { + doTestWithClass(new AutoPopulatingList(new LinkedList(), TestBean.class)); + } + + public void testWithElementFactory() throws Exception { + doTestWithElementFactory(new AutoPopulatingList(new MockElementFactory())); + } + + public void testWithElementFactoryAndUserSuppliedBackingList() throws Exception { + doTestWithElementFactory(new AutoPopulatingList(new LinkedList(), new MockElementFactory())); + } + + private void doTestWithClass(AutoPopulatingList list) { + Object lastElement = null; + for (int x = 0; x < 10; x++) { + Object element = list.get(x); + assertNotNull("Element is null", list.get(x)); + assertTrue("Element is incorrect type", element instanceof TestBean); + assertNotSame(lastElement, element); + lastElement = element; + } + + String helloWorld = "Hello World!"; + list.add(10, null); + list.add(11, helloWorld); + assertEquals(helloWorld, list.get(11)); + + assertTrue(list.get(10) instanceof TestBean); + assertTrue(list.get(12) instanceof TestBean); + assertTrue(list.get(13) instanceof TestBean); + assertTrue(list.get(20) instanceof TestBean); + } + + private void doTestWithElementFactory(AutoPopulatingList list) { + doTestWithClass(list); + + for(int x = 0; x < list.size(); x++) { + Object element = list.get(x); + if(element instanceof TestBean) { + assertEquals(x, ((TestBean) element).getAge()); + } + } + } + + public void testSerialization() throws Exception { + AutoPopulatingList list = new AutoPopulatingList(TestBean.class); + assertEquals(list, SerializationTestUtils.serializeAndDeserialize(list)); + } + + + private static class MockElementFactory implements AutoPopulatingList.ElementFactory { + + public Object createElement(int index) { + TestBean bean = new TestBean(); + bean.setAge(index); + return bean; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/CachingMapDecoratorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/CachingMapDecoratorTests.java new file mode 100644 index 00000000000..04623853620 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/CachingMapDecoratorTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import junit.framework.TestCase; + +/** + * @author Keith Donald + */ +public class CachingMapDecoratorTests extends TestCase { + + public void testValidCache() { + MyCachingMap cache = new MyCachingMap(); + Object value; + + value = cache.get("value key"); + assertTrue(cache.createCalled()); + assertEquals(value, "expensive value to cache"); + + cache.get("value key 2"); + assertTrue(cache.createCalled()); + + value = cache.get("value key"); + assertEquals(cache.createCalled(), false); + assertEquals(value, "expensive value to cache"); + + cache.get("value key 2"); + assertEquals(cache.createCalled(), false); + assertEquals(value, "expensive value to cache"); + } + + + private static class MyCachingMap extends CachingMapDecorator { + + private boolean createCalled; + + protected Object create(Object key) { + createCalled = true; + return "expensive value to cache"; + } + + public boolean createCalled() { + boolean c = createCalled; + this.createCalled = false; + return c; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/ClassUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/ClassUtilsTests.java new file mode 100644 index 00000000000..af74cbc5932 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/ClassUtilsTests.java @@ -0,0 +1,320 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.IOther; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @author Rob Harrop + * @author Rick Evans + */ +public class ClassUtilsTests extends TestCase { + + public void setUp() { + InnerClass.noArgCalled = false; + InnerClass.argCalled = false; + InnerClass.overloadedCalled = false; + } + + public void testIsPresent() throws Exception { + assertTrue(ClassUtils.isPresent("java.lang.String")); + assertFalse(ClassUtils.isPresent("java.lang.MySpecialString")); + } + + public void testForName() throws ClassNotFoundException { + assertEquals(String.class, ClassUtils.forName("java.lang.String")); + assertEquals(String[].class, ClassUtils.forName("java.lang.String[]")); + assertEquals(String[].class, ClassUtils.forName(String[].class.getName())); + assertEquals(String[][].class, ClassUtils.forName(String[][].class.getName())); + assertEquals(String[][][].class, ClassUtils.forName(String[][][].class.getName())); + assertEquals(TestBean.class, ClassUtils.forName("org.springframework.beans.TestBean")); + assertEquals(TestBean[].class, ClassUtils.forName("org.springframework.beans.TestBean[]")); + assertEquals(TestBean[].class, ClassUtils.forName(TestBean[].class.getName())); + assertEquals(TestBean[][].class, ClassUtils.forName("org.springframework.beans.TestBean[][]")); + assertEquals(TestBean[][].class, ClassUtils.forName(TestBean[][].class.getName())); + } + + public void testForNameWithPrimitiveClasses() throws ClassNotFoundException { + assertEquals(boolean.class, ClassUtils.forName("boolean")); + assertEquals(byte.class, ClassUtils.forName("byte")); + assertEquals(char.class, ClassUtils.forName("char")); + assertEquals(short.class, ClassUtils.forName("short")); + assertEquals(int.class, ClassUtils.forName("int")); + assertEquals(long.class, ClassUtils.forName("long")); + assertEquals(float.class, ClassUtils.forName("float")); + assertEquals(double.class, ClassUtils.forName("double")); + } + + public void testForNameWithPrimitiveArrays() throws ClassNotFoundException { + assertEquals(boolean[].class, ClassUtils.forName("boolean[]")); + assertEquals(byte[].class, ClassUtils.forName("byte[]")); + assertEquals(char[].class, ClassUtils.forName("char[]")); + assertEquals(short[].class, ClassUtils.forName("short[]")); + assertEquals(int[].class, ClassUtils.forName("int[]")); + assertEquals(long[].class, ClassUtils.forName("long[]")); + assertEquals(float[].class, ClassUtils.forName("float[]")); + assertEquals(double[].class, ClassUtils.forName("double[]")); + } + + public void testForNameWithPrimitiveArraysInternalName() throws ClassNotFoundException { + assertEquals(boolean[].class, ClassUtils.forName(boolean[].class.getName())); + assertEquals(byte[].class, ClassUtils.forName(byte[].class.getName())); + assertEquals(char[].class, ClassUtils.forName(char[].class.getName())); + assertEquals(short[].class, ClassUtils.forName(short[].class.getName())); + assertEquals(int[].class, ClassUtils.forName(int[].class.getName())); + assertEquals(long[].class, ClassUtils.forName(long[].class.getName())); + assertEquals(float[].class, ClassUtils.forName(float[].class.getName())); + assertEquals(double[].class, ClassUtils.forName(double[].class.getName())); + } + + public void testGetShortName() { + String className = ClassUtils.getShortName(getClass()); + assertEquals("Class name did not match", "ClassUtilsTests", className); + } + + public void testGetShortNameForObjectArrayClass() { + String className = ClassUtils.getShortName(Object[].class); + assertEquals("Class name did not match", "Object[]", className); + } + + public void testGetShortNameForMultiDimensionalObjectArrayClass() { + String className = ClassUtils.getShortName(Object[][].class); + assertEquals("Class name did not match", "Object[][]", className); + } + + public void testGetShortNameForPrimitiveArrayClass() { + String className = ClassUtils.getShortName(byte[].class); + assertEquals("Class name did not match", "byte[]", className); + } + + public void testGetShortNameForMultiDimensionalPrimitiveArrayClass() { + String className = ClassUtils.getShortName(byte[][][].class); + assertEquals("Class name did not match", "byte[][][]", className); + } + + public void testGetShortNameForInnerClass() { + String className = ClassUtils.getShortName(InnerClass.class); + assertEquals("Class name did not match", "ClassUtilsTests.InnerClass", className); + } + + public void testGetShortNameForCglibClass() { + TestBean tb = new TestBean(); + ProxyFactory pf = new ProxyFactory(); + pf.setTarget(tb); + pf.setProxyTargetClass(true); + TestBean proxy = (TestBean) pf.getProxy(); + String className = ClassUtils.getShortName(proxy.getClass()); + assertEquals("Class name did not match", "TestBean", className); + } + + public void testGetShortNameAsProperty() { + String shortName = ClassUtils.getShortNameAsProperty(this.getClass()); + assertEquals("Class name did not match", "classUtilsTests", shortName); + } + + public void testGetClassFileName() { + assertEquals("String.class", ClassUtils.getClassFileName(String.class)); + assertEquals("ClassUtilsTests.class", ClassUtils.getClassFileName(getClass())); + } + + public void testGetPackageName() { + assertEquals("java.lang", ClassUtils.getPackageName(String.class)); + assertEquals(getClass().getPackage().getName(), ClassUtils.getPackageName(getClass())); + } + + public void testGetQualifiedName() { + String className = ClassUtils.getQualifiedName(getClass()); + assertEquals("Class name did not match", "org.springframework.util.ClassUtilsTests", className); + } + + public void testGetQualifiedNameForObjectArrayClass() { + String className = ClassUtils.getQualifiedName(Object[].class); + assertEquals("Class name did not match", "java.lang.Object[]", className); + } + + public void testGetQualifiedNameForMultiDimensionalObjectArrayClass() { + String className = ClassUtils.getQualifiedName(Object[][].class); + assertEquals("Class name did not match", "java.lang.Object[][]", className); + } + + public void testGetQualifiedNameForPrimitiveArrayClass() { + String className = ClassUtils.getQualifiedName(byte[].class); + assertEquals("Class name did not match", "byte[]", className); + } + + public void testGetQualifiedNameForMultiDimensionalPrimitiveArrayClass() { + String className = ClassUtils.getQualifiedName(byte[][].class); + assertEquals("Class name did not match", "byte[][]", className); + } + + public void testHasMethod() throws Exception { + assertTrue(ClassUtils.hasMethod(Collection.class, "size", null)); + assertTrue(ClassUtils.hasMethod(Collection.class, "remove", new Class[] {Object.class})); + assertFalse(ClassUtils.hasMethod(Collection.class, "remove", null)); + assertFalse(ClassUtils.hasMethod(Collection.class, "someOtherMethod", null)); + } + + public void testGetMethodIfAvailable() throws Exception { + Method method = ClassUtils.getMethodIfAvailable(Collection.class, "size", null); + assertNotNull(method); + assertEquals("size", method.getName()); + + method = ClassUtils.getMethodIfAvailable(Collection.class, "remove", new Class[] {Object.class}); + assertNotNull(method); + assertEquals("remove", method.getName()); + + assertNull(ClassUtils.getMethodIfAvailable(Collection.class, "remove", null)); + assertNull(ClassUtils.getMethodIfAvailable(Collection.class, "someOtherMethod", null)); + } + + public void testGetMethodCountForName() { + assertEquals("Verifying number of overloaded 'print' methods for OverloadedMethodsClass.", 2, + ClassUtils.getMethodCountForName(OverloadedMethodsClass.class, "print")); + assertEquals("Verifying number of overloaded 'print' methods for SubOverloadedMethodsClass.", 4, + ClassUtils.getMethodCountForName(SubOverloadedMethodsClass.class, "print")); + } + + public void testCountOverloadedMethods() { + assertFalse(ClassUtils.hasAtLeastOneMethodWithName(TestBean.class, "foobar")); + // no args + assertTrue(ClassUtils.hasAtLeastOneMethodWithName(TestBean.class, "hashCode")); + // matches although it takes an arg + assertTrue(ClassUtils.hasAtLeastOneMethodWithName(TestBean.class, "setAge")); + } + + public void testNoArgsStaticMethod() throws IllegalAccessException, InvocationTargetException { + Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", (Class[]) null); + method.invoke(null, (Object[]) null); + assertTrue("no argument method was not invoked.", + InnerClass.noArgCalled); + } + + public void testArgsStaticMethod() throws IllegalAccessException, InvocationTargetException { + Method method = ClassUtils.getStaticMethod(InnerClass.class, "argStaticMethod", + new Class[] {String.class}); + method.invoke(null, new Object[] {"test"}); + assertTrue("argument method was not invoked.", InnerClass.argCalled); + } + + public void testOverloadedStaticMethod() throws IllegalAccessException, InvocationTargetException { + Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", + new Class[] {String.class}); + method.invoke(null, new Object[] {"test"}); + assertTrue("argument method was not invoked.", + InnerClass.overloadedCalled); + } + + public void testClassPackageAsResourcePath() { + String result = ClassUtils.classPackageAsResourcePath(Proxy.class); + assertTrue(result.equals("java/lang/reflect")); + } + + public void testAddResourcePathToPackagePath() { + String result = "java/lang/reflect/xyzabc.xml"; + assertEquals(result, ClassUtils.addResourcePathToPackagePath(Proxy.class, "xyzabc.xml")); + assertEquals(result, ClassUtils.addResourcePathToPackagePath(Proxy.class, "/xyzabc.xml")); + + assertEquals("java/lang/reflect/a/b/c/d.xml", + ClassUtils.addResourcePathToPackagePath(Proxy.class, "a/b/c/d.xml")); + } + + public void testGetAllInterfaces() { + DerivedTestBean testBean = new DerivedTestBean(); + List ifcs = Arrays.asList(ClassUtils.getAllInterfaces(testBean)); + assertEquals("Correct number of interfaces", 7, ifcs.size()); + assertTrue("Contains Serializable", ifcs.contains(Serializable.class)); + assertTrue("Contains ITestBean", ifcs.contains(ITestBean.class)); + assertTrue("Contains IOther", ifcs.contains(IOther.class)); + } + + public void testClassNamesToString() { + List ifcs = new LinkedList(); + ifcs.add(Serializable.class); + ifcs.add(Runnable.class); + assertEquals("[interface java.io.Serializable, interface java.lang.Runnable]", ifcs.toString()); + assertEquals("[java.io.Serializable, java.lang.Runnable]", ClassUtils.classNamesToString(ifcs)); + + List classes = new LinkedList(); + classes.add(LinkedList.class); + classes.add(Integer.class); + assertEquals("[class java.util.LinkedList, class java.lang.Integer]", classes.toString()); + assertEquals("[java.util.LinkedList, java.lang.Integer]", ClassUtils.classNamesToString(classes)); + + assertEquals("[interface java.util.List]", Collections.singletonList(List.class).toString()); + assertEquals("[java.util.List]", ClassUtils.classNamesToString(Collections.singletonList(List.class))); + + assertEquals("[]", Collections.EMPTY_LIST.toString()); + assertEquals("[]", ClassUtils.classNamesToString(Collections.EMPTY_LIST)); + } + + + public static class InnerClass { + + static boolean noArgCalled; + static boolean argCalled; + static boolean overloadedCalled; + + public static void staticMethod() { + noArgCalled = true; + } + + public static void staticMethod(String anArg) { + overloadedCalled = true; + } + + public static void argStaticMethod(String anArg) { + argCalled = true; + } + } + + private static class OverloadedMethodsClass { + public void print(String messages) { + /* no-op */ + } + public void print(String[] messages) { + /* no-op */ + } + } + + private static class SubOverloadedMethodsClass extends OverloadedMethodsClass{ + public void print(String header, String[] messages) { + /* no-op */ + } + void print(String header, String[] messages, String footer) { + /* no-op */ + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/CollectionUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/CollectionUtilsTests.java new file mode 100644 index 00000000000..6f9150a4b72 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/CollectionUtilsTests.java @@ -0,0 +1,226 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import junit.framework.TestCase; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + * @author Rick Evans + */ +public class CollectionUtilsTests extends TestCase { + + public void testIsEmpty() { + assertTrue(CollectionUtils.isEmpty((Set) null)); + assertTrue(CollectionUtils.isEmpty((Map) null)); + assertTrue(CollectionUtils.isEmpty(new HashMap())); + assertTrue(CollectionUtils.isEmpty(new HashSet())); + + List list = new LinkedList(); + list.add(new Object()); + assertFalse(CollectionUtils.isEmpty(list)); + + Map map = new HashMap(); + map.put("foo", "bar"); + assertFalse(CollectionUtils.isEmpty(map)); + } + + public void testMergeArrayIntoCollection() { + Object[] arr = new Object[] {"value1", "value2"}; + List list = new LinkedList(); + list.add("value3"); + + CollectionUtils.mergeArrayIntoCollection(arr, list); + assertEquals("value3", list.get(0)); + assertEquals("value1", list.get(1)); + assertEquals("value2", list.get(2)); + } + + public void testMergePrimitiveArrayIntoCollection() { + int[] arr = new int[] {1, 2}; + List list = new LinkedList(); + list.add(new Integer(3)); + + CollectionUtils.mergeArrayIntoCollection(arr, list); + assertEquals(new Integer(3), list.get(0)); + assertEquals(new Integer(1), list.get(1)); + assertEquals(new Integer(2), list.get(2)); + } + + public void testMergePropertiesIntoMap() { + Properties defaults = new Properties(); + defaults.setProperty("prop1", "value1"); + Properties props = new Properties(defaults); + props.setProperty("prop2", "value2"); + + Map map = new HashMap(); + map.put("prop3", "value3"); + + CollectionUtils.mergePropertiesIntoMap(props, map); + assertEquals("value1", map.get("prop1")); + assertEquals("value2", map.get("prop2")); + assertEquals("value3", map.get("prop3")); + } + + public void testContains() { + assertFalse(CollectionUtils.contains((Iterator) null, "myElement")); + assertFalse(CollectionUtils.contains((Enumeration) null, "myElement")); + assertFalse(CollectionUtils.contains(new LinkedList().iterator(), "myElement")); + assertFalse(CollectionUtils.contains(new Hashtable().keys(), "myElement")); + + List list = new LinkedList(); + list.add("myElement"); + assertTrue(CollectionUtils.contains(list.iterator(), "myElement")); + + Hashtable ht = new Hashtable(); + ht.put("myElement", "myValue"); + assertTrue(CollectionUtils.contains(ht.keys(), "myElement")); + } + + public void testContainsAny() throws Exception { + List source = new ArrayList(); + source.add("abc"); + source.add("def"); + source.add("ghi"); + + List candidates = new ArrayList(); + candidates.add("xyz"); + candidates.add("def"); + candidates.add("abc"); + + assertTrue(CollectionUtils.containsAny(source, candidates)); + candidates.remove("def"); + assertTrue(CollectionUtils.containsAny(source, candidates)); + candidates.remove("abc"); + assertFalse(CollectionUtils.containsAny(source, candidates)); + } + + public void testContainsInstanceWithNullCollection() throws Exception { + assertFalse("Must return false if supplied Collection argument is null", + CollectionUtils.containsInstance(null, this)); + } + + public void testContainsInstanceWithInstancesThatAreEqualButDistinct() throws Exception { + List list = new ArrayList(); + list.add(new Instance("fiona")); + assertFalse("Must return false if instance is not in the supplied Collection argument", + CollectionUtils.containsInstance(list, new Instance("fiona"))); + } + + public void testContainsInstanceWithSameInstance() throws Exception { + List list = new ArrayList(); + list.add(new Instance("apple")); + Instance instance = new Instance("fiona"); + list.add(instance); + assertTrue("Must return true if instance is in the supplied Collection argument", + CollectionUtils.containsInstance(list, instance)); + } + + public void testContainsInstanceWithNullInstance() throws Exception { + List list = new ArrayList(); + list.add(new Instance("apple")); + list.add(new Instance("fiona")); + assertFalse("Must return false if null instance is supplied", + CollectionUtils.containsInstance(list, null)); + } + + public void testFindFirstMatch() throws Exception { + List source = new ArrayList(); + source.add("abc"); + source.add("def"); + source.add("ghi"); + + List candidates = new ArrayList(); + candidates.add("xyz"); + candidates.add("def"); + candidates.add("abc"); + + assertEquals("def", CollectionUtils.findFirstMatch(source, candidates)); + } + + public void testHasUniqueObject() { + List list = new LinkedList(); + list.add("myElement"); + list.add("myOtherElement"); + assertFalse(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList(); + list.add("myElement"); + assertTrue(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList(); + list.add("myElement"); + list.add(null); + assertFalse(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList(); + list.add(null); + list.add("myElement"); + assertFalse(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList(); + list.add(null); + list.add(null); + assertTrue(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList(); + list.add(null); + assertTrue(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList(); + assertFalse(CollectionUtils.hasUniqueObject(list)); + } + + + private static final class Instance { + + private final String name; + + public Instance(String name) { + this.name = name; + } + + public boolean equals(Object rhs) { + if (this == rhs) { + return true; + } + if (rhs == null || this.getClass() != rhs.getClass()) { + return false; + } + Instance instance = (Instance) rhs; + return this.name.equals(instance.name); + } + + public int hashCode() { + return this.name.hashCode(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/FileCopyUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/FileCopyUtilsTests.java new file mode 100644 index 00000000000..6848c4d197f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/FileCopyUtilsTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Arrays; + +import junit.framework.TestCase; + +/** + * Unit tests for the FileCopyUtils class. + * + * @author Juergen Hoeller + * @since 12.03.2005 + */ +public class FileCopyUtilsTests extends TestCase { + + public void testCopyFromInputStream() throws IOException { + byte[] content = "content".getBytes(); + ByteArrayInputStream in = new ByteArrayInputStream(content); + ByteArrayOutputStream out = new ByteArrayOutputStream(content.length); + int count = FileCopyUtils.copy(in, out); + assertEquals(content.length, count); + assertTrue(Arrays.equals(content, out.toByteArray())); + } + + public void testCopyFromByteArray() throws IOException { + byte[] content = "content".getBytes(); + ByteArrayOutputStream out = new ByteArrayOutputStream(content.length); + FileCopyUtils.copy(content, out); + assertTrue(Arrays.equals(content, out.toByteArray())); + } + + public void testCopyToByteArray() throws IOException { + byte[] content = "content".getBytes(); + ByteArrayInputStream in = new ByteArrayInputStream(content); + byte[] result = FileCopyUtils.copyToByteArray(in); + assertTrue(Arrays.equals(content, result)); + } + + public void testCopyFromReader() throws IOException { + String content = "content"; + StringReader in = new StringReader(content); + StringWriter out = new StringWriter(); + int count = FileCopyUtils.copy(in, out); + assertEquals(content.length(), count); + assertEquals(content, out.toString()); + } + + public void testCopyFromString() throws IOException { + String content = "content"; + StringWriter out = new StringWriter(); + FileCopyUtils.copy(content, out); + assertEquals(content, out.toString()); + } + + public void testCopyToString() throws IOException { + String content = "content"; + StringReader in = new StringReader(content); + String result = FileCopyUtils.copyToString(in); + assertEquals(content, result); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/FileSystemUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/FileSystemUtilsTests.java new file mode 100644 index 00000000000..f15b52ffc4d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/FileSystemUtilsTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.File; + +import junit.framework.TestCase; + +/** + * @author Rob Harrop + */ +public class FileSystemUtilsTests extends TestCase { + + public void testDeleteRecursively() throws Exception { + File root = new File("./tmp/root"); + File child = new File(root, "child"); + File grandchild = new File(child, "grandchild"); + + grandchild.mkdirs(); + + File bar = new File(child, "bar.txt"); + bar.createNewFile(); + + assertTrue(root.exists()); + assertTrue(child.exists()); + assertTrue(grandchild.exists()); + assertTrue(bar.exists()); + + FileSystemUtils.deleteRecursively(root); + + assertFalse(root.exists()); + assertFalse(child.exists()); + assertFalse(grandchild.exists()); + assertFalse(bar.exists()); + } + + public void testCopyRecursively() throws Exception { + File src = new File("./tmp/src"); + File child = new File(src, "child"); + File grandchild = new File(child, "grandchild"); + + grandchild.mkdirs(); + + File bar = new File(child, "bar.txt"); + bar.createNewFile(); + + assertTrue(src.exists()); + assertTrue(child.exists()); + assertTrue(grandchild.exists()); + assertTrue(bar.exists()); + + File dest = new File("./dest"); + FileSystemUtils.copyRecursively(src, dest); + + assertTrue(dest.exists()); + assertTrue(new File(dest, child.getName()).exists()); + + FileSystemUtils.deleteRecursively(src); + assertTrue(!src.exists()); + } + + protected void tearDown() throws Exception { + File tmp = new File("./tmp"); + if (tmp.exists()) { + FileSystemUtils.deleteRecursively(tmp); + } + File dest = new File("./dest"); + if (dest.exists()) { + FileSystemUtils.deleteRecursively(dest); + } + super.tearDown(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/Log4jConfigurerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/Log4jConfigurerTests.java new file mode 100644 index 00000000000..5b36d46f893 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/Log4jConfigurerTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.FileNotFoundException; +import java.net.URL; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author Alef Arendsen + * @author Juergen Hoeller + */ +public class Log4jConfigurerTests extends TestCase { + + public void testInitLoggingWithClasspath() throws FileNotFoundException { + doTestInitLogging("classpath:org/springframework/util/testlog4j.properties", false); + } + + public void testInitLoggingWithRelativeFilePath() throws FileNotFoundException { + doTestInitLogging("test/org/springframework/util/testlog4j.properties", false); + } + + public void testInitLoggingWithAbsoluteFilePath() throws FileNotFoundException { + URL url = getClass().getResource("testlog4j.properties"); + doTestInitLogging(url.toString(), false); + } + + public void testInitLoggingWithClasspathAndRefreshInterval() throws FileNotFoundException { + doTestInitLogging("classpath:org/springframework/util/testlog4j.properties", true); + } + + public void testInitLoggingWithRelativeFilePathAndRefreshInterval() throws FileNotFoundException { + doTestInitLogging("test/org/springframework/util/testlog4j.properties", true); + } + + /* only works on Windows + public void testInitLoggingWithAbsoluteFilePathAndRefreshInterval() throws FileNotFoundException { + URL url = getClass().getResource("testlog4j.properties"); + doTestInitLogging(url.getFile(), true); + } + */ + + public void testInitLoggingWithFileUrlAndRefreshInterval() throws FileNotFoundException { + URL url = getClass().getResource("testlog4j.properties"); + doTestInitLogging(url.toString(), true); + } + + private void doTestInitLogging(String location, boolean refreshInterval) throws FileNotFoundException { + if (refreshInterval) { + Log4jConfigurer.initLogging(location, 10); + } + else { + Log4jConfigurer.initLogging(location); + } + + Log log = LogFactory.getLog(this.getClass()); + log.debug("debug"); + log.info("info"); + log.warn("warn"); + log.error("error"); + log.fatal("fatal"); + + assertTrue(MockLog4jAppender.loggingStrings.contains("debug")); + assertTrue(MockLog4jAppender.loggingStrings.contains("info")); + assertTrue(MockLog4jAppender.loggingStrings.contains("warn")); + assertTrue(MockLog4jAppender.loggingStrings.contains("error")); + assertTrue(MockLog4jAppender.loggingStrings.contains("fatal")); + + Log4jConfigurer.shutdownLogging(); + assertTrue(MockLog4jAppender.closeCalled); + } + + public void testInitLoggingWithRefreshIntervalAndFileNotFound() throws FileNotFoundException { + try { + Log4jConfigurer.initLogging("test/org/springframework/util/bla.properties", 10); + fail("Exception should have been thrown, file does not exist!"); + } + catch (FileNotFoundException ex) { + // OK + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/MethodInvokerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/MethodInvokerTests.java new file mode 100644 index 00000000000..955d788c746 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/MethodInvokerTests.java @@ -0,0 +1,285 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @since 21.11.2003 + */ +public class MethodInvokerTests extends TestCase { + + public void testPlainMethodInvoker() throws Exception { + // sanity check: singleton, non-static should work + TestClass1 tc1 = new TestClass1(); + MethodInvoker mi = new MethodInvoker(); + mi.setTargetObject(tc1); + mi.setTargetMethod("method1"); + mi.prepare(); + Integer i = (Integer) mi.invoke(); + assertEquals(1, i.intValue()); + + // sanity check: check that argument count matching works + mi = new MethodInvoker(); + mi.setTargetClass(TestClass1.class); + mi.setTargetMethod("supertypes"); + mi.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello"}); + mi.prepare(); + assertEquals("hello", mi.invoke()); + + mi = new MethodInvoker(); + mi.setTargetClass(TestClass1.class); + mi.setTargetMethod("supertypes2"); + mi.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello", "bogus"}); + mi.prepare(); + assertEquals("hello", mi.invoke()); + + // Sanity check: check that argument conversion doesn't work with plain MethodInvoker + mi = new MethodInvoker(); + mi.setTargetClass(TestClass1.class); + mi.setTargetMethod("supertypes2"); + mi.setArguments(new Object[] {new ArrayList(), new ArrayList(), "hello", Boolean.TRUE}); + try { + mi.prepare(); + fail("Shouldn't have matched without argument conversion"); + } + catch (NoSuchMethodException ex) { + // expected + } + } + + public void testStringWithMethodInvoker() throws Exception { + try { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new String("no match")}); + methodInvoker.prepare(); + fail("Should have thrown a NoSuchMethodException"); + } + catch (NoSuchMethodException e) { + // expected + } + } + + public void testPurchaserWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Purchaser()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("purchaser: hello", greeting); + } + + public void testShopperWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Shopper()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("purchaser: may I help you?", greeting); + } + + public void testSalesmanWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Salesman()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("greetable: how are sales?", greeting); + } + + public void testCustomerWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Customer()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("customer: good day", greeting); + } + + public void testRegularWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Regular("Kotter")}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("regular: welcome back Kotter", greeting); + } + + public void testVIPWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new VIP("Fonzie")}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("regular: whassup dude?", greeting); + } + + + public static class TestClass1 { + + public static int _staticField1; + + public int _field1 = 0; + + public int method1() { + return ++_field1; + } + + public static int staticMethod1() { + return ++TestClass1._staticField1; + } + + public static void voidRetvalMethod() { + } + + public static void nullArgument(Object arg) { + } + + public static void intArgument(int arg) { + } + + public static void intArguments(int[] arg) { + } + + public static String supertypes(Collection c, Integer i) { + return i.toString(); + } + + public static String supertypes(Collection c, List l, String s) { + return s; + } + + public static String supertypes2(Collection c, List l, Integer i) { + return i.toString(); + } + + public static String supertypes2(Collection c, List l, String s, Integer i) { + return s; + } + + public static String supertypes2(Collection c, List l, String s, String s2) { + return s; + } + } + + + public static class Greeter { + + // should handle Salesman (only interface) + public String greet(Greetable greetable) { + return "greetable: " + greetable.getGreeting(); + } + + // should handle Shopper (beats Greetable since it is a class) + protected String greet(Purchaser purchaser) { + return "purchaser: " + purchaser.getGreeting(); + } + + // should handle Customer (exact match) + String greet(Customer customer) { + return "customer: " + customer.getGreeting(); + } + + // should handle Regular (exact) and VIP (closest match) + private String greet(Regular regular) { + return "regular: " + regular.getGreeting(); + } + } + + + private static interface Greetable { + + String getGreeting(); + } + + + private static interface Person extends Greetable { + } + + + private static class Purchaser implements Greetable { + + public String getGreeting() { + return "hello"; + } + } + + + private static class Shopper extends Purchaser implements Person { + + public String getGreeting() { + return "may I help you?"; + } + } + + + private static class Salesman implements Person { + + public String getGreeting() { + return "how are sales?"; + } + } + + + private static class Customer extends Shopper { + + public String getGreeting() { + return "good day"; + } + } + + + private static class Regular extends Customer { + + private String name; + + public Regular(String name) { + this.name = name; + } + + public String getGreeting() { + return "welcome back " + name ; + } + } + + + private static class VIP extends Regular { + + public VIP(String name) { + super(name); + } + + public String getGreeting() { + return "whassup dude?"; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/MockLog4jAppender.java b/org.springframework.testsuite/src/test/java/org/springframework/util/MockLog4jAppender.java new file mode 100644 index 00000000000..18bc8b2d5b2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/MockLog4jAppender.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.LoggingEvent; + +/** + * @author Alef Arendsen + */ +public class MockLog4jAppender extends AppenderSkeleton { + + public static final List loggingStrings = new ArrayList(); + + public static boolean closeCalled = false; + + /* (non-Javadoc) + * @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent) + */ + protected void append(LoggingEvent evt) { + //System.out.println("Adding " + evt.getMessage()); + loggingStrings.add(evt.getMessage()); + } + + /* (non-Javadoc) + * @see org.apache.log4j.Appender#close() + */ + public void close() { + closeCalled = true; + } + + /* (non-Javadoc) + * @see org.apache.log4j.Appender#requiresLayout() + */ + public boolean requiresLayout() { + return false; + } + + + + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/NumberUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/NumberUtilsTests.java new file mode 100644 index 00000000000..aae2b8a7d5b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/NumberUtilsTests.java @@ -0,0 +1,348 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.NumberFormat; +import java.util.Locale; + +import junit.framework.TestCase; + +import org.springframework.core.JdkVersion; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class NumberUtilsTests extends TestCase { + + public void testParseNumber() { + String aByte = "" + Byte.MAX_VALUE; + String aShort = "" + Short.MAX_VALUE; + String anInteger = "" + Integer.MAX_VALUE; + String aLong = "" + Long.MAX_VALUE; + String aFloat = "" + Float.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseNumberUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aByte = "" + Byte.MAX_VALUE; + String aShort = "" + Short.MAX_VALUE; + String anInteger = "" + Integer.MAX_VALUE; + String aLong = "" + Long.MAX_VALUE; + String aFloat = "" + Float.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class, nf)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class, nf)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class, nf)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class, nf)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + public void testParseWithTrim() { + String aByte = " " + Byte.MAX_VALUE + " "; + String aShort = " " + Short.MAX_VALUE + " "; + String anInteger = " " + Integer.MAX_VALUE + " "; + String aLong = " " + Long.MAX_VALUE + " "; + String aFloat = " " + Float.MAX_VALUE + " "; + String aDouble = " " + Double.MAX_VALUE + " "; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseWithTrimUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aByte = " " + Byte.MAX_VALUE + " "; + String aShort = " " + Short.MAX_VALUE + " "; + String anInteger = " " + Integer.MAX_VALUE + " "; + String aLong = " " + Long.MAX_VALUE + " "; + String aFloat = " " + Float.MAX_VALUE + " "; + String aDouble = " " + Double.MAX_VALUE + " "; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class, nf)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class, nf)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class, nf)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class, nf)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + public void testParseAsHex() { + String aByte = "0x" + Integer.toHexString(new Byte(Byte.MAX_VALUE).intValue()); + String aShort = "0x" + Integer.toHexString(new Short(Short.MAX_VALUE).intValue()); + String anInteger = "0x" + Integer.toHexString(Integer.MAX_VALUE); + String aLong = "0x" + Long.toHexString(Long.MAX_VALUE); + String aReallyBigInt = "FEBD4E677898DFEBFFEE44"; + + assertByteEquals(aByte); + assertShortEquals(aShort); + assertIntegerEquals(anInteger); + assertLongEquals(aLong); + assertEquals("BigInteger did not parse", + new BigInteger(aReallyBigInt, 16), NumberUtils.parseNumber("0x" + aReallyBigInt, BigInteger.class)); + } + + public void testParseNegativeHex() { + String aByte = "-0x80"; + String aShort = "-0x8000"; + String anInteger = "-0x80000000"; + String aLong = "-0x8000000000000000"; + String aReallyBigInt = "FEBD4E677898DFEBFFEE44"; + + assertNegativeByteEquals(aByte); + assertNegativeShortEquals(aShort); + assertNegativeIntegerEquals(anInteger); + assertNegativeLongEquals(aLong); + assertEquals("BigInteger did not parse", + new BigInteger(aReallyBigInt, 16).negate(), NumberUtils.parseNumber("-0x" + aReallyBigInt, BigInteger.class)); + } + + public void testDoubleToBigInteger() { + Double decimal = new Double(3.14d); + assertEquals(new BigInteger("3"), NumberUtils.convertNumberToTargetClass(decimal, BigInteger.class)); + } + + public void testBigDecimalToBigInteger() { + String number = "987459837583750387355346"; + BigDecimal decimal = new BigDecimal(number); + assertEquals(new BigInteger(number), NumberUtils.convertNumberToTargetClass(decimal, BigInteger.class)); + } + + public void testNonExactBigDecimalToBigInteger() { + BigDecimal decimal = new BigDecimal("987459837583750387355346.14"); + assertEquals(new BigInteger("987459837583750387355346"), NumberUtils.convertNumberToTargetClass(decimal, BigInteger.class)); + } + + public void testParseBigDecimalNumber1() { + String bigDecimalAsString = "0.10"; + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseBigDecimalNumber2() { + String bigDecimalAsString = "0.001"; + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseBigDecimalNumber3() { + String bigDecimalAsString = "3.14159265358979323846"; + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseLocalizedBigDecimalNumber1() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + String bigDecimalAsString = "0.10"; + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class, numberFormat); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseLocalizedBigDecimalNumber2() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + String bigDecimalAsString = "0.001"; + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class, numberFormat); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseLocalizedBigDecimalNumber3() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + String bigDecimalAsString = "3.14159265358979323846"; + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class, numberFormat); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseOverflow() { + String aLong = "" + Long.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + + assertEquals(new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseNegativeOverflow() { + String aLong = "" + Long.MIN_VALUE; + String aDouble = "" + Double.MIN_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MIN_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + + assertEquals(new Double(Double.MIN_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseOverflowUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aLong = "" + Long.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + + assertEquals(new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + public void testParseNegativeOverflowUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aLong = "" + Long.MIN_VALUE; + String aDouble = "" + Double.MIN_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MIN_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + + assertEquals(new Double(Double.MIN_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + private void assertLongEquals(String aLong) { + assertEquals("Long did not parse", Long.MAX_VALUE, NumberUtils.parseNumber(aLong, Long.class).longValue()); + } + + private void assertIntegerEquals(String anInteger) { + assertEquals("Integer did not parse", Integer.MAX_VALUE, NumberUtils.parseNumber(anInteger, Integer.class).intValue()); + } + + private void assertShortEquals(String aShort) { + assertEquals("Short did not parse", Short.MAX_VALUE, NumberUtils.parseNumber(aShort, Short.class).shortValue()); + } + + private void assertByteEquals(String aByte) { + assertEquals("Byte did not parse", Byte.MAX_VALUE, NumberUtils.parseNumber(aByte, Byte.class).byteValue()); + } + + private void assertNegativeLongEquals(String aLong) { + assertEquals("Long did not parse", Long.MIN_VALUE, NumberUtils.parseNumber(aLong, Long.class).longValue()); + } + + private void assertNegativeIntegerEquals(String anInteger) { + assertEquals("Integer did not parse", Integer.MIN_VALUE, NumberUtils.parseNumber(anInteger, Integer.class).intValue()); + } + + private void assertNegativeShortEquals(String aShort) { + assertEquals("Short did not parse", Short.MIN_VALUE, NumberUtils.parseNumber(aShort, Short.class).shortValue()); + } + + private void assertNegativeByteEquals(String aByte) { + assertEquals("Byte did not parse", Byte.MIN_VALUE, NumberUtils.parseNumber(aByte, Byte.class).byteValue()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/ObjectUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/ObjectUtilsTests.java new file mode 100644 index 00000000000..a963e17258b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/ObjectUtilsTests.java @@ -0,0 +1,627 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.IOException; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.beans.FatalBeanException; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + */ +public final class ObjectUtilsTests extends TestCase { + + public void testIsCheckedException() { + assertTrue(ObjectUtils.isCheckedException(new Exception())); + assertTrue(ObjectUtils.isCheckedException(new ServletException())); + + assertFalse(ObjectUtils.isCheckedException(new RuntimeException())); + assertFalse(ObjectUtils.isCheckedException(new FatalBeanException(""))); + + // Any Throwable other than RuntimeException and Error + // has to be considered checked according to the JLS. + assertTrue(ObjectUtils.isCheckedException(new Throwable())); + } + + public void testIsCompatibleWithThrowsClause() { + Class[] empty = new Class[0]; + Class[] exception = new Class[] {Exception.class}; + Class[] servletAndIO = new Class[] {ServletException.class, IOException.class}; + Class[] throwable = new Class[] {Throwable.class}; + + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), null)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), empty)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), exception)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), servletAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), throwable)); + + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), null)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), empty)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), exception)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), servletAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), throwable)); + + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new ServletException(), null)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new ServletException(), empty)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new ServletException(), exception)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new ServletException(), servletAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new ServletException(), throwable)); + + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), null)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), empty)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), exception)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), servletAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), throwable)); + } + + public void testToObjectArray() { + int[] a = new int[] {1, 2, 3, 4, 5}; + Integer[] wrapper = (Integer[]) ObjectUtils.toObjectArray(a); + assertTrue(wrapper.length == 5); + for (int i = 0; i < wrapper.length; i++) { + assertEquals(a[i], wrapper[i].intValue()); + } + } + + public void testToObjectArrayWithNull() { + Object[] objects = ObjectUtils.toObjectArray(null); + assertNotNull(objects); + assertEquals(0, objects.length); + } + + public void testToObjectArrayWithEmptyPrimitiveArray() { + Object[] objects = ObjectUtils.toObjectArray(new byte[] {}); + assertNotNull(objects); + assertEquals(0, objects.length); + } + + public void testToObjectArrayWithNonArrayType() { + try { + ObjectUtils.toObjectArray("Not an []"); + fail("Must have thrown an IllegalArgumentException by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + public void testToObjectArrayWithNonPrimitiveArray() { + String[] source = new String[] {"Bingo"}; + assertEquals(source, ObjectUtils.toObjectArray(source)); + } + + public void testAddObjectToArraySunnyDay() { + String[] array = new String[] {"foo", "bar"}; + String newElement = "baz"; + Object[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(3, newArray.length); + assertEquals(newElement, newArray[2]); + } + + public void testAddObjectToArrayWhenEmpty() { + String[] array = new String[0]; + String newElement = "foo"; + Object[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(1, newArray.length); + assertEquals(newElement, newArray[0]); + } + + public void testAddObjectToSingleNonNullElementArray() { + String existingElement = "foo"; + String[] array = new String[] {existingElement}; + String newElement = "bar"; + Object[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(2, newArray.length); + assertEquals(existingElement, newArray[0]); + assertEquals(newElement, newArray[1]); + } + + public void testAddObjectToSingleNullElementArray() { + String[] array = new String[] {null}; + String newElement = "bar"; + Object[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(2, newArray.length); + assertEquals(null, newArray[0]); + assertEquals(newElement, newArray[1]); + } + + public void testAddObjectToNullArray() throws Exception { + String newElement = "foo"; + Object[] newArray = ObjectUtils.addObjectToArray(null, newElement); + assertEquals(1, newArray.length); + assertEquals(newElement, newArray[0]); + } + + public void testAddNullObjectToNullArray() throws Exception { + Object[] newArray = ObjectUtils.addObjectToArray(null, null); + assertEquals(1, newArray.length); + assertEquals(null, newArray[0]); + } + + public void testNullSafeEqualsWithArrays() throws Exception { + assertTrue(ObjectUtils.nullSafeEquals(new String[] {"a", "b", "c"}, new String[] {"a", "b", "c"})); + assertTrue(ObjectUtils.nullSafeEquals(new int[] {1, 2, 3}, new int[] {1, 2, 3})); + } + + public void testHashCodeWithBooleanFalse() { + int expected = Boolean.FALSE.hashCode(); + assertEquals(expected, ObjectUtils.hashCode(false)); + } + + public void testHashCodeWithBooleanTrue() { + int expected = Boolean.TRUE.hashCode(); + assertEquals(expected, ObjectUtils.hashCode(true)); + } + + public void testHashCodeWithDouble() { + double dbl = 9830.43; + int expected = (new Double(dbl)).hashCode(); + assertEquals(expected, ObjectUtils.hashCode(dbl)); + } + + public void testHashCodeWithFloat() { + float flt = 34.8f; + int expected = (new Float(flt)).hashCode(); + assertEquals(expected, ObjectUtils.hashCode(flt)); + } + + public void testHashCodeWithLong() { + long lng = 883l; + int expected = (new Long(lng)).hashCode(); + assertEquals(expected, ObjectUtils.hashCode(lng)); + } + + public void testIdentityToString() { + Object obj = new Object(); + String expected = obj.getClass().getName() + "@" + ObjectUtils.getIdentityHexString(obj); + String actual = ObjectUtils.identityToString(obj); + assertEquals(expected.toString(), actual); + } + + public void testIdentityToStringWithNullObject() { + assertEquals("", ObjectUtils.identityToString(null)); + } + + public void testIsArrayOfPrimitivesWithBooleanArray() { + assertTrue(ClassUtils.isPrimitiveArray(boolean[].class)); + } + + public void testIsArrayOfPrimitivesWithObjectArray() { + assertFalse(ClassUtils.isPrimitiveArray(Object[].class)); + } + + public void testIsArrayOfPrimitivesWithNonArray() { + assertFalse(ClassUtils.isPrimitiveArray(String.class)); + } + + public void testIsPrimitiveOrWrapperWithBooleanPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(boolean.class)); + } + + public void testIsPrimitiveOrWrapperWithBooleanWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Boolean.class)); + } + + public void testIsPrimitiveOrWrapperWithBytePrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(byte.class)); + } + + public void testIsPrimitiveOrWrapperWithByteWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Byte.class)); + } + + public void testIsPrimitiveOrWrapperWithCharacterClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Character.class)); + } + + public void testIsPrimitiveOrWrapperWithCharClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(char.class)); + } + + public void testIsPrimitiveOrWrapperWithDoublePrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(double.class)); + } + + public void testIsPrimitiveOrWrapperWithDoubleWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Double.class)); + } + + public void testIsPrimitiveOrWrapperWithFloatPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(float.class)); + } + + public void testIsPrimitiveOrWrapperWithFloatWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Float.class)); + } + + public void testIsPrimitiveOrWrapperWithIntClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(int.class)); + } + + public void testIsPrimitiveOrWrapperWithIntegerClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Integer.class)); + } + + public void testIsPrimitiveOrWrapperWithLongPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(long.class)); + } + + public void testIsPrimitiveOrWrapperWithLongWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Long.class)); + } + + public void testIsPrimitiveOrWrapperWithNonPrimitiveOrWrapperClass() { + assertFalse(ClassUtils.isPrimitiveOrWrapper(Object.class)); + } + + public void testIsPrimitiveOrWrapperWithShortPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(short.class)); + } + + public void testIsPrimitiveOrWrapperWithShortWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Short.class)); + } + + public void testNullSafeHashCodeWithBooleanArray() { + int expected = 31 * 7 + Boolean.TRUE.hashCode(); + expected = 31 * expected + Boolean.FALSE.hashCode(); + + boolean[] array = {true, false}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithBooleanArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((boolean[]) null)); + } + + public void testNullSafeHashCodeWithByteArray() { + int expected = 31 * 7 + 8; + expected = 31 * expected + 10; + + byte[] array = {8, 10}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithByteArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((byte[]) null)); + } + + public void testNullSafeHashCodeWithCharArray() { + int expected = 31 * 7 + 'a'; + expected = 31 * expected + 'E'; + + char[] array = {'a', 'E'}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithCharArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((char[]) null)); + } + + public void testNullSafeHashCodeWithDoubleArray() { + long bits = Double.doubleToLongBits(8449.65); + int expected = 31 * 7 + (int) (bits ^ (bits >>> 32)); + bits = Double.doubleToLongBits(9944.923); + expected = 31 * expected + (int) (bits ^ (bits >>> 32)); + + double[] array = {8449.65, 9944.923}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithDoubleArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((double[]) null)); + } + + public void testNullSafeHashCodeWithFloatArray() { + int expected = 31 * 7 + Float.floatToIntBits(9.6f); + expected = 31 * expected + Float.floatToIntBits(7.4f); + + float[] array = {9.6f, 7.4f}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithFloatArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((float[]) null)); + } + + public void testNullSafeHashCodeWithIntArray() { + int expected = 31 * 7 + 884; + expected = 31 * expected + 340; + + int[] array = {884, 340}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithIntArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((int[]) null)); + } + + public void testNullSafeHashCodeWithLongArray() { + long lng = 7993l; + int expected = 31 * 7 + (int) (lng ^ (lng >>> 32)); + lng = 84320l; + expected = 31 * expected + (int) (lng ^ (lng >>> 32)); + + long[] array = {7993l, 84320l}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithLongArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((long[]) null)); + } + + public void testNullSafeHashCodeWithObject() { + String str = "Luke"; + assertEquals(str.hashCode(), ObjectUtils.nullSafeHashCode(str)); + } + + public void testNullSafeHashCodeWithObjectArray() { + int expected = 31 * 7 + "Leia".hashCode(); + expected = 31 * expected + "Han".hashCode(); + + Object[] array = {"Leia", "Han"}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithObjectArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((Object[]) null)); + } + + public void testNullSafeHashCodeWithObjectBeingBooleanArray() { + Object array = new boolean[] {true, false}; + int expected = ObjectUtils.nullSafeHashCode((boolean[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingByteArray() { + Object array = new byte[] {6, 39}; + int expected = ObjectUtils.nullSafeHashCode((byte[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingCharArray() { + Object array = new char[] {'l', 'M'}; + int expected = ObjectUtils.nullSafeHashCode((char[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingDoubleArray() { + Object array = new double[] {68930.993, 9022.009}; + int expected = ObjectUtils.nullSafeHashCode((double[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingFloatArray() { + Object array = new float[] {9.9f, 9.54f}; + int expected = ObjectUtils.nullSafeHashCode((float[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingIntArray() { + Object array = new int[] {89, 32}; + int expected = ObjectUtils.nullSafeHashCode((int[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingLongArray() { + Object array = new long[] {4389, 320}; + int expected = ObjectUtils.nullSafeHashCode((long[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingObjectArray() { + Object array = new Object[] {"Luke", "Anakin"}; + int expected = ObjectUtils.nullSafeHashCode((Object[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectBeingShortArray() { + Object array = new short[] {5, 3}; + int expected = ObjectUtils.nullSafeHashCode((short[]) array); + assertEqualHashCodes(expected, array); + } + + public void testNullSafeHashCodeWithObjectEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((Object) null)); + } + + public void testNullSafeHashCodeWithShortArray() { + int expected = 31 * 7 + 70; + expected = 31 * expected + 8; + + short[] array = {70, 8}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + public void testNullSafeHashCodeWithShortArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((short[]) null)); + } + + public void testNullSafeToStringWithBooleanArray() { + boolean[] array = {true, false}; + assertEquals("{true, false}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithBooleanArrayBeingEmpty() { + boolean[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithBooleanArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((boolean[]) null)); + } + + public void testNullSafeToStringWithByteArray() { + byte[] array = {5, 8}; + assertEquals("{5, 8}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithByteArrayBeingEmpty() { + byte[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithByteArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((byte[]) null)); + } + + public void testNullSafeToStringWithCharArray() { + char[] array = {'A', 'B'}; + assertEquals("{'A', 'B'}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithCharArrayBeingEmpty() { + char[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithCharArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((char[]) null)); + } + + public void testNullSafeToStringWithDoubleArray() { + double[] array = {8594.93, 8594023.95}; + assertEquals("{8594.93, 8594023.95}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithDoubleArrayBeingEmpty() { + double[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithDoubleArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((double[]) null)); + } + + public void testNullSafeToStringWithFloatArray() { + float[] array = {8.6f, 43.8f}; + assertEquals("{8.6, 43.8}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithFloatArrayBeingEmpty() { + float[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithFloatArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((float[]) null)); + } + + public void testNullSafeToStringWithIntArray() { + int[] array = {9, 64}; + assertEquals("{9, 64}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithIntArrayBeingEmpty() { + int[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithIntArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((int[]) null)); + } + + public void testNullSafeToStringWithLongArray() { + long[] array = {434l, 23423l}; + assertEquals("{434, 23423}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithLongArrayBeingEmpty() { + long[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithLongArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((long[]) null)); + } + + public void testNullSafeToStringWithPlainOldString() { + assertEquals("I shoh love tha taste of mangoes", ObjectUtils.nullSafeToString("I shoh love tha taste of mangoes")); + } + + public void testNullSafeToStringWithObjectArray() { + Object[] array = {"Han", new Long(43)}; + assertEquals("{Han, 43}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithObjectArrayBeingEmpty() { + Object[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithObjectArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((Object[]) null)); + } + + public void testNullSafeToStringWithShortArray() { + short[] array = {7, 9}; + assertEquals("{7, 9}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithShortArrayBeingEmpty() { + short[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithShortArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((short[]) null)); + } + + public void testNullSafeToStringWithStringArray() { + String[] array = {"Luke", "Anakin"}; + assertEquals("{Luke, Anakin}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithStringArrayBeingEmpty() { + String[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + public void testNullSafeToStringWithStringArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((String[]) null)); + } + + private void assertEqualHashCodes(int expected, Object array) { + int actual = ObjectUtils.nullSafeHashCode(array); + assertEquals(expected, actual); + assertTrue(array.hashCode() != actual); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/PathMatcherTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/PathMatcherTests.java new file mode 100644 index 00000000000..8ac4e00801c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/PathMatcherTests.java @@ -0,0 +1,285 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import junit.framework.TestCase; + +/** + * @author Alef Arendsen + * @author Seth Ladd + * @author Juergen Hoeller + */ +public class PathMatcherTests extends TestCase { + + public void testAntPathMatcher() { + PathMatcher pathMatcher = new AntPathMatcher(); + + // test exact matching + assertTrue(pathMatcher.match("test", "test")); + assertTrue(pathMatcher.match("/test", "/test")); + assertFalse(pathMatcher.match("/test.jpg", "test.jpg")); + assertFalse(pathMatcher.match("test", "/test")); + assertFalse(pathMatcher.match("/test", "test")); + + // test matching with ?'s + assertTrue(pathMatcher.match("t?st", "test")); + assertTrue(pathMatcher.match("??st", "test")); + assertTrue(pathMatcher.match("tes?", "test")); + assertTrue(pathMatcher.match("te??", "test")); + assertTrue(pathMatcher.match("?es?", "test")); + assertFalse(pathMatcher.match("tes?", "tes")); + assertFalse(pathMatcher.match("tes?", "testt")); + assertFalse(pathMatcher.match("tes?", "tsst")); + + // test matchin with *'s + assertTrue(pathMatcher.match("*", "test")); + assertTrue(pathMatcher.match("test*", "test")); + assertTrue(pathMatcher.match("test*", "testTest")); + assertTrue(pathMatcher.match("test/*", "test/Test")); + assertTrue(pathMatcher.match("test/*", "test/t")); + assertTrue(pathMatcher.match("test/*", "test/")); + assertTrue(pathMatcher.match("*test*", "AnothertestTest")); + assertTrue(pathMatcher.match("*test", "Anothertest")); + assertTrue(pathMatcher.match("*.*", "test.")); + assertTrue(pathMatcher.match("*.*", "test.test")); + assertTrue(pathMatcher.match("*.*", "test.test.test")); + assertTrue(pathMatcher.match("test*aaa", "testblaaaa")); + assertFalse(pathMatcher.match("test*", "tst")); + assertFalse(pathMatcher.match("test*", "tsttest")); + assertFalse(pathMatcher.match("test*", "test/")); + assertFalse(pathMatcher.match("test*", "test/t")); + assertFalse(pathMatcher.match("test/*", "test")); + assertFalse(pathMatcher.match("*test*", "tsttst")); + assertFalse(pathMatcher.match("*test", "tsttst")); + assertFalse(pathMatcher.match("*.*", "tsttst")); + assertFalse(pathMatcher.match("test*aaa", "test")); + assertFalse(pathMatcher.match("test*aaa", "testblaaab")); + + // test matching with ?'s and /'s + assertTrue(pathMatcher.match("/?", "/a")); + assertTrue(pathMatcher.match("/?/a", "/a/a")); + assertTrue(pathMatcher.match("/a/?", "/a/b")); + assertTrue(pathMatcher.match("/??/a", "/aa/a")); + assertTrue(pathMatcher.match("/a/??", "/a/bb")); + assertTrue(pathMatcher.match("/?", "/a")); + + // test matching with **'s + assertTrue(pathMatcher.match("/**", "/testing/testing")); + assertTrue(pathMatcher.match("/*/**", "/testing/testing")); + assertTrue(pathMatcher.match("/**/*", "/testing/testing")); + assertTrue(pathMatcher.match("/bla/**/bla", "/bla/testing/testing/bla")); + assertTrue(pathMatcher.match("/bla/**/bla", "/bla/testing/testing/bla/bla")); + assertTrue(pathMatcher.match("/**/test", "/bla/bla/test")); + assertTrue(pathMatcher.match("/bla/**/**/bla", "/bla/bla/bla/bla/bla/bla")); + assertTrue(pathMatcher.match("/bla*bla/test", "/blaXXXbla/test")); + assertTrue(pathMatcher.match("/*bla/test", "/XXXbla/test")); + assertFalse(pathMatcher.match("/bla*bla/test", "/blaXXXbl/test")); + assertFalse(pathMatcher.match("/*bla/test", "XXXblab/test")); + assertFalse(pathMatcher.match("/*bla/test", "XXXbl/test")); + + assertFalse(pathMatcher.match("/????", "/bala/bla")); + assertFalse(pathMatcher.match("/**/*bla", "/bla/bla/bla/bbb")); + + assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.match("/*bla*/**/bla/*", "/XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing")); + assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing.jpg")); + + assertTrue(pathMatcher.match("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.match("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.match("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing")); + assertFalse(pathMatcher.match("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing/testing")); + + assertFalse(pathMatcher.match("/x/x/**/bla", "/x/x/x/")); + + assertTrue(pathMatcher.match("", "")); + } + + public void testAntPathMatcherWithMatchStart() { + PathMatcher pathMatcher = new AntPathMatcher(); + + // test exact matching + assertTrue(pathMatcher.matchStart("test", "test")); + assertTrue(pathMatcher.matchStart("/test", "/test")); + assertFalse(pathMatcher.matchStart("/test.jpg", "test.jpg")); + assertFalse(pathMatcher.matchStart("test", "/test")); + assertFalse(pathMatcher.matchStart("/test", "test")); + + // test matching with ?'s + assertTrue(pathMatcher.matchStart("t?st", "test")); + assertTrue(pathMatcher.matchStart("??st", "test")); + assertTrue(pathMatcher.matchStart("tes?", "test")); + assertTrue(pathMatcher.matchStart("te??", "test")); + assertTrue(pathMatcher.matchStart("?es?", "test")); + assertFalse(pathMatcher.matchStart("tes?", "tes")); + assertFalse(pathMatcher.matchStart("tes?", "testt")); + assertFalse(pathMatcher.matchStart("tes?", "tsst")); + + // test matchin with *'s + assertTrue(pathMatcher.matchStart("*", "test")); + assertTrue(pathMatcher.matchStart("test*", "test")); + assertTrue(pathMatcher.matchStart("test*", "testTest")); + assertTrue(pathMatcher.matchStart("test/*", "test/Test")); + assertTrue(pathMatcher.matchStart("test/*", "test/t")); + assertTrue(pathMatcher.matchStart("test/*", "test/")); + assertTrue(pathMatcher.matchStart("*test*", "AnothertestTest")); + assertTrue(pathMatcher.matchStart("*test", "Anothertest")); + assertTrue(pathMatcher.matchStart("*.*", "test.")); + assertTrue(pathMatcher.matchStart("*.*", "test.test")); + assertTrue(pathMatcher.matchStart("*.*", "test.test.test")); + assertTrue(pathMatcher.matchStart("test*aaa", "testblaaaa")); + assertFalse(pathMatcher.matchStart("test*", "tst")); + assertFalse(pathMatcher.matchStart("test*", "test/")); + assertFalse(pathMatcher.matchStart("test*", "tsttest")); + assertFalse(pathMatcher.matchStart("test*", "test/")); + assertFalse(pathMatcher.matchStart("test*", "test/t")); + assertTrue(pathMatcher.matchStart("test/*", "test")); + assertTrue(pathMatcher.matchStart("test/t*.txt", "test")); + assertFalse(pathMatcher.matchStart("*test*", "tsttst")); + assertFalse(pathMatcher.matchStart("*test", "tsttst")); + assertFalse(pathMatcher.matchStart("*.*", "tsttst")); + assertFalse(pathMatcher.matchStart("test*aaa", "test")); + assertFalse(pathMatcher.matchStart("test*aaa", "testblaaab")); + + // test matching with ?'s and /'s + assertTrue(pathMatcher.matchStart("/?", "/a")); + assertTrue(pathMatcher.matchStart("/?/a", "/a/a")); + assertTrue(pathMatcher.matchStart("/a/?", "/a/b")); + assertTrue(pathMatcher.matchStart("/??/a", "/aa/a")); + assertTrue(pathMatcher.matchStart("/a/??", "/a/bb")); + assertTrue(pathMatcher.matchStart("/?", "/a")); + + // test matching with **'s + assertTrue(pathMatcher.matchStart("/**", "/testing/testing")); + assertTrue(pathMatcher.matchStart("/*/**", "/testing/testing")); + assertTrue(pathMatcher.matchStart("/**/*", "/testing/testing")); + assertTrue(pathMatcher.matchStart("test*/**", "test/")); + assertTrue(pathMatcher.matchStart("test*/**", "test/t")); + assertTrue(pathMatcher.matchStart("/bla/**/bla", "/bla/testing/testing/bla")); + assertTrue(pathMatcher.matchStart("/bla/**/bla", "/bla/testing/testing/bla/bla")); + assertTrue(pathMatcher.matchStart("/**/test", "/bla/bla/test")); + assertTrue(pathMatcher.matchStart("/bla/**/**/bla", "/bla/bla/bla/bla/bla/bla")); + assertTrue(pathMatcher.matchStart("/bla*bla/test", "/blaXXXbla/test")); + assertTrue(pathMatcher.matchStart("/*bla/test", "/XXXbla/test")); + assertFalse(pathMatcher.matchStart("/bla*bla/test", "/blaXXXbl/test")); + assertFalse(pathMatcher.matchStart("/*bla/test", "XXXblab/test")); + assertFalse(pathMatcher.matchStart("/*bla/test", "XXXbl/test")); + + assertFalse(pathMatcher.matchStart("/????", "/bala/bla")); + assertTrue(pathMatcher.matchStart("/**/*bla", "/bla/bla/bla/bbb")); + + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/*", "/XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing")); + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing.jpg")); + + assertTrue(pathMatcher.matchStart("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.matchStart("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.matchStart("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing")); + assertTrue(pathMatcher.matchStart("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing/testing")); + + assertTrue(pathMatcher.matchStart("/x/x/**/bla", "/x/x/x/")); + + assertTrue(pathMatcher.matchStart("", "")); + } + + public void testAntPathMatcherWithUniqueDeliminator() { + AntPathMatcher pathMatcher = new AntPathMatcher(); + pathMatcher.setPathSeparator("."); + + // test exact matching + assertTrue(pathMatcher.match("test", "test")); + assertTrue(pathMatcher.match(".test", ".test")); + assertFalse(pathMatcher.match(".test/jpg", "test/jpg")); + assertFalse(pathMatcher.match("test", ".test")); + assertFalse(pathMatcher.match(".test", "test")); + + // test matching with ?'s + assertTrue(pathMatcher.match("t?st", "test")); + assertTrue(pathMatcher.match("??st", "test")); + assertTrue(pathMatcher.match("tes?", "test")); + assertTrue(pathMatcher.match("te??", "test")); + assertTrue(pathMatcher.match("?es?", "test")); + assertFalse(pathMatcher.match("tes?", "tes")); + assertFalse(pathMatcher.match("tes?", "testt")); + assertFalse(pathMatcher.match("tes?", "tsst")); + + // test matchin with *'s + assertTrue(pathMatcher.match("*", "test")); + assertTrue(pathMatcher.match("test*", "test")); + assertTrue(pathMatcher.match("test*", "testTest")); + assertTrue(pathMatcher.match("*test*", "AnothertestTest")); + assertTrue(pathMatcher.match("*test", "Anothertest")); + assertTrue(pathMatcher.match("*/*", "test/")); + assertTrue(pathMatcher.match("*/*", "test/test")); + assertTrue(pathMatcher.match("*/*", "test/test/test")); + assertTrue(pathMatcher.match("test*aaa", "testblaaaa")); + assertFalse(pathMatcher.match("test*", "tst")); + assertFalse(pathMatcher.match("test*", "tsttest")); + assertFalse(pathMatcher.match("*test*", "tsttst")); + assertFalse(pathMatcher.match("*test", "tsttst")); + assertFalse(pathMatcher.match("*/*", "tsttst")); + assertFalse(pathMatcher.match("test*aaa", "test")); + assertFalse(pathMatcher.match("test*aaa", "testblaaab")); + + // test matching with ?'s and .'s + assertTrue(pathMatcher.match(".?", ".a")); + assertTrue(pathMatcher.match(".?.a", ".a.a")); + assertTrue(pathMatcher.match(".a.?", ".a.b")); + assertTrue(pathMatcher.match(".??.a", ".aa.a")); + assertTrue(pathMatcher.match(".a.??", ".a.bb")); + assertTrue(pathMatcher.match(".?", ".a")); + + // test matching with **'s + assertTrue(pathMatcher.match(".**", ".testing.testing")); + assertTrue(pathMatcher.match(".*.**", ".testing.testing")); + assertTrue(pathMatcher.match(".**.*", ".testing.testing")); + assertTrue(pathMatcher.match(".bla.**.bla", ".bla.testing.testing.bla")); + assertTrue(pathMatcher.match(".bla.**.bla", ".bla.testing.testing.bla.bla")); + assertTrue(pathMatcher.match(".**.test", ".bla.bla.test")); + assertTrue(pathMatcher.match(".bla.**.**.bla", ".bla.bla.bla.bla.bla.bla")); + assertTrue(pathMatcher.match(".bla*bla.test", ".blaXXXbla.test")); + assertTrue(pathMatcher.match(".*bla.test", ".XXXbla.test")); + assertFalse(pathMatcher.match(".bla*bla.test", ".blaXXXbl.test")); + assertFalse(pathMatcher.match(".*bla.test", "XXXblab.test")); + assertFalse(pathMatcher.match(".*bla.test", "XXXbl.test")); + } + + public void testAntPathMatcherExtractPathWithinPattern() throws Exception { + PathMatcher pathMatcher = new AntPathMatcher(); + + assertEquals("", pathMatcher.extractPathWithinPattern("/docs/commit.html", "/docs/commit.html")); + + assertEquals("cvs/commit", pathMatcher.extractPathWithinPattern("/docs/*", "/docs/cvs/commit")); + assertEquals("commit.html", pathMatcher.extractPathWithinPattern("/docs/cvs/*.html", "/docs/cvs/commit.html")); + assertEquals("cvs/commit", pathMatcher.extractPathWithinPattern("/docs/**", "/docs/cvs/commit")); + assertEquals("cvs/commit.html", pathMatcher.extractPathWithinPattern("/docs/**/*.html", "/docs/cvs/commit.html")); + assertEquals("commit.html", pathMatcher.extractPathWithinPattern("/docs/**/*.html", "/docs/commit.html")); + assertEquals("commit.html", pathMatcher.extractPathWithinPattern("/*.html", "/commit.html")); + assertEquals("docs/commit.html", pathMatcher.extractPathWithinPattern("/*.html", "/docs/commit.html")); + assertEquals("/commit.html", pathMatcher.extractPathWithinPattern("*.html", "/commit.html")); + assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("*.html", "/docs/commit.html")); + assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("**/*.*", "/docs/commit.html")); + assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("*", "/docs/commit.html")); + + assertEquals("docs/cvs/commit", pathMatcher.extractPathWithinPattern("/d?cs/*", "/docs/cvs/commit")); + assertEquals("cvs/commit.html", pathMatcher.extractPathWithinPattern("/docs/c?s/*.html", "/docs/cvs/commit.html")); + assertEquals("docs/cvs/commit", pathMatcher.extractPathWithinPattern("/d?cs/**", "/docs/cvs/commit")); + assertEquals("docs/cvs/commit.html", pathMatcher.extractPathWithinPattern("/d?cs/**/*.html", "/docs/cvs/commit.html")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/PatternMatchUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/PatternMatchUtilsTests.java new file mode 100644 index 00000000000..8128cee620a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/PatternMatchUtilsTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + * @author Johan Gorter + */ +public class PatternMatchUtilsTests extends TestCase { + + public void testTrivial() { + assertEquals(false, PatternMatchUtils.simpleMatch((String) null, "")); + assertEquals(false, PatternMatchUtils.simpleMatch("1", null)); + doTest("*", "123", true); + doTest("123", "123", true); + } + + public void testStartsWith() { + doTest("get*", "getMe", true); + doTest("get*", "setMe", false); + } + + public void testEndsWith() { + doTest("*Test", "getMeTest", true); + doTest("*Test", "setMe", false); + } + + public void testBetween() { + doTest("*stuff*", "getMeTest", false); + doTest("*stuff*", "getstuffTest", true); + doTest("*stuff*", "stuffTest", true); + doTest("*stuff*", "getstuff", true); + doTest("*stuff*", "stuff", true); + } + + public void testStartsEnds() { + doTest("on*Event", "onMyEvent", true); + doTest("on*Event", "onEvent", true); + doTest("3*3", "3", false); + doTest("3*3", "33", true); + } + + public void testStartsEndsBetween() { + doTest("12*45*78", "12345678", true); + doTest("12*45*78", "123456789", false); + doTest("12*45*78", "012345678", false); + doTest("12*45*78", "124578", true); + doTest("12*45*78", "1245457878", true); + doTest("3*3*3", "33", false); + doTest("3*3*3", "333", true); + } + + public void testRidiculous() { + doTest("*1*2*3*", "0011002001010030020201030", true); + doTest("1*2*3*4", "10300204", false); + doTest("1*2*3*3", "10300203", false); + doTest("*1*2*3*", "123", true); + doTest("*1*2*3*", "132", false); + } + + private void doTest(String pattern, String str, boolean shouldMatch) { + assertEquals(shouldMatch, PatternMatchUtils.simpleMatch(pattern, str)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/PropertiesPersisterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/PropertiesPersisterTests.java new file mode 100644 index 00000000000..0fcc4238ae5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/PropertiesPersisterTests.java @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Properties; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + * @since 11.01.2005 + */ +public class PropertiesPersisterTests extends TestCase { + + public void testPropertiesPersister() throws IOException { + String propString = "code1=message1\ncode2:message2"; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, null, false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithWhitespace() throws IOException { + String propString = " code1\t= \tmessage1\n code2 \t :\t mess\\\n \t age2"; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, null, false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithHeader() throws IOException { + String propString = "code1=message1\ncode2:message2"; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, "myHeader", false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithEmptyValue() throws IOException { + String propString = "code1=message1\ncode2:message2\ncode3="; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, null, false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReader() throws IOException { + String propString = "code1=message1\ncode2:message2"; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, null, true); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReaderAndWhitespace() throws IOException { + String propString = " code1\t= \tmessage1\n code2 \t :\t mess\\\n \t age2"; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, null, true); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReaderAndHeader() throws IOException { + String propString = "code1\t=\tmessage1\n code2 \t : \t message2"; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, "myHeader", true); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReaderAndEmptyValue() throws IOException { + String propString = "code1=message1\ncode2:message2\ncode3="; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, null, true); + loadProperties(propCopy, false); + } + + private Properties loadProperties(String propString, boolean useReader) throws IOException { + DefaultPropertiesPersister persister = new DefaultPropertiesPersister(); + Properties props = new Properties(); + if (useReader) { + persister.load(props, new StringReader(propString)); + } + else { + persister.load(props, new ByteArrayInputStream(propString.getBytes())); + } + assertEquals("message1", props.getProperty("code1")); + assertEquals("message2", props.getProperty("code2")); + return props; + } + + private String storeProperties(Properties props, String header, boolean useWriter) throws IOException { + DefaultPropertiesPersister persister = new DefaultPropertiesPersister(); + String propCopy = null; + if (useWriter) { + StringWriter propWriter = new StringWriter(); + persister.store(props, propWriter, header); + propCopy = propWriter.toString(); + } + else { + ByteArrayOutputStream propOut = new ByteArrayOutputStream(); + persister.store(props, propOut, header); + propCopy = new String(propOut.toByteArray()); + } + if (header != null) { + assertTrue(propCopy.indexOf(header) != -1); + } + assertTrue(propCopy.indexOf("\ncode1=message1") != -1); + assertTrue(propCopy.indexOf("\ncode2=message2") != -1); + return propCopy; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/ReflectionUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/ReflectionUtilsTests.java new file mode 100644 index 00000000000..474cbd64424 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/ReflectionUtilsTests.java @@ -0,0 +1,285 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.rmi.ConnectException; +import java.rmi.RemoteException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.test.AssertThrows; + +/** + *

+ * JUnit 3.8 based unit tests for {@link ReflectionUtils}. + *

+ * + * @author Rob Harrop + * @author Juergen Hoeller + * @author Sam Brannen + */ +public class ReflectionUtilsTests extends TestCase { + + public void testFindField() { + Field field; + + field = ReflectionUtils.findField(TestBeanSubclassWithPublicField.class, "publicField", String.class); + assertNotNull(field); + assertEquals("publicField", field.getName()); + assertEquals(String.class, field.getType()); + assertTrue("Field should be public.", Modifier.isPublic(field.getModifiers())); + + field = ReflectionUtils.findField(TestBeanSubclassWithNewField.class, "prot", String.class); + assertNotNull(field); + assertEquals("prot", field.getName()); + assertEquals(String.class, field.getType()); + assertTrue("Field should be protected.", Modifier.isProtected(field.getModifiers())); + + field = ReflectionUtils.findField(TestBeanSubclassWithNewField.class, "name", String.class); + assertNotNull(field); + assertEquals("name", field.getName()); + assertEquals(String.class, field.getType()); + assertTrue("Field should be private.", Modifier.isPrivate(field.getModifiers())); + } + + public void testSetField() { + final TestBeanSubclassWithNewField testBean = new TestBeanSubclassWithNewField(); + final Field field = ReflectionUtils.findField(TestBeanSubclassWithNewField.class, "name", String.class); + + new AssertThrows(IllegalStateException.class, + "Calling setField() with on a private field without making it accessible should throw an IllegalStateException.") { + + public void test() throws Exception { + ReflectionUtils.setField(field, testBean, "FooBar"); + } + }.runTest(); + + ReflectionUtils.makeAccessible(field); + + ReflectionUtils.setField(field, testBean, "FooBar"); + assertNotNull(testBean.getName()); + assertEquals("FooBar", testBean.getName()); + + ReflectionUtils.setField(field, testBean, null); + assertNull(testBean.getName()); + } + + + public void testInvokeMethod() throws Exception { + String rob = "Rob Harrop"; + String juergen = "Juergen Hoeller"; + + TestBean bean = new TestBean(); + bean.setName(rob); + + Method getName = TestBean.class.getMethod("getName", (Class[]) null); + Method setName = TestBean.class.getMethod("setName", new Class[] { String.class }); + + Object name = ReflectionUtils.invokeMethod(getName, bean); + assertEquals("Incorrect name returned", rob, name); + + ReflectionUtils.invokeMethod(setName, bean, new Object[] { juergen }); + assertEquals("Incorrect name set", juergen, bean.getName()); + } + + public void testDeclaresException() throws Exception { + Method remoteExMethod = A.class.getDeclaredMethod("foo", new Class[] {Integer.class}); + assertTrue(ReflectionUtils.declaresException(remoteExMethod, RemoteException.class)); + assertTrue(ReflectionUtils.declaresException(remoteExMethod, ConnectException.class)); + assertFalse(ReflectionUtils.declaresException(remoteExMethod, NoSuchMethodException.class)); + assertFalse(ReflectionUtils.declaresException(remoteExMethod, Exception.class)); + + Method illegalExMethod = B.class.getDeclaredMethod("bar", new Class[] {String.class}); + assertTrue(ReflectionUtils.declaresException(illegalExMethod, IllegalArgumentException.class)); + assertTrue(ReflectionUtils.declaresException(illegalExMethod, NumberFormatException.class)); + assertFalse(ReflectionUtils.declaresException(illegalExMethod, IllegalStateException.class)); + assertFalse(ReflectionUtils.declaresException(illegalExMethod, Exception.class)); + } + + public void testCopySrcToDestinationOfIncorrectClass() { + TestBean src = new TestBean(); + String dest = new String(); + try { + ReflectionUtils.shallowCopyFieldState(src, dest); + fail(); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testRejectsNullSrc() { + TestBean src = null; + String dest = new String(); + try { + ReflectionUtils.shallowCopyFieldState(src, dest); + fail(); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testRejectsNullDest() { + TestBean src = new TestBean(); + String dest = null; + try { + ReflectionUtils.shallowCopyFieldState(src, dest); + fail(); + } + catch (IllegalArgumentException ex) { + // Ok + } + } + + public void testValidCopy() { + TestBean src = new TestBean(); + TestBean dest = new TestBean(); + testValidCopy(src, dest); + } + + public void testValidCopyOnSubTypeWithNewField() { + TestBeanSubclassWithNewField src = new TestBeanSubclassWithNewField(); + TestBeanSubclassWithNewField dest = new TestBeanSubclassWithNewField(); + src.magic = 11; + + // Will check inherited fields are copied + testValidCopy(src, dest); + + // Check subclass fields were copied + assertEquals(src.magic, dest.magic); + assertEquals(src.prot, dest.prot); + } + + public void testValidCopyToSubType() { + TestBean src = new TestBean(); + TestBeanSubclassWithNewField dest = new TestBeanSubclassWithNewField(); + dest.magic = 11; + testValidCopy(src, dest); + // Should have left this one alone + assertEquals(11, dest.magic); + } + + public void testValidCopyToSubTypeWithFinalField() { + TestBeanSubclassWithFinalField src = new TestBeanSubclassWithFinalField(); + TestBeanSubclassWithFinalField dest = new TestBeanSubclassWithFinalField(); + // Check that this doesn't fail due to attempt to assign final + testValidCopy(src, dest); + } + + private void testValidCopy(TestBean src, TestBean dest) { + src.setName("freddie"); + src.setAge(15); + src.setSpouse(new TestBean()); + assertFalse(src.getAge() == dest.getAge()); + + ReflectionUtils.shallowCopyFieldState(src, dest); + assertEquals(src.getAge(), dest.getAge()); + assertEquals(src.getSpouse(), dest.getSpouse()); + assertEquals(src.getDoctor(), dest.getDoctor()); + } + + static class ListSavingMethodCallback implements ReflectionUtils.MethodCallback { + private List methodNames = new LinkedList(); + + private List methods = new LinkedList(); + + public void doWith(Method m) throws IllegalArgumentException, IllegalAccessException { + this.methodNames.add(m.getName()); + this.methods.add(m); + } + + public List getMethodNames() { + return this.methodNames; + } + + public List getMethods() { + return this.methods; + } + }; + + public void testDoWithProtectedMethods() { + ListSavingMethodCallback mc = new ListSavingMethodCallback(); + ReflectionUtils.doWithMethods(TestBean.class, mc, new ReflectionUtils.MethodFilter() { + public boolean matches(Method m) { + return Modifier.isProtected(m.getModifiers()); + } + }); + assertFalse(mc.getMethodNames().isEmpty()); + assertTrue("Must find protected method on Object", mc.getMethodNames().contains("clone")); + assertTrue("Must find protected method on Object", mc.getMethodNames().contains("finalize")); + assertFalse("Public, not protected", mc.getMethodNames().contains("hashCode")); + assertFalse("Public, not protected", mc.getMethodNames().contains("absquatulate")); + } + + public static class TestBeanSubclass extends TestBean { + public void absquatulate() { + throw new UnsupportedOperationException(); + } + } + + public void testDuplicatesFound() { + ListSavingMethodCallback mc = new ListSavingMethodCallback(); + ReflectionUtils.doWithMethods(TestBeanSubclass.class, mc); + int absquatulateCount = 0; + for (Iterator it = mc.getMethodNames().iterator(); it.hasNext();) { + String name = (String) it.next(); + if (name.equals("absquatulate")) { + ++absquatulateCount; + } + } + assertEquals("Found 2 absquatulates", 2, absquatulateCount); + } + + public void testFindMethod() throws Exception { + assertNotNull(ReflectionUtils.findMethod(B.class, "bar", new Class[]{String.class})); + assertNotNull(ReflectionUtils.findMethod(B.class, "foo", new Class[]{Integer.class})); + } + + + public static class TestBeanSubclassWithPublicField extends TestBean { + public String publicField = "foo"; + } + + public static class TestBeanSubclassWithNewField extends TestBean { + private int magic; + protected String prot = "foo"; + } + + + public static class TestBeanSubclassWithFinalField extends TestBean { + private final String foo = "will break naive copy that doesn't exclude statics"; + } + + + private static class A { + private void foo(Integer i) throws RemoteException {} + } + + + private static class B extends A { + void bar(String s) throws IllegalArgumentException {} + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/ResourceUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/ResourceUtilsTests.java new file mode 100644 index 00000000000..9baaf384a00 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/ResourceUtilsTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + */ +public class ResourceUtilsTests extends TestCase { + + public void testIsJarURL() throws Exception { + assertTrue(ResourceUtils.isJarURL(new URL("jar:file:myjar.jar!/mypath"))); + assertTrue(ResourceUtils.isJarURL(new URL(null, "zip:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertTrue(ResourceUtils.isJarURL(new URL(null, "wsjar:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertFalse(ResourceUtils.isJarURL(new URL("file:myjar.jar"))); + assertFalse(ResourceUtils.isJarURL(new URL("http:myserver/myjar.jar"))); + } + + public void testExtractJarFileURL() throws Exception { + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL("jar:file:myjar.jar!/mypath"))); + assertEquals(new URL("file:/myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "jar:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "zip:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "wsjar:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL("jar:file:myjar.jar!/"))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "zip:file:myjar.jar!/", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "wsjar:file:myjar.jar!/", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL("file:myjar.jar"))); + } + + + /** + * Dummy URLStreamHandler that's just specified to suppress the standard + * java.net.URL URLStreamHandler lookup, to be able to + * use the standard URL class for parsing "rmi:..." URLs. + */ + private static class DummyURLStreamHandler extends URLStreamHandler { + + protected URLConnection openConnection(URL url) throws IOException { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/SerializationTestUtils.java b/org.springframework.testsuite/src/test/java/org/springframework/util/SerializationTestUtils.java new file mode 100644 index 00000000000..bdffe7578da --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/SerializationTestUtils.java @@ -0,0 +1,97 @@ +/* + * The Spring Framework is published under the terms + * of the Apache Software License. + */ + +package org.springframework.util; + +import java.awt.Point; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; + +/** + * Utilities for testing serializability of objects. + * Exposes static methods for use in other test cases. + * Extends TestCase only to test itself. + * + * @author Rod Johnson + */ +public class SerializationTestUtils extends TestCase { + + public static void testSerialization(Object o) throws IOException { + OutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + } + + public static boolean isSerializable(Object o) throws IOException { + try { + testSerialization(o); + return true; + } + catch (NotSerializableException ex) { + return false; + } + } + + public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.flush(); + baos.flush(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(is); + Object o2 = ois.readObject(); + + return o2; + } + + public SerializationTestUtils(String s) { + super(s); + } + + public void testWithNonSerializableObject() throws IOException { + TestBean o = new TestBean(); + assertFalse(o instanceof Serializable); + + assertFalse(isSerializable(o)); + + try { + testSerialization(o); + fail(); + } + catch (NotSerializableException ex) { + // Ok + } + } + + public void testWithSerializableObject() throws Exception { + int x = 5; + int y = 10; + Point p = new Point(x, y); + assertTrue(p instanceof Serializable); + + testSerialization(p); + + assertTrue(isSerializable(p)); + + Point p2 = (Point) serializeAndDeserialize(p); + assertNotSame(p, p2); + assertEquals(x, (int) p2.getX()); + assertEquals(y, (int) p2.getY()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/StopWatchTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/StopWatchTests.java new file mode 100644 index 00000000000..a066318ebf8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/StopWatchTests.java @@ -0,0 +1,144 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + */ +public class StopWatchTests extends TestCase { + + /** + * Are timings off in JUnit? + */ + public void testValidUsage() throws Exception { + StopWatch sw = new StopWatch(); + long int1 = 166L; + long int2 = 45L; + String name1 = "Task 1"; + String name2 = "Task 2"; + + long fudgeFactor = 5L; + assertFalse(sw.isRunning()); + sw.start(name1); + Thread.sleep(int1); + assertTrue(sw.isRunning()); + sw.stop(); + + // TODO are timings off in JUnit? Why do these assertions sometimes fail + // under both Ant and Eclipse? + + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + fudgeFactor); + sw.start(name2); + Thread.sleep(int2); + sw.stop(); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1 + int2); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + int2 + fudgeFactor); + + assertTrue(sw.getTaskCount() == 2); + String pp = sw.prettyPrint(); + assertTrue(pp.indexOf(name1) != -1); + assertTrue(pp.indexOf(name2) != -1); + + StopWatch.TaskInfo[] tasks = sw.getTaskInfo(); + assertTrue(tasks.length == 2); + assertTrue(tasks[0].getTaskName().equals(name1)); + assertTrue(tasks[1].getTaskName().equals(name2)); + sw.toString(); + } + + public void testValidUsageNotKeepingTaskList() throws Exception { + StopWatch sw = new StopWatch(); + sw.setKeepTaskList(false); + long int1 = 166L; + long int2 = 45L; + String name1 = "Task 1"; + String name2 = "Task 2"; + + long fudgeFactor = 5L; + assertFalse(sw.isRunning()); + sw.start(name1); + Thread.sleep(int1); + assertTrue(sw.isRunning()); + sw.stop(); + + // TODO are timings off in JUnit? Why do these assertions sometimes fail + // under both Ant and Eclipse? + + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + fudgeFactor); + sw.start(name2); + Thread.sleep(int2); + sw.stop(); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1 + int2); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + int2 + fudgeFactor); + + assertTrue(sw.getTaskCount() == 2); + String pp = sw.prettyPrint(); + assertTrue(pp.indexOf("kept") != -1); + sw.toString(); + + try { + sw.getTaskInfo(); + fail(); + } + catch (UnsupportedOperationException ex) { + // Ok + } + } + + public void testFailureToStartBeforeGettingTimings() { + StopWatch sw = new StopWatch(); + try { + sw.getLastTaskTimeMillis(); + fail("Can't get last interval if no tests run"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testFailureToStartBeforeStop() { + StopWatch sw = new StopWatch(); + try { + sw.stop(); + fail("Can't stop without starting"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testRejectsStartTwice() { + StopWatch sw = new StopWatch(); + try { + sw.start(""); + sw.stop(); + sw.start(""); + assertTrue(sw.isRunning()); + sw.start(""); + fail("Can't start twice"); + } + catch (IllegalStateException ex) { + // Ok + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/StringUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/StringUtilsTests.java new file mode 100644 index 00000000000..320b7363c61 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/StringUtilsTests.java @@ -0,0 +1,614 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.util.Arrays; +import java.util.Locale; +import java.util.Properties; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + */ +public class StringUtilsTests extends TestCase { + + public void testHasTextBlank() throws Exception { + String blank = " "; + assertEquals(false, StringUtils.hasText(blank)); + } + + public void testHasTextNullEmpty() throws Exception { + assertEquals(false, StringUtils.hasText(null)); + assertEquals(false, StringUtils.hasText("")); + } + + public void testHasTextValid() throws Exception { + assertEquals(true, StringUtils.hasText("t")); + } + + public void testContainsWhitespace() throws Exception { + assertFalse(StringUtils.containsWhitespace(null)); + assertFalse(StringUtils.containsWhitespace("")); + assertFalse(StringUtils.containsWhitespace("a")); + assertFalse(StringUtils.containsWhitespace("abc")); + assertTrue(StringUtils.containsWhitespace(" ")); + assertTrue(StringUtils.containsWhitespace(" a")); + assertTrue(StringUtils.containsWhitespace("abc ")); + assertTrue(StringUtils.containsWhitespace("a b")); + assertTrue(StringUtils.containsWhitespace("a b")); + } + + public void testTrimWhitespace() throws Exception { + assertEquals(null, StringUtils.trimWhitespace(null)); + assertEquals("", StringUtils.trimWhitespace("")); + assertEquals("", StringUtils.trimWhitespace(" ")); + assertEquals("", StringUtils.trimWhitespace("\t")); + assertEquals("a", StringUtils.trimWhitespace(" a")); + assertEquals("a", StringUtils.trimWhitespace("a ")); + assertEquals("a", StringUtils.trimWhitespace(" a ")); + assertEquals("a b", StringUtils.trimWhitespace(" a b ")); + assertEquals("a b c", StringUtils.trimWhitespace(" a b c ")); + } + + public void testTrimAllWhitespace() throws Exception { + assertEquals("", StringUtils.trimAllWhitespace("")); + assertEquals("", StringUtils.trimAllWhitespace(" ")); + assertEquals("", StringUtils.trimAllWhitespace("\t")); + assertEquals("a", StringUtils.trimAllWhitespace(" a")); + assertEquals("a", StringUtils.trimAllWhitespace("a ")); + assertEquals("a", StringUtils.trimAllWhitespace(" a ")); + assertEquals("ab", StringUtils.trimAllWhitespace(" a b ")); + assertEquals("abc", StringUtils.trimAllWhitespace(" a b c ")); + } + + public void testTrimLeadingWhitespace() throws Exception { + assertEquals(null, StringUtils.trimLeadingWhitespace(null)); + assertEquals("", StringUtils.trimLeadingWhitespace("")); + assertEquals("", StringUtils.trimLeadingWhitespace(" ")); + assertEquals("", StringUtils.trimLeadingWhitespace("\t")); + assertEquals("a", StringUtils.trimLeadingWhitespace(" a")); + assertEquals("a ", StringUtils.trimLeadingWhitespace("a ")); + assertEquals("a ", StringUtils.trimLeadingWhitespace(" a ")); + assertEquals("a b ", StringUtils.trimLeadingWhitespace(" a b ")); + assertEquals("a b c ", StringUtils.trimLeadingWhitespace(" a b c ")); + } + + public void testTrimTrailingWhitespace() throws Exception { + assertEquals(null, StringUtils.trimTrailingWhitespace(null)); + assertEquals("", StringUtils.trimTrailingWhitespace("")); + assertEquals("", StringUtils.trimTrailingWhitespace(" ")); + assertEquals("", StringUtils.trimTrailingWhitespace("\t")); + assertEquals("a", StringUtils.trimTrailingWhitespace("a ")); + assertEquals(" a", StringUtils.trimTrailingWhitespace(" a")); + assertEquals(" a", StringUtils.trimTrailingWhitespace(" a ")); + assertEquals(" a b", StringUtils.trimTrailingWhitespace(" a b ")); + assertEquals(" a b c", StringUtils.trimTrailingWhitespace(" a b c ")); + } + + public void testTrimLeadingCharacter() throws Exception { + assertEquals(null, StringUtils.trimLeadingCharacter(null, ' ')); + assertEquals("", StringUtils.trimLeadingCharacter("", ' ')); + assertEquals("", StringUtils.trimLeadingCharacter(" ", ' ')); + assertEquals("\t", StringUtils.trimLeadingCharacter("\t", ' ')); + assertEquals("a", StringUtils.trimLeadingCharacter(" a", ' ')); + assertEquals("a ", StringUtils.trimLeadingCharacter("a ", ' ')); + assertEquals("a ", StringUtils.trimLeadingCharacter(" a ", ' ')); + assertEquals("a b ", StringUtils.trimLeadingCharacter(" a b ", ' ')); + assertEquals("a b c ", StringUtils.trimLeadingCharacter(" a b c ", ' ')); + } + + public void testTrimTrailingCharacter() throws Exception { + assertEquals(null, StringUtils.trimTrailingCharacter(null, ' ')); + assertEquals("", StringUtils.trimTrailingCharacter("", ' ')); + assertEquals("", StringUtils.trimTrailingCharacter(" ", ' ')); + assertEquals("\t", StringUtils.trimTrailingCharacter("\t", ' ')); + assertEquals("a", StringUtils.trimTrailingCharacter("a ", ' ')); + assertEquals(" a", StringUtils.trimTrailingCharacter(" a", ' ')); + assertEquals(" a", StringUtils.trimTrailingCharacter(" a ", ' ')); + assertEquals(" a b", StringUtils.trimTrailingCharacter(" a b ", ' ')); + assertEquals(" a b c", StringUtils.trimTrailingCharacter(" a b c ", ' ')); + } + + public void testCountOccurrencesOf() { + assertTrue("nullx2 = 0", + StringUtils.countOccurrencesOf(null, null) == 0); + assertTrue("null string = 0", + StringUtils.countOccurrencesOf("s", null) == 0); + assertTrue("null substring = 0", + StringUtils.countOccurrencesOf(null, "s") == 0); + String s = "erowoiueoiur"; + assertTrue("not found = 0", + StringUtils.countOccurrencesOf(s, "WERWER") == 0); + assertTrue("not found char = 0", + StringUtils.countOccurrencesOf(s, "x") == 0); + assertTrue("not found ws = 0", + StringUtils.countOccurrencesOf(s, " ") == 0); + assertTrue("not found empty string = 0", + StringUtils.countOccurrencesOf(s, "") == 0); + assertTrue("found char=2", StringUtils.countOccurrencesOf(s, "e") == 2); + assertTrue("found substring=2", + StringUtils.countOccurrencesOf(s, "oi") == 2); + assertTrue("found substring=2", + StringUtils.countOccurrencesOf(s, "oiu") == 2); + assertTrue("found substring=3", + StringUtils.countOccurrencesOf(s, "oiur") == 1); + assertTrue("test last", StringUtils.countOccurrencesOf(s, "r") == 2); + } + + public void testReplace() throws Exception { + String inString = "a6AazAaa77abaa"; + String oldPattern = "aa"; + String newPattern = "foo"; + + // Simple replace + String s = StringUtils.replace(inString, oldPattern, newPattern); + assertTrue("Replace 1 worked", s.equals("a6AazAfoo77abfoo")); + + // Non match: no change + s = StringUtils.replace(inString, "qwoeiruqopwieurpoqwieur", newPattern); + assertTrue("Replace non matched is equal", s.equals(inString)); + + // Null new pattern: should ignore + s = StringUtils.replace(inString, oldPattern, null); + assertTrue("Replace non matched is equal", s.equals(inString)); + + // Null old pattern: should ignore + s = StringUtils.replace(inString, null, newPattern); + assertTrue("Replace non matched is equal", s.equals(inString)); + } + + public void testDelete() throws Exception { + String inString = "The quick brown fox jumped over the lazy dog"; + + String noThe = StringUtils.delete(inString, "the"); + assertTrue("Result has no the [" + noThe + "]", + noThe.equals("The quick brown fox jumped over lazy dog")); + + String nohe = StringUtils.delete(inString, "he"); + assertTrue("Result has no he [" + nohe + "]", + nohe.equals("T quick brown fox jumped over t lazy dog")); + + String nosp = StringUtils.delete(inString, " "); + assertTrue("Result has no spaces", + nosp.equals("Thequickbrownfoxjumpedoverthelazydog")); + + String killEnd = StringUtils.delete(inString, "dog"); + assertTrue("Result has no dog", + killEnd.equals("The quick brown fox jumped over the lazy ")); + + String mismatch = StringUtils.delete(inString, "dxxcxcxog"); + assertTrue("Result is unchanged", mismatch.equals(inString)); + + String nochange = StringUtils.delete(inString, ""); + assertTrue("Result is unchanged", nochange.equals(inString)); + } + + public void testDeleteAny() throws Exception { + String inString = "Able was I ere I saw Elba"; + + String res = StringUtils.deleteAny(inString, "I"); + assertTrue("Result has no Is [" + res + "]", res.equals("Able was ere saw Elba")); + + res = StringUtils.deleteAny(inString, "AeEba!"); + assertTrue("Result has no Is [" + res + "]", res.equals("l ws I r I sw l")); + + String mismatch = StringUtils.deleteAny(inString, "#@$#$^"); + assertTrue("Result is unchanged", mismatch.equals(inString)); + + String whitespace = "This is\n\n\n \t a messagy string with whitespace\n"; + assertTrue("Has CR", whitespace.indexOf("\n") != -1); + assertTrue("Has tab", whitespace.indexOf("\t") != -1); + assertTrue("Has sp", whitespace.indexOf(" ") != -1); + String cleaned = StringUtils.deleteAny(whitespace, "\n\t "); + assertTrue("Has no CR", cleaned.indexOf("\n") == -1); + assertTrue("Has no tab", cleaned.indexOf("\t") == -1); + assertTrue("Has no sp", cleaned.indexOf(" ") == -1); + assertTrue("Still has chars", cleaned.length() > 10); + } + + + public void testQuote() { + assertEquals("'myString'", StringUtils.quote("myString")); + assertEquals("''", StringUtils.quote("")); + assertNull(StringUtils.quote(null)); + } + + public void testQuoteIfString() { + assertEquals("'myString'", StringUtils.quoteIfString("myString")); + assertEquals("''", StringUtils.quoteIfString("")); + assertEquals(new Integer(5), StringUtils.quoteIfString(new Integer(5))); + assertNull(StringUtils.quoteIfString(null)); + } + + public void testUnqualify() { + String qualified = "i.am.not.unqualified"; + assertEquals("unqualified", StringUtils.unqualify(qualified)); + } + + public void testCapitalize() { + String capitalized = "i am not capitalized"; + assertEquals("I am not capitalized", StringUtils.capitalize(capitalized)); + } + + public void testUncapitalize() { + String capitalized = "I am capitalized"; + assertEquals("i am capitalized", StringUtils.uncapitalize(capitalized)); + } + + public void testGetFilename() { + assertEquals(null, StringUtils.getFilename(null)); + assertEquals("", StringUtils.getFilename("")); + assertEquals("myfile", StringUtils.getFilename("myfile")); + assertEquals("myfile", StringUtils.getFilename("mypath/myfile")); + assertEquals("myfile.", StringUtils.getFilename("myfile.")); + assertEquals("myfile.", StringUtils.getFilename("mypath/myfile.")); + assertEquals("myfile.txt", StringUtils.getFilename("myfile.txt")); + assertEquals("myfile.txt", StringUtils.getFilename("mypath/myfile.txt")); + } + + public void testGetFilenameExtension() { + assertEquals(null, StringUtils.getFilenameExtension(null)); + assertEquals(null, StringUtils.getFilenameExtension("")); + assertEquals(null, StringUtils.getFilenameExtension("myfile")); + assertEquals(null, StringUtils.getFilenameExtension("myPath/myfile")); + assertEquals("", StringUtils.getFilenameExtension("myfile.")); + assertEquals("", StringUtils.getFilenameExtension("myPath/myfile.")); + assertEquals("txt", StringUtils.getFilenameExtension("myfile.txt")); + assertEquals("txt", StringUtils.getFilenameExtension("mypath/myfile.txt")); + } + + public void testStripFilenameExtension() { + assertEquals(null, StringUtils.stripFilenameExtension(null)); + assertEquals("", StringUtils.stripFilenameExtension("")); + assertEquals("myfile", StringUtils.stripFilenameExtension("myfile")); + assertEquals("mypath/myfile", StringUtils.stripFilenameExtension("mypath/myfile")); + assertEquals("myfile", StringUtils.stripFilenameExtension("myfile.")); + assertEquals("mypath/myfile", StringUtils.stripFilenameExtension("mypath/myfile.")); + assertEquals("myfile", StringUtils.stripFilenameExtension("myfile.txt")); + assertEquals("mypath/myfile", StringUtils.stripFilenameExtension("mypath/myfile.txt")); + } + + public void testCleanPath() { + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath/myfile")); + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath\\myfile")); + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath/../mypath/myfile")); + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath/myfile/../../mypath/myfile")); + assertEquals("../mypath/myfile", StringUtils.cleanPath("../mypath/myfile")); + assertEquals("../mypath/myfile", StringUtils.cleanPath("../mypath/../mypath/myfile")); + assertEquals("../mypath/myfile", StringUtils.cleanPath("mypath/../../mypath/myfile")); + assertEquals("/../mypath/myfile", StringUtils.cleanPath("/../mypath/myfile")); + } + + public void testPathEquals() { + assertTrue("Must be true for the same strings", + StringUtils.pathEquals("/dummy1/dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for the same win strings", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\dummy2\\dummy3")); + assertTrue("Must be true for one top path on 1", + StringUtils.pathEquals("/dummy1/bin/../dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for one win top path on 2", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\bin\\..\\dummy2\\dummy3")); + assertTrue("Must be true for two top paths on 1", + StringUtils.pathEquals("/dummy1/bin/../dummy2/bin/../dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for two win top paths on 2", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\bin\\..\\dummy2\\bin\\..\\dummy3")); + assertTrue("Must be true for double top paths on 1", + StringUtils.pathEquals("/dummy1/bin/tmp/../../dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for double top paths on 2 with similarity", + StringUtils.pathEquals("/dummy1/dummy2/dummy3", + "/dummy1/dum/dum/../../dummy2/dummy3")); + assertTrue("Must be true for current paths", + StringUtils.pathEquals("./dummy1/dummy2/dummy3", + "dummy1/dum/./dum/../../dummy2/dummy3")); + assertFalse("Must be false for relative/absolute paths", + StringUtils.pathEquals("./dummy1/dummy2/dummy3", + "/dummy1/dum/./dum/../../dummy2/dummy3")); + assertFalse("Must be false for different strings", + StringUtils.pathEquals("/dummy1/dummy2/dummy3", + "/dummy1/dummy4/dummy3")); + assertFalse("Must be false for one false path on 1", + StringUtils.pathEquals("/dummy1/bin/tmp/../dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertFalse("Must be false for one false win top path on 2", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\bin\\tmp\\..\\dummy2\\dummy3")); + assertFalse("Must be false for top path on 1 + difference", + StringUtils.pathEquals("/dummy1/bin/../dummy2/dummy3", + "/dummy1/dummy2/dummy4")); + } + + public void testConcatenateStringArrays() { + String[] input1 = new String[] {"myString2"}; + String[] input2 = new String[] {"myString1", "myString2"}; + String[] result = StringUtils.concatenateStringArrays(input1, input2); + assertEquals(3, result.length); + assertEquals("myString2", result[0]); + assertEquals("myString1", result[1]); + assertEquals("myString2", result[2]); + + assertEquals(input1, StringUtils.concatenateStringArrays(input1, null)); + assertEquals(input2, StringUtils.concatenateStringArrays(null, input2)); + assertNull(StringUtils.concatenateStringArrays(null, null)); + } + + public void testMergeStringArrays() { + String[] input1 = new String[] {"myString2"}; + String[] input2 = new String[] {"myString1", "myString2"}; + String[] result = StringUtils.mergeStringArrays(input1, input2); + assertEquals(2, result.length); + assertEquals("myString2", result[0]); + assertEquals("myString1", result[1]); + + assertEquals(input1, StringUtils.mergeStringArrays(input1, null)); + assertEquals(input2, StringUtils.mergeStringArrays(null, input2)); + assertNull(StringUtils.mergeStringArrays(null, null)); + } + + public void testSortStringArray() { + String[] input = new String[] {"myString2"}; + input = StringUtils.addStringToArray(input, "myString1"); + assertEquals("myString2", input[0]); + assertEquals("myString1", input[1]); + + StringUtils.sortStringArray(input); + assertEquals("myString1", input[0]); + assertEquals("myString2", input[1]); + } + + public void testRemoveDuplicateStrings() { + String[] input = new String[] {"myString2", "myString1", "myString2"}; + input = StringUtils.removeDuplicateStrings(input); + assertEquals("myString1", input[0]); + assertEquals("myString2", input[1]); + } + + public void testSplitArrayElementsIntoProperties() { + String[] input = new String[] {"key1=value1 ", "key2 =\"value2\""}; + Properties result = StringUtils.splitArrayElementsIntoProperties(input, "="); + assertEquals("value1", result.getProperty("key1")); + assertEquals("\"value2\"", result.getProperty("key2")); + } + + public void testSplitArrayElementsIntoPropertiesAndDeletedChars() { + String[] input = new String[] {"key1=value1 ", "key2 =\"value2\""}; + Properties result = StringUtils.splitArrayElementsIntoProperties(input, "=", "\""); + assertEquals("value1", result.getProperty("key1")); + assertEquals("value2", result.getProperty("key2")); + } + + public void testTokenizeToStringArray() { + String[] sa = StringUtils.tokenizeToStringArray("a,b , ,c", ","); + assertEquals(3, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("b") && sa[2].equals("c")); + } + + public void testTokenizeToStringArrayWithNotIgnoreEmptyTokens() { + String[] sa = StringUtils.tokenizeToStringArray("a,b , ,c", ",", true, false); + assertEquals(4, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("b") && sa[2].equals("") && sa[3].equals("c")); + } + + public void testTokenizeToStringArrayWithNotTrimTokens() { + String[] sa = StringUtils.tokenizeToStringArray("a,b ,c", ",", false, true); + assertEquals(3, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("b ") && sa[2].equals("c")); + } + + public void testCommaDelimitedListToStringArrayWithNullProducesEmptyArray() { + String[] sa = StringUtils.commaDelimitedListToStringArray(null); + assertTrue("String array isn't null with null input", sa != null); + assertTrue("String array length == 0 with null input", sa.length == 0); + } + + public void testCommaDelimitedListToStringArrayWithEmptyStringProducesEmptyArray() { + String[] sa = StringUtils.commaDelimitedListToStringArray(""); + assertTrue("String array isn't null with null input", sa != null); + assertTrue("String array length == 0 with null input", sa.length == 0); + } + + private void testStringArrayReverseTransformationMatches(String[] sa) { + String[] reverse = + StringUtils.commaDelimitedListToStringArray(StringUtils.arrayToCommaDelimitedString(sa)); + assertEquals("Reverse transformation is equal", + Arrays.asList(sa), + Arrays.asList(reverse)); + } + + public void testDelimitedListToStringArrayWithComma() { + String[] sa = StringUtils.delimitedListToStringArray("a,b", ","); + assertEquals(2, sa.length); + assertEquals("a", sa[0]); + assertEquals("b", sa[1]); + } + + public void testDelimitedListToStringArrayWithSemicolon() { + String[] sa = StringUtils.delimitedListToStringArray("a;b", ";"); + assertEquals(2, sa.length); + assertEquals("a", sa[0]); + assertEquals("b", sa[1]); + } + + public void testDelimitedListToStringArrayWithEmptyString() { + String[] sa = StringUtils.delimitedListToStringArray("a,b", ""); + assertEquals(3, sa.length); + assertEquals("a", sa[0]); + assertEquals(",", sa[1]); + assertEquals("b", sa[2]); + } + + public void testDelimitedListToStringArrayWithNullDelimiter() { + String[] sa = StringUtils.delimitedListToStringArray("a,b", null); + assertEquals(1, sa.length); + assertEquals("a,b", sa[0]); + } + + public void testCommaDelimitedListToStringArrayMatchWords() { + // Could read these from files + String[] sa = new String[] {"foo", "bar", "big"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + testStringArrayReverseTransformationMatches(sa); + + sa = new String[] {"a", "b", "c"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + testStringArrayReverseTransformationMatches(sa); + + // Test same words + sa = new String[] {"AA", "AA", "AA", "AA", "AA"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + testStringArrayReverseTransformationMatches(sa); + } + + public void testCommaDelimitedListToStringArraySingleString() { + // Could read these from files + String s = "woeirqupoiewuropqiewuorpqiwueopriquwopeiurqopwieur"; + String[] sa = StringUtils.commaDelimitedListToStringArray(s); + assertTrue("Found one String with no delimiters", sa.length == 1); + assertTrue("Single array entry matches input String with no delimiters", + sa[0].equals(s)); + } + + public void testCommaDelimitedListToStringArrayWithOtherPunctuation() { + // Could read these from files + String[] sa = new String[] {"xcvwert4456346&*.", "///", ".!", ".", ";"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + } + + /** + * We expect to see the empty Strings in the output. + */ + public void testCommaDelimitedListToStringArrayEmptyStrings() { + // Could read these from files + String[] sa = StringUtils.commaDelimitedListToStringArray("a,,b"); + assertEquals("a,,b produces array length 3", 3, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("") && sa[2].equals("b")); + + sa = new String[] {"", "", "a", ""}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + } + + private void doTestCommaDelimitedListToStringArrayLegalMatch(String[] components) { + StringBuffer sbuf = new StringBuffer(); + for (int i = 0; i < components.length; i++) { + if (i != 0) { + sbuf.append(","); + } + sbuf.append(components[i]); + } + String[] sa = StringUtils.commaDelimitedListToStringArray(sbuf.toString()); + assertTrue("String array isn't null with legal match", sa != null); + assertEquals("String array length is correct with legal match", components.length, sa.length); + assertTrue("Output equals input", Arrays.equals(sa, components)); + } + + public void testEndsWithIgnoreCase() { + String suffix = "fOo"; + assertTrue(StringUtils.endsWithIgnoreCase("foo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("Foo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barfoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barbarfoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barFoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barBarFoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barfoO", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barFOO", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barfOo", suffix)); + assertFalse(StringUtils.endsWithIgnoreCase(null, suffix)); + assertFalse(StringUtils.endsWithIgnoreCase("barfOo", null)); + assertFalse(StringUtils.endsWithIgnoreCase("b", suffix)); + } + + public void testParseLocaleStringSunnyDay() throws Exception { + Locale expectedLocale = Locale.UK; + Locale locale = StringUtils.parseLocaleString(expectedLocale.toString()); + assertNotNull("When given a bona-fide Locale string, must not return null.", locale); + assertEquals(expectedLocale, locale); + } + + public void testParseLocaleStringWithMalformedLocaleString() throws Exception { + Locale locale = StringUtils.parseLocaleString("_banjo_on_my_knee"); + assertNotNull("When given a malformed Locale string, must not return null.", locale); + } + + public void testParseLocaleStringWithEmptyLocaleStringYieldsNullLocale() throws Exception { + Locale locale = StringUtils.parseLocaleString(""); + assertNull("When given an empty Locale string, must return null.", locale); + } + + /** + *
See SPR-3671. + */ + public void testParseLocaleWithMultiValuedVariant() throws Exception { + final String variant = "proper_northern"; + final String localeString = "en_GB_" + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + /** + * See SPR-3671. + */ + public void testParseLocaleWithMultiValuedVariantUsingSpacesAsSeparators() throws Exception { + final String variant = "proper northern"; + final String localeString = "en GB " + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + /** + * See SPR-3671. + */ + public void testParseLocaleWithMultiValuedVariantUsingMixtureOfUnderscoresAndSpacesAsSeparators() throws Exception { + final String variant = "proper northern"; + final String localeString = "en_GB_" + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + /** + * See SPR-3671. + */ + public void testParseLocaleWithMultiValuedVariantUsingSpacesAsSeparatorsWithLotsOfLeadingWhitespace() throws Exception { + final String variant = "proper northern"; + final String localeString = "en GB " + variant; // lots of whitespace + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + /** + * See SPR-3671. + */ + public void testParseLocaleWithMultiValuedVariantUsingUnderscoresAsSeparatorsWithLotsOfLeadingWhitespace() throws Exception { + final String variant = "proper_northern"; + final String localeString = "en_GB_____" + variant; // lots of underscores + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/comparator/ComparatorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/comparator/ComparatorTests.java new file mode 100644 index 00000000000..94cb6433b04 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/comparator/ComparatorTests.java @@ -0,0 +1,179 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util.comparator; + +import java.util.Comparator; + +import junit.framework.TestCase; + +import org.springframework.beans.support.PropertyComparator; + +/** + * @author Keith Donald + */ +public class ComparatorTests extends TestCase { + + public void testComparableComparator() { + Comparator c = new ComparableComparator(); + String s1 = "abc"; + String s2 = "cde"; + assertTrue(c.compare(s1, s2) < 0); + } + + public void testComparableComparatorIllegalArgs() { + Comparator c = new ComparableComparator(); + Object o1 = new Object(); + Object o2 = new Object(); + try { + c.compare(o1, o2); + } + catch (IllegalArgumentException e) { + return; + } + fail("Comparator should have thrown a cce"); + } + + public void testBooleanComparatorTrueLow() { + Comparator c = BooleanComparator.TRUE_LOW; + assertTrue(c.compare(new Boolean(true), new Boolean(false)) < 0); + } + + public void testBooleanComparatorTrueHigh() { + Comparator c = BooleanComparator.TRUE_HIGH; + assertTrue(c.compare(new Boolean(true), new Boolean(false)) > 0); + assertTrue(c.compare(Boolean.TRUE, Boolean.TRUE) == 0); + } + + public void testPropertyComparator() { + Dog dog = new Dog(); + dog.setNickName("mace"); + + Dog dog2 = new Dog(); + dog2.setNickName("biscy"); + + PropertyComparator c = new PropertyComparator("nickName", false, true); + assertTrue(c.compare(dog, dog2) > 0); + assertTrue(c.compare(dog, dog) == 0); + assertTrue(c.compare(dog2, dog) < 0); + } + + public void testPropertyComparatorNulls() { + Dog dog = new Dog(); + Dog dog2 = new Dog(); + PropertyComparator c = new PropertyComparator("nickName", false, true); + assertTrue(c.compare(dog, dog2) == 0); + } + + public void testNullSafeComparatorNullsLow() { + Comparator c = NullSafeComparator.NULLS_LOW; + assertTrue(c.compare(null, "boo") < 0); + } + + public void testNullSafeComparatorNullsHigh() { + Comparator c = NullSafeComparator.NULLS_HIGH; + assertTrue(c.compare(null, "boo") > 0); + assertTrue(c.compare(null, null) == 0); + } + + public void testCompoundComparatorEmpty() { + Comparator c = new CompoundComparator(); + try { + c.compare("foo", "bar"); + } + catch (IllegalStateException e) { + return; + } + fail("illegal state should've been thrown on empty list"); + } + + public void testCompoundComparator() { + CompoundComparator c = new CompoundComparator(); + c.addComparator(new PropertyComparator("lastName", false, true)); + + Dog dog1 = new Dog(); + dog1.setFirstName("macy"); + dog1.setLastName("grayspots"); + + Dog dog2 = new Dog(); + dog2.setFirstName("biscuit"); + dog2.setLastName("grayspots"); + + assertTrue(c.compare(dog1, dog2) == 0); + + c.addComparator(new PropertyComparator("firstName", false, true)); + assertTrue(c.compare(dog1, dog2) > 0); + + dog2.setLastName("konikk dog"); + assertTrue(c.compare(dog2, dog1) > 0); + } + + public void testCompoundComparatorInvert() { + CompoundComparator c = new CompoundComparator(); + c.addComparator(new PropertyComparator("lastName", false, true)); + c.addComparator(new PropertyComparator("firstName", false, true)); + Dog dog1 = new Dog(); + dog1.setFirstName("macy"); + dog1.setLastName("grayspots"); + + Dog dog2 = new Dog(); + dog2.setFirstName("biscuit"); + dog2.setLastName("grayspots"); + + assertTrue(c.compare(dog1, dog2) > 0); + c.invertOrder(); + assertTrue(c.compare(dog1, dog2) < 0); + } + + + private static class Dog implements Comparable { + + private String nickName; + + private String firstName; + + private String lastName; + + public int compareTo(Object o) { + return nickName.compareTo(((Dog)o).nickName); + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/testlog4j.properties b/org.springframework.testsuite/src/test/java/org/springframework/util/testlog4j.properties new file mode 100644 index 00000000000..15d9af5a58b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/testlog4j.properties @@ -0,0 +1,2 @@ +log4j.rootCategory=DEBUG, mock +log4j.appender.mock=org.springframework.util.MockLog4jAppender \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/util/xml/TransformerUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/util/xml/TransformerUtilsTests.java new file mode 100644 index 00000000000..caf687537d1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/util/xml/TransformerUtilsTests.java @@ -0,0 +1,151 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util.xml; + +import java.util.Properties; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; + +import junit.framework.TestCase; + +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + */ +public class TransformerUtilsTests extends TestCase { + + public void testEnableIndentingSunnyDay() throws Exception { + Transformer transformer = new StubTransformer(); + TransformerUtils.enableIndenting(transformer); + String indent = transformer.getOutputProperty(OutputKeys.INDENT); + assertNotNull(indent); + assertEquals("yes", indent); + String indentAmount = transformer.getOutputProperty("{http://xml.apache.org/xslt}indent-amount"); + assertNotNull(indentAmount); + assertEquals(String.valueOf(TransformerUtils.DEFAULT_INDENT_AMOUNT), indentAmount); + } + + public void testEnableIndentingSunnyDayWithCustomKosherIndentAmount() throws Exception { + final String indentAmountProperty = "10"; + Transformer transformer = new StubTransformer(); + TransformerUtils.enableIndenting(transformer, Integer.valueOf(indentAmountProperty).intValue()); + String indent = transformer.getOutputProperty(OutputKeys.INDENT); + assertNotNull(indent); + assertEquals("yes", indent); + String indentAmount = transformer.getOutputProperty("{http://xml.apache.org/xslt}indent-amount"); + assertNotNull(indentAmount); + assertEquals(indentAmountProperty, indentAmount); + } + + public void testDisableIndentingSunnyDay() throws Exception { + Transformer transformer = new StubTransformer(); + TransformerUtils.disableIndenting(transformer); + String indent = transformer.getOutputProperty(OutputKeys.INDENT); + assertNotNull(indent); + assertEquals("no", indent); + } + + public void testEnableIndentingWithNullTransformer() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TransformerUtils.enableIndenting(null); + } + }.runTest(); + } + + public void testDisableIndentingWithNullTransformer() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TransformerUtils.disableIndenting(null); + } + }.runTest(); + } + + public void testEnableIndentingWithNegativeIndentAmount() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TransformerUtils.enableIndenting(new StubTransformer(), -21938); + } + }.runTest(); + } + + public void testEnableIndentingWithZeroIndentAmount() throws Exception { + TransformerUtils.enableIndenting(new StubTransformer(), 0); + } + + + private static class StubTransformer extends Transformer { + + private Properties outputProperties = new Properties(); + + public void transform(Source xmlSource, Result outputTarget) throws TransformerException { + throw new UnsupportedOperationException(); + } + + public void setParameter(String name, Object value) { + throw new UnsupportedOperationException(); + } + + public Object getParameter(String name) { + throw new UnsupportedOperationException(); + } + + public void clearParameters() { + throw new UnsupportedOperationException(); + } + + public void setURIResolver(URIResolver resolver) { + throw new UnsupportedOperationException(); + } + + public URIResolver getURIResolver() { + throw new UnsupportedOperationException(); + } + + public void setOutputProperties(Properties oformat) { + throw new UnsupportedOperationException(); + } + + public Properties getOutputProperties() { + return this.outputProperties; + } + + public void setOutputProperty(String name, String value) throws IllegalArgumentException { + this.outputProperties.setProperty(name, value); + } + + public String getOutputProperty(String name) throws IllegalArgumentException { + return this.outputProperties.getProperty(name); + } + + public void setErrorListener(ErrorListener listener) throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + + public ErrorListener getErrorListener() { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderFieldAccessTests.java b/org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderFieldAccessTests.java new file mode 100644 index 00000000000..4eceff3d8a7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderFieldAccessTests.java @@ -0,0 +1,160 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation; + +import java.beans.PropertyEditorSupport; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.beans.FieldAccessBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.NotWritablePropertyException; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.TestBean; + +/** + * @author Juergen Hoeller + * @since 07.03.2006 + */ +public class DataBinderFieldAccessTests extends TestCase { + + public void testBindingNoErrors() throws Exception { + FieldAccessBean rod = new FieldAccessBean(); + DataBinder binder = new DataBinder(rod, "person"); + assertTrue(binder.isIgnoreUnknownFields()); + binder.initDirectFieldAccess(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("name", "Rod")); + pvs.addPropertyValue(new PropertyValue("age", new Integer(32))); + pvs.addPropertyValue(new PropertyValue("nonExisting", "someValue")); + + binder.bind(pvs); + binder.close(); + + assertTrue("changed name correctly", rod.getName().equals("Rod")); + assertTrue("changed age correctly", rod.getAge() == 32); + + Map m = binder.getBindingResult().getModel(); + assertTrue("There is one element in map", m.size() == 2); + FieldAccessBean tb = (FieldAccessBean) m.get("person"); + assertTrue("Same object", tb.equals(rod)); + } + + public void testBindingNoErrorsNotIgnoreUnknown() throws Exception { + FieldAccessBean rod = new FieldAccessBean(); + DataBinder binder = new DataBinder(rod, "person"); + binder.initDirectFieldAccess(); + binder.setIgnoreUnknownFields(false); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("name", "Rod")); + pvs.addPropertyValue(new PropertyValue("age", new Integer(32))); + pvs.addPropertyValue(new PropertyValue("nonExisting", "someValue")); + + try { + binder.bind(pvs); + fail("Should have thrown NotWritablePropertyException"); + } + catch (NotWritablePropertyException ex) { + // expected + } + } + + public void testBindingWithErrors() throws Exception { + FieldAccessBean rod = new FieldAccessBean(); + DataBinder binder = new DataBinder(rod, "person"); + binder.initDirectFieldAccess(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("name", "Rod")); + pvs.addPropertyValue(new PropertyValue("age", "32x")); + binder.bind(pvs); + + try { + binder.close(); + fail("Should have thrown BindException"); + } + catch (BindException ex) { + assertTrue("changed name correctly", rod.getName().equals("Rod")); + //assertTrue("changed age correctly", rod.getAge() == 32); + + Map map = binder.getBindingResult().getModel(); + //assertTrue("There are 3 element in map", m.size() == 1); + FieldAccessBean tb = (FieldAccessBean) map.get("person"); + assertTrue("Same object", tb.equals(rod)); + + BindingResult br = (BindingResult) map.get(BindingResult.MODEL_KEY_PREFIX + "person"); + assertTrue("Added itself to map", br == binder.getBindingResult()); + assertTrue(br.hasErrors()); + assertTrue("Correct number of errors", br.getErrorCount() == 1); + + assertTrue("Has age errors", br.hasFieldErrors("age")); + assertTrue("Correct number of age errors", br.getFieldErrorCount("age") == 1); + assertEquals("32x", binder.getBindingResult().getFieldValue("age")); + assertEquals("32x", binder.getBindingResult().getFieldError("age").getRejectedValue()); + assertEquals(0, tb.getAge()); + } + } + + public void testBindingWithErrorsAndCustomEditors() throws Exception { + FieldAccessBean rod = new FieldAccessBean(); + DataBinder binder = new DataBinder(rod, "person"); + binder.initDirectFieldAccess(); + binder.registerCustomEditor(TestBean.class, "spouse", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean(text, 0)); + } + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("name", "Rod")); + pvs.addPropertyValue(new PropertyValue("age", "32x")); + pvs.addPropertyValue(new PropertyValue("spouse", "Kerry")); + binder.bind(pvs); + + try { + binder.close(); + fail("Should have thrown BindException"); + } + catch (BindException ex) { + assertTrue("changed name correctly", rod.getName().equals("Rod")); + //assertTrue("changed age correctly", rod.getAge() == 32); + + Map model = binder.getBindingResult().getModel(); + //assertTrue("There are 3 element in map", m.size() == 1); + FieldAccessBean tb = (FieldAccessBean) model.get("person"); + assertTrue("Same object", tb.equals(rod)); + + BindingResult br = (BindingResult) model.get(BindingResult.MODEL_KEY_PREFIX + "person"); + assertTrue("Added itself to map", br == binder.getBindingResult()); + assertTrue(br.hasErrors()); + assertTrue("Correct number of errors", br.getErrorCount() == 1); + + assertTrue("Has age errors", br.hasFieldErrors("age")); + assertTrue("Correct number of age errors", br.getFieldErrorCount("age") == 1); + assertEquals("32x", binder.getBindingResult().getFieldValue("age")); + assertEquals("32x", binder.getBindingResult().getFieldError("age").getRejectedValue()); + assertEquals(0, tb.getAge()); + + assertTrue("Does not have spouse errors", !br.hasFieldErrors("spouse")); + assertEquals("Kerry", binder.getBindingResult().getFieldValue("spouse")); + assertNotNull(tb.getSpouse()); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderTests.java new file mode 100644 index 00000000000..099810ea02b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/validation/DataBinderTests.java @@ -0,0 +1,1348 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation; + +import java.beans.PropertyEditorSupport; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import junit.framework.TestCase; + +import org.springframework.beans.BeanWithObjectProperty; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.NotWritablePropertyException; +import org.springframework.beans.NullValueInNestedPathException; +import org.springframework.beans.SerializablePerson; +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.CustomCollectionEditor; +import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.context.support.ResourceBundleMessageSource; +import org.springframework.context.support.StaticMessageSource; +import org.springframework.util.StringUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + */ +public class DataBinderTests extends TestCase { + + public void testBindingNoErrors() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + assertTrue(binder.isIgnoreUnknownFields()); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "032"); + pvs.addPropertyValue("nonExisting", "someValue"); + + binder.bind(pvs); + binder.close(); + + assertTrue("changed name correctly", rod.getName().equals("Rod")); + assertTrue("changed age correctly", rod.getAge() == 32); + + Map map = binder.getBindingResult().getModel(); + assertTrue("There is one element in map", map.size() == 2); + TestBean tb = (TestBean) map.get("person"); + assertTrue("Same object", tb.equals(rod)); + + BindingResult other = new BeanPropertyBindingResult(rod, "person"); + assertEquals(other, binder.getBindingResult()); + assertEquals(binder.getBindingResult(), other); + BindException ex = new BindException(other); + assertEquals(ex, other); + assertEquals(other, ex); + assertEquals(ex, binder.getBindingResult()); + assertEquals(binder.getBindingResult(), ex); + + other.reject("xxx"); + assertTrue(!other.equals(binder.getBindingResult())); + } + + public void testedBindingWithDefaultConversionNoErrors() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + assertTrue(binder.isIgnoreUnknownFields()); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("jedi", "on"); + + binder.bind(pvs); + binder.close(); + + assertEquals("Rod", rod.getName()); + assertTrue(rod.isJedi()); + } + + public void testedNestedBindingWithDefaultConversionNoErrors() throws Exception { + TestBean rod = new TestBean(new TestBean()); + DataBinder binder = new DataBinder(rod, "person"); + assertTrue(binder.isIgnoreUnknownFields()); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("spouse.name", "Kerry"); + pvs.addPropertyValue("spouse.jedi", "on"); + + binder.bind(pvs); + binder.close(); + + assertEquals("Kerry", rod.getSpouse().getName()); + assertTrue(((TestBean) rod.getSpouse()).isJedi()); + } + + public void testBindingNoErrorsNotIgnoreUnknown() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + binder.setIgnoreUnknownFields(false); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", new Integer(32)); + pvs.addPropertyValue("nonExisting", "someValue"); + + try { + binder.bind(pvs); + fail("Should have thrown NotWritablePropertyException"); + } + catch (NotWritablePropertyException ex) { + // expected + } + } + + public void testBindingNoErrorsWithInvalidField() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("spouse.age", new Integer(32)); + + try { + binder.bind(pvs); + fail("Should have thrown NullValueInNestedPathException"); + } + catch (NullValueInNestedPathException ex) { + // expected + } + } + + public void testBindingNoErrorsWithIgnoreInvalid() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + binder.setIgnoreInvalidFields(true); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("spouse.age", new Integer(32)); + + binder.bind(pvs); + } + + public void testBindingWithErrors() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "32x"); + pvs.addPropertyValue("touchy", "m.y"); + binder.bind(pvs); + + try { + binder.close(); + fail("Should have thrown BindException"); + } + catch (BindException ex) { + assertTrue("changed name correctly", rod.getName().equals("Rod")); + //assertTrue("changed age correctly", rod.getAge() == 32); + + Map map = binder.getBindingResult().getModel(); + //assertTrue("There are 3 element in map", m.size() == 1); + TestBean tb = (TestBean) map.get("person"); + assertTrue("Same object", tb.equals(rod)); + + BindingResult br = (BindingResult) map.get(BindingResult.MODEL_KEY_PREFIX + "person"); + assertSame(br, BindingResultUtils.getBindingResult(map, "person")); + assertSame(br, BindingResultUtils.getRequiredBindingResult(map, "person")); + + assertNull(BindingResultUtils.getBindingResult(map, "someOtherName")); + try { + BindingResultUtils.getRequiredBindingResult(map, "someOtherName"); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException expected) { + } + + assertTrue("Added itself to map", br == binder.getBindingResult()); + assertTrue(br.hasErrors()); + assertTrue("Correct number of errors", br.getErrorCount() == 2); + + assertTrue("Has age errors", br.hasFieldErrors("age")); + assertTrue("Correct number of age errors", br.getFieldErrorCount("age") == 1); + assertEquals("32x", binder.getBindingResult().getFieldValue("age")); + assertEquals("32x", binder.getBindingResult().getFieldError("age").getRejectedValue()); + assertEquals(0, tb.getAge()); + + assertTrue("Has touchy errors", br.hasFieldErrors("touchy")); + assertTrue("Correct number of touchy errors", br.getFieldErrorCount("touchy") == 1); + assertEquals("m.y", binder.getBindingResult().getFieldValue("touchy")); + assertEquals("m.y", binder.getBindingResult().getFieldError("touchy").getRejectedValue()); + assertNull(tb.getTouchy()); + + rod = new TestBean(); + binder = new DataBinder(rod, "person"); + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "32x"); + pvs.addPropertyValue("touchy", "m.y"); + binder.bind(pvs); + assertEquals(binder.getBindingResult(), ex.getBindingResult()); + } + } + + public void testBindingWithErrorsAndCustomEditors() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + binder.registerCustomEditor(String.class, "touchy", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix_" + text); + } + public String getAsText() { + return getValue().toString().substring(7); + } + }); + binder.registerCustomEditor(TestBean.class, "spouse", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean(text, 0)); + } + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "32x"); + pvs.addPropertyValue("touchy", "m.y"); + pvs.addPropertyValue("spouse", "Kerry"); + binder.bind(pvs); + + try { + binder.close(); + fail("Should have thrown BindException"); + } + catch (BindException ex) { + assertTrue("changed name correctly", rod.getName().equals("Rod")); + //assertTrue("changed age correctly", rod.getAge() == 32); + + Map model = binder.getBindingResult().getModel(); + //assertTrue("There are 3 element in map", m.size() == 1); + TestBean tb = (TestBean) model.get("person"); + assertTrue("Same object", tb.equals(rod)); + + BindingResult br = (BindingResult) model.get(BindingResult.MODEL_KEY_PREFIX + "person"); + assertTrue("Added itself to map", br == binder.getBindingResult()); + assertTrue(br.hasErrors()); + assertTrue("Correct number of errors", br.getErrorCount() == 2); + + assertTrue("Has age errors", br.hasFieldErrors("age")); + assertTrue("Correct number of age errors", br.getFieldErrorCount("age") == 1); + assertEquals("32x", binder.getBindingResult().getFieldValue("age")); + assertEquals("32x", binder.getBindingResult().getFieldError("age").getRejectedValue()); + assertEquals(0, tb.getAge()); + + assertTrue("Has touchy errors", br.hasFieldErrors("touchy")); + assertTrue("Correct number of touchy errors", br.getFieldErrorCount("touchy") == 1); + assertEquals("m.y", binder.getBindingResult().getFieldValue("touchy")); + assertEquals("m.y", binder.getBindingResult().getFieldError("touchy").getRejectedValue()); + assertNull(tb.getTouchy()); + + assertTrue("Does not have spouse errors", !br.hasFieldErrors("spouse")); + assertEquals("Kerry", binder.getBindingResult().getFieldValue("spouse")); + assertNotNull(tb.getSpouse()); + } + } + + public void testBindingWithCustomEditorOnObjectField() { + BeanWithObjectProperty tb = new BeanWithObjectProperty(); + DataBinder binder = new DataBinder(tb); + binder.registerCustomEditor(Integer.class, "object", new CustomNumberEditor(Integer.class, true)); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("object", "1"); + binder.bind(pvs); + assertEquals(new Integer(1), tb.getObject()); + } + + public void testBindingWithAllowedFields() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod); + binder.setAllowedFields(new String[] {"name", "myparam"}); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "32x"); + + binder.bind(pvs); + binder.close(); + assertTrue("changed name correctly", rod.getName().equals("Rod")); + assertTrue("did not change age", rod.getAge() == 0); + } + + public void testBindingWithDisallowedFields() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod); + binder.setDisallowedFields(new String[] {"age"}); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "32x"); + + binder.bind(pvs); + binder.close(); + assertTrue("changed name correctly", rod.getName().equals("Rod")); + assertTrue("did not change age", rod.getAge() == 0); + String[] disallowedFields = binder.getBindingResult().getSuppressedFields(); + assertEquals(1, disallowedFields.length); + assertEquals("age", disallowedFields[0]); + } + + public void testBindingWithAllowedAndDisallowedFields() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod); + binder.setAllowedFields(new String[] {"name", "myparam"}); + binder.setDisallowedFields(new String[] {"age"}); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "32x"); + + binder.bind(pvs); + binder.close(); + assertTrue("changed name correctly", rod.getName().equals("Rod")); + assertTrue("did not change age", rod.getAge() == 0); + String[] disallowedFields = binder.getBindingResult().getSuppressedFields(); + assertEquals(1, disallowedFields.length); + assertEquals("age", disallowedFields[0]); + } + + public void testBindingWithOverlappingAllowedAndDisallowedFields() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod); + binder.setAllowedFields(new String[] {"name", "age"}); + binder.setDisallowedFields(new String[] {"age"}); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("age", "32x"); + + binder.bind(pvs); + binder.close(); + assertTrue("changed name correctly", rod.getName().equals("Rod")); + assertTrue("did not change age", rod.getAge() == 0); + String[] disallowedFields = binder.getBindingResult().getSuppressedFields(); + assertEquals(1, disallowedFields.length); + assertEquals("age", disallowedFields[0]); + } + + public void testBindingWithAllowedFieldsUsingAsterisks() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + binder.setAllowedFields(new String[] {"nam*", "*ouchy"}); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "Rod"); + pvs.addPropertyValue("touchy", "Rod"); + pvs.addPropertyValue("age", "32x"); + + binder.bind(pvs); + binder.close(); + + assertTrue("changed name correctly", "Rod".equals(rod.getName())); + assertTrue("changed touchy correctly", "Rod".equals(rod.getTouchy())); + assertTrue("did not change age", rod.getAge() == 0); + String[] disallowedFields = binder.getBindingResult().getSuppressedFields(); + assertEquals(1, disallowedFields.length); + assertEquals("age", disallowedFields[0]); + + Map m = binder.getBindingResult().getModel(); + assertTrue("There is one element in map", m.size() == 2); + TestBean tb = (TestBean) m.get("person"); + assertTrue("Same object", tb.equals(rod)); + } + + public void testBindingWithAllowedAndDisallowedMapFields() throws Exception { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod); + binder.setAllowedFields(new String[] {"someMap[key1]", "someMap[key2]"}); + binder.setDisallowedFields(new String[] {"someMap['key3']", "someMap[key4]"}); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("someMap[key1]", "value1"); + pvs.addPropertyValue("someMap['key2']", "value2"); + pvs.addPropertyValue("someMap[key3]", "value3"); + pvs.addPropertyValue("someMap['key4']", "value4"); + + binder.bind(pvs); + binder.close(); + assertEquals("value1", rod.getSomeMap().get("key1")); + assertEquals("value2", rod.getSomeMap().get("key2")); + assertNull(rod.getSomeMap().get("key3")); + assertNull(rod.getSomeMap().get("key4")); + String[] disallowedFields = binder.getBindingResult().getSuppressedFields(); + assertEquals(2, disallowedFields.length); + assertEquals("someMap[key3]", disallowedFields[0]); + assertEquals("someMap[key4]", disallowedFields[1]); + } + + /** + * Tests for required field, both null, non-existing and empty strings. + */ + public void testBindingWithRequiredFields() throws Exception { + TestBean tb = new TestBean(); + tb.setSpouse(new TestBean()); + + DataBinder binder = new DataBinder(tb, "person"); + binder.setRequiredFields(new String[] {"touchy", "name", "age", "date", "spouse.name"}); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("touchy", ""); + pvs.addPropertyValue("name", null); + pvs.addPropertyValue("age", null); + pvs.addPropertyValue("spouse.name", " "); + + binder.bind(pvs); + + BindingResult br = binder.getBindingResult(); + assertEquals("Wrong number of errors", 5, br.getErrorCount()); + + assertEquals("required", br.getFieldError("touchy").getCode()); + assertEquals("", br.getFieldValue("touchy")); + assertEquals("required", br.getFieldError("name").getCode()); + assertEquals("", br.getFieldValue("name")); + assertEquals("required", br.getFieldError("age").getCode()); + assertEquals("", br.getFieldValue("age")); + assertEquals("required", br.getFieldError("date").getCode()); + assertEquals("", br.getFieldValue("date")); + assertEquals("required", br.getFieldError("spouse.name").getCode()); + assertEquals("", br.getFieldValue("spouse.name")); + } + + public void testBindingWithRequiredMapFields() throws Exception { + TestBean tb = new TestBean(); + tb.setSpouse(new TestBean()); + + DataBinder binder = new DataBinder(tb, "person"); + binder.setRequiredFields(new String[] {"someMap[key1]", "someMap[key2]", "someMap['key3']", "someMap[key4]"}); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("someMap[key1]", "value1"); + pvs.addPropertyValue("someMap['key2']", "value2"); + pvs.addPropertyValue("someMap[key3]", "value3"); + + binder.bind(pvs); + + BindingResult br = binder.getBindingResult(); + assertEquals("Wrong number of errors", 1, br.getErrorCount()); + assertEquals("required", br.getFieldError("someMap[key4]").getCode()); + } + + public void testBindingWithNestedObjectCreation() throws Exception { + TestBean tb = new TestBean(); + + DataBinder binder = new DataBinder(tb, "person"); + binder.registerCustomEditor(ITestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean()); + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("spouse", "someValue"); + pvs.addPropertyValue("spouse.name", "test"); + binder.bind(pvs); + + assertNotNull(tb.getSpouse()); + assertEquals("test", tb.getSpouse().getName()); + } + + public void testCustomEditorForSingleProperty() { + TestBean tb = new TestBean(); + tb.setSpouse(new TestBean()); + DataBinder binder = new DataBinder(tb, "tb"); + + binder.registerCustomEditor(String.class, "name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix" + text); + } + public String getAsText() { + return ((String) getValue()).substring(6); + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "value"); + pvs.addPropertyValue("touchy", "value"); + pvs.addPropertyValue("spouse.name", "sue"); + binder.bind(pvs); + + binder.getBindingResult().rejectValue("name", "someCode", "someMessage"); + binder.getBindingResult().rejectValue("touchy", "someCode", "someMessage"); + binder.getBindingResult().rejectValue("spouse.name", "someCode", "someMessage"); + + assertEquals("", binder.getBindingResult().getNestedPath()); + assertEquals("value", binder.getBindingResult().getFieldValue("name")); + assertEquals("prefixvalue", binder.getBindingResult().getFieldError("name").getRejectedValue()); + assertEquals("prefixvalue", tb.getName()); + assertEquals("value", binder.getBindingResult().getFieldValue("touchy")); + assertEquals("value", binder.getBindingResult().getFieldError("touchy").getRejectedValue()); + assertEquals("value", tb.getTouchy()); + + assertTrue(binder.getBindingResult().hasFieldErrors("spouse.*")); + assertEquals(1, binder.getBindingResult().getFieldErrorCount("spouse.*")); + assertEquals("spouse.name", binder.getBindingResult().getFieldError("spouse.*").getField()); + } + + public void testCustomEditorForPrimitiveProperty() { + TestBean tb = new TestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + + binder.registerCustomEditor(int.class, "age", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new Integer(99)); + } + public String getAsText() { + return "argh"; + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", ""); + binder.bind(pvs); + + assertEquals("argh", binder.getBindingResult().getFieldValue("age")); + assertEquals(99, tb.getAge()); + } + + public void testCustomEditorForAllStringProperties() { + TestBean tb = new TestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + + binder.registerCustomEditor(String.class, null, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("prefix" + text); + } + public String getAsText() { + return ((String) getValue()).substring(6); + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "value"); + pvs.addPropertyValue("touchy", "value"); + binder.bind(pvs); + + binder.getBindingResult().rejectValue("name", "someCode", "someMessage"); + binder.getBindingResult().rejectValue("touchy", "someCode", "someMessage"); + + assertEquals("value", binder.getBindingResult().getFieldValue("name")); + assertEquals("prefixvalue", binder.getBindingResult().getFieldError("name").getRejectedValue()); + assertEquals("prefixvalue", tb.getName()); + assertEquals("value", binder.getBindingResult().getFieldValue("touchy")); + assertEquals("prefixvalue", binder.getBindingResult().getFieldError("touchy").getRejectedValue()); + assertEquals("prefixvalue", tb.getTouchy()); + } + + public void testCustomEditorWithOldValueAccess() { + TestBean tb = new TestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + + binder.registerCustomEditor(String.class, null, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + if (getValue() == null || !text.equalsIgnoreCase(getValue().toString())) { + setValue(text); + } + } + }); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "value"); + binder.bind(pvs); + assertEquals("value", tb.getName()); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("name", "vaLue"); + binder.bind(pvs); + assertEquals("value", tb.getName()); + } + + public void testValidatorNoErrors() { + TestBean tb = new TestBean(); + tb.setAge(33); + tb.setName("Rod"); + try { + tb.setTouchy("Rod"); + } + catch (Exception e) { + fail("Should not throw any Exception"); + } + TestBean tb2 = new TestBean(); + tb2.setAge(34); + tb.setSpouse(tb2); + DataBinder db = new DataBinder(tb, "tb"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("spouse.age", "argh"); + db.bind(pvs); + Errors errors = db.getBindingResult(); + Validator testValidator = new TestBeanValidator(); + testValidator.validate(tb, errors); + + errors.setNestedPath("spouse"); + assertEquals("spouse.", errors.getNestedPath()); + assertEquals("argh", errors.getFieldValue("age")); + Validator spouseValidator = new SpouseValidator(); + spouseValidator.validate(tb.getSpouse(), errors); + + errors.setNestedPath(""); + assertEquals("", errors.getNestedPath()); + errors.pushNestedPath("spouse"); + assertEquals("spouse.", errors.getNestedPath()); + errors.pushNestedPath("spouse"); + assertEquals("spouse.spouse.", errors.getNestedPath()); + errors.popNestedPath(); + assertEquals("spouse.", errors.getNestedPath()); + errors.popNestedPath(); + assertEquals("", errors.getNestedPath()); + try { + errors.popNestedPath(); + } + catch (IllegalStateException ex) { + // expected, because stack was empty + } + errors.pushNestedPath("spouse"); + assertEquals("spouse.", errors.getNestedPath()); + errors.setNestedPath(""); + assertEquals("", errors.getNestedPath()); + try { + errors.popNestedPath(); + } + catch (IllegalStateException ex) { + // expected, because stack was reset by setNestedPath + } + + errors.pushNestedPath("spouse"); + assertEquals("spouse.", errors.getNestedPath()); + + assertEquals(1, errors.getErrorCount()); + assertTrue(!errors.hasGlobalErrors()); + assertEquals(1, errors.getFieldErrorCount("age")); + assertTrue(!errors.hasFieldErrors("name")); + } + + public void testValidatorWithErrors() { + TestBean tb = new TestBean(); + tb.setSpouse(new TestBean()); + + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + + Validator testValidator = new TestBeanValidator(); + testValidator.validate(tb, errors); + + errors.setNestedPath("spouse."); + assertEquals("spouse.", errors.getNestedPath()); + Validator spouseValidator = new SpouseValidator(); + spouseValidator.validate(tb.getSpouse(), errors); + + errors.setNestedPath(""); + assertTrue(errors.hasErrors()); + assertEquals(6, errors.getErrorCount()); + + assertEquals(2, errors.getGlobalErrorCount()); + assertEquals("NAME_TOUCHY_MISMATCH", errors.getGlobalError().getCode()); + assertEquals("NAME_TOUCHY_MISMATCH", ((ObjectError) errors.getGlobalErrors().get(0)).getCode()); + assertEquals("NAME_TOUCHY_MISMATCH.tb", ((ObjectError) errors.getGlobalErrors().get(0)).getCodes()[0]); + assertEquals("NAME_TOUCHY_MISMATCH", ((ObjectError) errors.getGlobalErrors().get(0)).getCodes()[1]); + assertEquals("tb", ((ObjectError) errors.getGlobalErrors().get(0)).getObjectName()); + assertEquals("GENERAL_ERROR", ((ObjectError) errors.getGlobalErrors().get(1)).getCode()); + assertEquals("GENERAL_ERROR.tb", ((ObjectError) errors.getGlobalErrors().get(1)).getCodes()[0]); + assertEquals("GENERAL_ERROR", ((ObjectError) errors.getGlobalErrors().get(1)).getCodes()[1]); + assertEquals("msg", ((ObjectError) errors.getGlobalErrors().get(1)).getDefaultMessage()); + assertEquals("arg", ((ObjectError) errors.getGlobalErrors().get(1)).getArguments()[0]); + + assertTrue(errors.hasFieldErrors()); + assertEquals(4, errors.getFieldErrorCount()); + assertEquals("TOO_YOUNG", errors.getFieldError().getCode()); + assertEquals("TOO_YOUNG", ((FieldError) errors.getFieldErrors().get(0)).getCode()); + assertEquals("age", ((FieldError) errors.getFieldErrors().get(0)).getField()); + assertEquals("AGE_NOT_ODD", ((FieldError) errors.getFieldErrors().get(1)).getCode()); + assertEquals("age", ((FieldError) errors.getFieldErrors().get(1)).getField()); + assertEquals("NOT_ROD", ((FieldError) errors.getFieldErrors().get(2)).getCode()); + assertEquals("name", ((FieldError) errors.getFieldErrors().get(2)).getField()); + assertEquals("TOO_YOUNG", ((FieldError) errors.getFieldErrors().get(3)).getCode()); + assertEquals("spouse.age", ((FieldError) errors.getFieldErrors().get(3)).getField()); + + assertTrue(errors.hasFieldErrors("age")); + assertEquals(2, errors.getFieldErrorCount("age")); + assertEquals("TOO_YOUNG", errors.getFieldError("age").getCode()); + assertEquals("TOO_YOUNG", ((FieldError) errors.getFieldErrors("age").get(0)).getCode()); + assertEquals("tb", ((FieldError) errors.getFieldErrors("age").get(0)).getObjectName()); + assertEquals("age", ((FieldError) errors.getFieldErrors("age").get(0)).getField()); + assertEquals(new Integer(0), ((FieldError) errors.getFieldErrors("age").get(0)).getRejectedValue()); + assertEquals("AGE_NOT_ODD", ((FieldError) errors.getFieldErrors("age").get(1)).getCode()); + + assertTrue(errors.hasFieldErrors("name")); + assertEquals(1, errors.getFieldErrorCount("name")); + assertEquals("NOT_ROD", errors.getFieldError("name").getCode()); + assertEquals("NOT_ROD.tb.name", errors.getFieldError("name").getCodes()[0]); + assertEquals("NOT_ROD.name", errors.getFieldError("name").getCodes()[1]); + assertEquals("NOT_ROD.java.lang.String", errors.getFieldError("name").getCodes()[2]); + assertEquals("NOT_ROD", errors.getFieldError("name").getCodes()[3]); + assertEquals("name", ((FieldError) errors.getFieldErrors("name").get(0)).getField()); + assertEquals(null, ((FieldError) errors.getFieldErrors("name").get(0)).getRejectedValue()); + + assertTrue(errors.hasFieldErrors("spouse.age")); + assertEquals(1, errors.getFieldErrorCount("spouse.age")); + assertEquals("TOO_YOUNG", errors.getFieldError("spouse.age").getCode()); + assertEquals("tb", ((FieldError) errors.getFieldErrors("spouse.age").get(0)).getObjectName()); + assertEquals(new Integer(0), ((FieldError) errors.getFieldErrors("spouse.age").get(0)).getRejectedValue()); + } + + public void testValidatorWithErrorsAndCodesPrefix() { + TestBean tb = new TestBean(); + tb.setSpouse(new TestBean()); + + BeanPropertyBindingResult errors = new BeanPropertyBindingResult(tb, "tb"); + DefaultMessageCodesResolver codesResolver = new DefaultMessageCodesResolver(); + codesResolver.setPrefix("validation."); + errors.setMessageCodesResolver(codesResolver); + + Validator testValidator = new TestBeanValidator(); + testValidator.validate(tb, errors); + + errors.setNestedPath("spouse."); + assertEquals("spouse.", errors.getNestedPath()); + Validator spouseValidator = new SpouseValidator(); + spouseValidator.validate(tb.getSpouse(), errors); + + errors.setNestedPath(""); + assertTrue(errors.hasErrors()); + assertEquals(6, errors.getErrorCount()); + + assertEquals(2, errors.getGlobalErrorCount()); + assertEquals("validation.NAME_TOUCHY_MISMATCH", errors.getGlobalError().getCode()); + assertEquals("validation.NAME_TOUCHY_MISMATCH", ((ObjectError) errors.getGlobalErrors().get(0)).getCode()); + assertEquals("validation.NAME_TOUCHY_MISMATCH.tb", ((ObjectError) errors.getGlobalErrors().get(0)).getCodes()[0]); + assertEquals("validation.NAME_TOUCHY_MISMATCH", ((ObjectError) errors.getGlobalErrors().get(0)).getCodes()[1]); + assertEquals("tb", ((ObjectError) errors.getGlobalErrors().get(0)).getObjectName()); + assertEquals("validation.GENERAL_ERROR", ((ObjectError) errors.getGlobalErrors().get(1)).getCode()); + assertEquals("validation.GENERAL_ERROR.tb", ((ObjectError) errors.getGlobalErrors().get(1)).getCodes()[0]); + assertEquals("validation.GENERAL_ERROR", ((ObjectError) errors.getGlobalErrors().get(1)).getCodes()[1]); + assertEquals("msg", ((ObjectError) errors.getGlobalErrors().get(1)).getDefaultMessage()); + assertEquals("arg", ((ObjectError) errors.getGlobalErrors().get(1)).getArguments()[0]); + + assertTrue(errors.hasFieldErrors()); + assertEquals(4, errors.getFieldErrorCount()); + assertEquals("validation.TOO_YOUNG", errors.getFieldError().getCode()); + assertEquals("validation.TOO_YOUNG", ((FieldError) errors.getFieldErrors().get(0)).getCode()); + assertEquals("age", ((FieldError) errors.getFieldErrors().get(0)).getField()); + assertEquals("validation.AGE_NOT_ODD", ((FieldError) errors.getFieldErrors().get(1)).getCode()); + assertEquals("age", ((FieldError) errors.getFieldErrors().get(1)).getField()); + assertEquals("validation.NOT_ROD", ((FieldError) errors.getFieldErrors().get(2)).getCode()); + assertEquals("name", ((FieldError) errors.getFieldErrors().get(2)).getField()); + assertEquals("validation.TOO_YOUNG", ((FieldError) errors.getFieldErrors().get(3)).getCode()); + assertEquals("spouse.age", ((FieldError) errors.getFieldErrors().get(3)).getField()); + + assertTrue(errors.hasFieldErrors("age")); + assertEquals(2, errors.getFieldErrorCount("age")); + assertEquals("validation.TOO_YOUNG", errors.getFieldError("age").getCode()); + assertEquals("validation.TOO_YOUNG", ((FieldError) errors.getFieldErrors("age").get(0)).getCode()); + assertEquals("tb", ((FieldError) errors.getFieldErrors("age").get(0)).getObjectName()); + assertEquals("age", ((FieldError) errors.getFieldErrors("age").get(0)).getField()); + assertEquals(new Integer(0), ((FieldError) errors.getFieldErrors("age").get(0)).getRejectedValue()); + assertEquals("validation.AGE_NOT_ODD", ((FieldError) errors.getFieldErrors("age").get(1)).getCode()); + + assertTrue(errors.hasFieldErrors("name")); + assertEquals(1, errors.getFieldErrorCount("name")); + assertEquals("validation.NOT_ROD", errors.getFieldError("name").getCode()); + assertEquals("validation.NOT_ROD.tb.name", errors.getFieldError("name").getCodes()[0]); + assertEquals("validation.NOT_ROD.name", errors.getFieldError("name").getCodes()[1]); + assertEquals("validation.NOT_ROD.java.lang.String", errors.getFieldError("name").getCodes()[2]); + assertEquals("validation.NOT_ROD", errors.getFieldError("name").getCodes()[3]); + assertEquals("name", ((FieldError) errors.getFieldErrors("name").get(0)).getField()); + assertEquals(null, ((FieldError) errors.getFieldErrors("name").get(0)).getRejectedValue()); + + assertTrue(errors.hasFieldErrors("spouse.age")); + assertEquals(1, errors.getFieldErrorCount("spouse.age")); + assertEquals("validation.TOO_YOUNG", errors.getFieldError("spouse.age").getCode()); + assertEquals("tb", ((FieldError) errors.getFieldErrors("spouse.age").get(0)).getObjectName()); + assertEquals(new Integer(0), ((FieldError) errors.getFieldErrors("spouse.age").get(0)).getRejectedValue()); + } + + public void testValidatorWithNestedObjectNull() { + TestBean tb = new TestBean(); + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + Validator testValidator = new TestBeanValidator(); + testValidator.validate(tb, errors); + errors.setNestedPath("spouse."); + assertEquals("spouse.", errors.getNestedPath()); + Validator spouseValidator = new SpouseValidator(); + spouseValidator.validate(tb.getSpouse(), errors); + errors.setNestedPath(""); + + assertTrue(errors.hasFieldErrors("spouse")); + assertEquals(1, errors.getFieldErrorCount("spouse")); + assertEquals("SPOUSE_NOT_AVAILABLE", errors.getFieldError("spouse").getCode()); + assertEquals("tb", ((FieldError) errors.getFieldErrors("spouse").get(0)).getObjectName()); + assertEquals(null, ((FieldError) errors.getFieldErrors("spouse").get(0)).getRejectedValue()); + } + + public void testNestedValidatorWithoutNestedPath() { + TestBean tb = new TestBean(); + tb.setName("XXX"); + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + Validator spouseValidator = new SpouseValidator(); + spouseValidator.validate(tb, errors); + + assertTrue(errors.hasGlobalErrors()); + assertEquals(1, errors.getGlobalErrorCount()); + assertEquals("SPOUSE_NOT_AVAILABLE", errors.getGlobalError().getCode()); + assertEquals("tb", ((ObjectError) errors.getGlobalErrors().get(0)).getObjectName()); + } + + public void testBindingStringArrayToIntegerSet() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(Set.class, new CustomCollectionEditor(TreeSet.class) { + protected Object convertElement(Object element) { + return new Integer(element.toString()); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("set", new String[] {"10", "20", "30"}); + binder.bind(pvs); + + assertEquals(tb.getSet(), binder.getBindingResult().getFieldValue("set")); + assertTrue(tb.getSet() instanceof TreeSet); + assertEquals(3, tb.getSet().size()); + assertTrue(tb.getSet().contains(new Integer(10))); + assertTrue(tb.getSet().contains(new Integer(20))); + assertTrue(tb.getSet().contains(new Integer(30))); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("set", null); + binder.bind(pvs); + + assertNull(tb.getSet()); + } + + public void testBindingNullToEmptyCollection() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(Set.class, new CustomCollectionEditor(TreeSet.class, true)); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("set", null); + binder.bind(pvs); + + assertTrue(tb.getSet() instanceof TreeSet); + assertTrue(tb.getSet().isEmpty()); + } + + public void testBindingToIndexedField() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(String.class, "array.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("array" + text); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0]", "a"); + binder.bind(pvs); + Errors errors = binder.getBindingResult(); + errors.rejectValue("array[0].name", "NOT_ROD", "are you sure you're not Rod?"); + errors.rejectValue("map[key1].name", "NOT_ROD", "are you sure you're not Rod?"); + + assertEquals(1, errors.getFieldErrorCount("array[0].name")); + assertEquals("NOT_ROD", errors.getFieldError("array[0].name").getCode()); + assertEquals("NOT_ROD.tb.array[0].name", errors.getFieldError("array[0].name").getCodes()[0]); + assertEquals("NOT_ROD.tb.array.name", errors.getFieldError("array[0].name").getCodes()[1]); + assertEquals("NOT_ROD.array[0].name", errors.getFieldError("array[0].name").getCodes()[2]); + assertEquals("NOT_ROD.array.name", errors.getFieldError("array[0].name").getCodes()[3]); + assertEquals("NOT_ROD.name", errors.getFieldError("array[0].name").getCodes()[4]); + assertEquals("NOT_ROD.java.lang.String", errors.getFieldError("array[0].name").getCodes()[5]); + assertEquals("NOT_ROD", errors.getFieldError("array[0].name").getCodes()[6]); + assertEquals(1, errors.getFieldErrorCount("map[key1].name")); + assertEquals(1, errors.getFieldErrorCount("map['key1'].name")); + assertEquals(1, errors.getFieldErrorCount("map[\"key1\"].name")); + assertEquals("NOT_ROD", errors.getFieldError("map[key1].name").getCode()); + assertEquals("NOT_ROD.tb.map[key1].name", errors.getFieldError("map[key1].name").getCodes()[0]); + assertEquals("NOT_ROD.tb.map.name", errors.getFieldError("map[key1].name").getCodes()[1]); + assertEquals("NOT_ROD.map[key1].name", errors.getFieldError("map[key1].name").getCodes()[2]); + assertEquals("NOT_ROD.map.name", errors.getFieldError("map[key1].name").getCodes()[3]); + assertEquals("NOT_ROD.name", errors.getFieldError("map[key1].name").getCodes()[4]); + assertEquals("NOT_ROD.java.lang.String", errors.getFieldError("map[key1].name").getCodes()[5]); + assertEquals("NOT_ROD", errors.getFieldError("map[key1].name").getCodes()[6]); + } + + public void testBindingToNestedIndexedField() { + IndexedTestBean tb = new IndexedTestBean(); + tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean()); + tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean()); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(String.class, "array.nestedIndexedBean.list.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list" + text); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].nestedIndexedBean.list[0].name", "a"); + binder.bind(pvs); + Errors errors = binder.getBindingResult(); + errors.rejectValue("array[0].nestedIndexedBean.list[0].name", "NOT_ROD", "are you sure you're not Rod?"); + + assertEquals(1, errors.getFieldErrorCount("array[0].nestedIndexedBean.list[0].name")); + assertEquals("NOT_ROD", errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCode()); + assertEquals("NOT_ROD.tb.array[0].nestedIndexedBean.list[0].name", + errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[0]); + assertEquals("NOT_ROD.tb.array[0].nestedIndexedBean.list.name", + errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[1]); + assertEquals("NOT_ROD.tb.array.nestedIndexedBean.list.name", + errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[2]); + assertEquals("NOT_ROD.array[0].nestedIndexedBean.list[0].name", + errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[3]); + assertEquals("NOT_ROD.array[0].nestedIndexedBean.list.name", + errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[4]); + assertEquals("NOT_ROD.array.nestedIndexedBean.list.name", + errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[5]); + assertEquals("NOT_ROD.name", errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[6]); + assertEquals("NOT_ROD.java.lang.String", + errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[7]); + assertEquals("NOT_ROD", errors.getFieldError("array[0].nestedIndexedBean.list[0].name").getCodes()[8]); + } + + public void testEditorForNestedIndexedField() { + IndexedTestBean tb = new IndexedTestBean(); + tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean()); + tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean()); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(String.class, "array.nestedIndexedBean.list.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list" + text); + } + public String getAsText() { + return ((String) getValue()).substring(4); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].nestedIndexedBean.list[0].name", "test1"); + pvs.addPropertyValue("array[1].nestedIndexedBean.list[1].name", "test2"); + binder.bind(pvs); + assertEquals("listtest1", ((TestBean) tb.getArray()[0].getNestedIndexedBean().getList().get(0)).getName()); + assertEquals("listtest2", ((TestBean) tb.getArray()[1].getNestedIndexedBean().getList().get(1)).getName()); + assertEquals("test1", binder.getBindingResult().getFieldValue("array[0].nestedIndexedBean.list[0].name")); + assertEquals("test2", binder.getBindingResult().getFieldValue("array[1].nestedIndexedBean.list[1].name")); + } + + public void testSpecificEditorForNestedIndexedField() { + IndexedTestBean tb = new IndexedTestBean(); + tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean()); + tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean()); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(String.class, "array[0].nestedIndexedBean.list.name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list" + text); + } + public String getAsText() { + return ((String) getValue()).substring(4); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].nestedIndexedBean.list[0].name", "test1"); + pvs.addPropertyValue("array[1].nestedIndexedBean.list[1].name", "test2"); + binder.bind(pvs); + assertEquals("listtest1", ((TestBean) tb.getArray()[0].getNestedIndexedBean().getList().get(0)).getName()); + assertEquals("test2", ((TestBean) tb.getArray()[1].getNestedIndexedBean().getList().get(1)).getName()); + assertEquals("test1", binder.getBindingResult().getFieldValue("array[0].nestedIndexedBean.list[0].name")); + assertEquals("test2", binder.getBindingResult().getFieldValue("array[1].nestedIndexedBean.list[1].name")); + } + + public void testInnerSpecificEditorForNestedIndexedField() { + IndexedTestBean tb = new IndexedTestBean(); + tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean()); + tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean()); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(String.class, "array.nestedIndexedBean.list[0].name", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("list" + text); + } + public String getAsText() { + return ((String) getValue()).substring(4); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0].nestedIndexedBean.list[0].name", "test1"); + pvs.addPropertyValue("array[1].nestedIndexedBean.list[1].name", "test2"); + binder.bind(pvs); + assertEquals("listtest1", ((TestBean) tb.getArray()[0].getNestedIndexedBean().getList().get(0)).getName()); + assertEquals("test2", ((TestBean) tb.getArray()[1].getNestedIndexedBean().getList().get(1)).getName()); + assertEquals("test1", binder.getBindingResult().getFieldValue("array[0].nestedIndexedBean.list[0].name")); + assertEquals("test2", binder.getBindingResult().getFieldValue("array[1].nestedIndexedBean.list[1].name")); + } + + public void testDirectBindingToIndexedField() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(TestBean.class, "array", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + DerivedTestBean tb = new DerivedTestBean(); + tb.setName("array" + text); + setValue(tb); + } + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0]", "a"); + binder.bind(pvs); + Errors errors = binder.getBindingResult(); + errors.rejectValue("array[0]", "NOT_ROD", "are you sure you're not Rod?"); + errors.rejectValue("map[key1]", "NOT_ROD", "are you sure you're not Rod?"); + errors.rejectValue("map[key0]", "NOT_NULL", "should not be null"); + + assertEquals("arraya", errors.getFieldValue("array[0]")); + assertEquals(1, errors.getFieldErrorCount("array[0]")); + assertEquals("NOT_ROD", errors.getFieldError("array[0]").getCode()); + assertEquals("NOT_ROD.tb.array[0]", errors.getFieldError("array[0]").getCodes()[0]); + assertEquals("NOT_ROD.tb.array", errors.getFieldError("array[0]").getCodes()[1]); + assertEquals("NOT_ROD.array[0]", errors.getFieldError("array[0]").getCodes()[2]); + assertEquals("NOT_ROD.array", errors.getFieldError("array[0]").getCodes()[3]); + assertEquals("NOT_ROD.org.springframework.beans.DerivedTestBean", errors.getFieldError("array[0]").getCodes()[4]); + assertEquals("NOT_ROD", errors.getFieldError("array[0]").getCodes()[5]); + assertEquals("arraya", errors.getFieldValue("array[0]")); + + assertEquals(1, errors.getFieldErrorCount("map[key1]")); + assertEquals("NOT_ROD", errors.getFieldError("map[key1]").getCode()); + assertEquals("NOT_ROD.tb.map[key1]", errors.getFieldError("map[key1]").getCodes()[0]); + assertEquals("NOT_ROD.tb.map", errors.getFieldError("map[key1]").getCodes()[1]); + assertEquals("NOT_ROD.map[key1]", errors.getFieldError("map[key1]").getCodes()[2]); + assertEquals("NOT_ROD.map", errors.getFieldError("map[key1]").getCodes()[3]); + assertEquals("NOT_ROD.org.springframework.beans.TestBean", errors.getFieldError("map[key1]").getCodes()[4]); + assertEquals("NOT_ROD", errors.getFieldError("map[key1]").getCodes()[5]); + + assertEquals(1, errors.getFieldErrorCount("map[key0]")); + assertEquals("NOT_NULL", errors.getFieldError("map[key0]").getCode()); + assertEquals("NOT_NULL.tb.map[key0]", errors.getFieldError("map[key0]").getCodes()[0]); + assertEquals("NOT_NULL.tb.map", errors.getFieldError("map[key0]").getCodes()[1]); + assertEquals("NOT_NULL.map[key0]", errors.getFieldError("map[key0]").getCodes()[2]); + assertEquals("NOT_NULL.map", errors.getFieldError("map[key0]").getCodes()[3]); + assertEquals("NOT_NULL", errors.getFieldError("map[key0]").getCodes()[4]); + } + + public void testDirectBindingToEmptyIndexedFieldWithRegisteredSpecificEditor() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(TestBean.class, "map[key0]", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + DerivedTestBean tb = new DerivedTestBean(); + tb.setName("array" + text); + setValue(tb); + } + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + Errors errors = binder.getBindingResult(); + errors.rejectValue("map[key0]", "NOT_NULL", "should not be null"); + + assertEquals(1, errors.getFieldErrorCount("map[key0]")); + assertEquals("NOT_NULL", errors.getFieldError("map[key0]").getCode()); + assertEquals("NOT_NULL.tb.map[key0]", errors.getFieldError("map[key0]").getCodes()[0]); + assertEquals("NOT_NULL.tb.map", errors.getFieldError("map[key0]").getCodes()[1]); + assertEquals("NOT_NULL.map[key0]", errors.getFieldError("map[key0]").getCodes()[2]); + assertEquals("NOT_NULL.map", errors.getFieldError("map[key0]").getCodes()[3]); + // This next code is only generated because of the registered editor, using the + // registered type of the editor as guess for the content type of the collection. + assertEquals("NOT_NULL.org.springframework.beans.TestBean", errors.getFieldError("map[key0]").getCodes()[4]); + assertEquals("NOT_NULL", errors.getFieldError("map[key0]").getCodes()[5]); + } + + public void testDirectBindingToEmptyIndexedFieldWithRegisteredGenericEditor() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(TestBean.class, "map", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + DerivedTestBean tb = new DerivedTestBean(); + tb.setName("array" + text); + setValue(tb); + } + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + Errors errors = binder.getBindingResult(); + errors.rejectValue("map[key0]", "NOT_NULL", "should not be null"); + + assertEquals(1, errors.getFieldErrorCount("map[key0]")); + assertEquals("NOT_NULL", errors.getFieldError("map[key0]").getCode()); + assertEquals("NOT_NULL.tb.map[key0]", errors.getFieldError("map[key0]").getCodes()[0]); + assertEquals("NOT_NULL.tb.map", errors.getFieldError("map[key0]").getCodes()[1]); + assertEquals("NOT_NULL.map[key0]", errors.getFieldError("map[key0]").getCodes()[2]); + assertEquals("NOT_NULL.map", errors.getFieldError("map[key0]").getCodes()[3]); + // This next code is only generated because of the registered editor, using the + // registered type of the editor as guess for the content type of the collection. + assertEquals("NOT_NULL.org.springframework.beans.TestBean", errors.getFieldError("map[key0]").getCodes()[4]); + assertEquals("NOT_NULL", errors.getFieldError("map[key0]").getCodes()[5]); + } + + public void testCustomEditorWithSubclass() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(TestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + DerivedTestBean tb = new DerivedTestBean(); + tb.setName("array" + text); + setValue(tb); + } + public String getAsText() { + return ((TestBean) getValue()).getName(); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("array[0]", "a"); + binder.bind(pvs); + Errors errors = binder.getBindingResult(); + errors.rejectValue("array[0]", "NOT_ROD", "are you sure you're not Rod?"); + + assertEquals("arraya", errors.getFieldValue("array[0]")); + assertEquals(1, errors.getFieldErrorCount("array[0]")); + assertEquals("NOT_ROD", errors.getFieldError("array[0]").getCode()); + assertEquals("NOT_ROD.tb.array[0]", errors.getFieldError("array[0]").getCodes()[0]); + assertEquals("NOT_ROD.tb.array", errors.getFieldError("array[0]").getCodes()[1]); + assertEquals("NOT_ROD.array[0]", errors.getFieldError("array[0]").getCodes()[2]); + assertEquals("NOT_ROD.array", errors.getFieldError("array[0]").getCodes()[3]); + assertEquals("NOT_ROD.org.springframework.beans.DerivedTestBean", errors.getFieldError("array[0]").getCodes()[4]); + assertEquals("NOT_ROD", errors.getFieldError("array[0]").getCodes()[5]); + assertEquals("arraya", errors.getFieldValue("array[0]")); + } + + public void testBindToStringArrayWithArrayEditor() { + TestBean tb = new TestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(String[].class, "stringArray", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(StringUtils.delimitedListToStringArray(text, "-")); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("stringArray", "a1-b2"); + binder.bind(pvs); + assertTrue(!binder.getBindingResult().hasErrors()); + assertEquals(2, tb.getStringArray().length); + assertEquals("a1", tb.getStringArray()[0]); + assertEquals("b2", tb.getStringArray()[1]); + } + + public void testBindToStringArrayWithComponentEditor() { + TestBean tb = new TestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + binder.registerCustomEditor(String.class, "stringArray", new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue("X" + text); + } + }); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("stringArray", new String[] {"a1", "b2"}); + binder.bind(pvs); + assertTrue(!binder.getBindingResult().hasErrors()); + assertEquals(2, tb.getStringArray().length); + assertEquals("Xa1", tb.getStringArray()[0]); + assertEquals("Xb2", tb.getStringArray()[1]); + } + + public void testBindingErrors() { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "32x"); + binder.bind(pvs); + Errors errors = binder.getBindingResult(); + FieldError ageError = errors.getFieldError("age"); + assertEquals("typeMismatch", ageError.getCode()); + + ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); + messageSource.setBasename("org.springframework.validation.messages1"); + String msg = messageSource.getMessage(ageError, Locale.getDefault()); + assertEquals("Field age did not have correct type", msg); + + messageSource = new ResourceBundleMessageSource(); + messageSource.setBasename("org.springframework.validation.messages2"); + msg = messageSource.getMessage(ageError, Locale.getDefault()); + assertEquals("Field Age did not have correct type", msg); + + messageSource = new ResourceBundleMessageSource(); + messageSource.setBasename("org.springframework.validation.messages3"); + msg = messageSource.getMessage(ageError, Locale.getDefault()); + assertEquals("Field Person Age did not have correct type", msg); + } + + public void testAddAllErrors() { + TestBean rod = new TestBean(); + DataBinder binder = new DataBinder(rod, "person"); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "32x"); + binder.bind(pvs); + Errors errors = binder.getBindingResult(); + + BeanPropertyBindingResult errors2 = new BeanPropertyBindingResult(rod, "person"); + errors.rejectValue("name", "badName"); + errors.addAllErrors(errors2); + + FieldError ageError = errors.getFieldError("age"); + assertEquals("typeMismatch", ageError.getCode()); + FieldError nameError = errors.getFieldError("name"); + assertEquals("badName", nameError.getCode()); + } + + public void testBindingWithResortedList() { + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new DataBinder(tb, "tb"); + MutablePropertyValues pvs = new MutablePropertyValues(); + TestBean tb1 = new TestBean("tb1", 99); + TestBean tb2 = new TestBean("tb2", 99); + pvs.addPropertyValue("list[0]", tb1); + pvs.addPropertyValue("list[1]", tb2); + binder.bind(pvs); + assertEquals(tb1.getName(), binder.getBindingResult().getFieldValue("list[0].name")); + assertEquals(tb2.getName(), binder.getBindingResult().getFieldValue("list[1].name")); + tb.getList().set(0, tb2); + tb.getList().set(1, tb1); + assertEquals(tb2.getName(), binder.getBindingResult().getFieldValue("list[0].name")); + assertEquals(tb1.getName(), binder.getBindingResult().getFieldValue("list[1].name")); + } + + public void testRejectWithoutDefaultMessage() throws Exception { + TestBean tb = new TestBean(); + tb.setName("myName"); + tb.setAge(99); + + BeanPropertyBindingResult ex = new BeanPropertyBindingResult(tb, "tb"); + ex.reject("invalid"); + ex.rejectValue("age", "invalidField"); + + StaticMessageSource ms = new StaticMessageSource(); + ms.addMessage("invalid", Locale.US, "general error"); + ms.addMessage("invalidField", Locale.US, "invalid field"); + + assertEquals("general error", ms.getMessage(ex.getGlobalError(), Locale.US)); + assertEquals("invalid field", ms.getMessage(ex.getFieldError("age"), Locale.US)); + } + + public void testBindExceptionSerializable() throws Exception { + SerializablePerson tb = new SerializablePerson(); + tb.setName("myName"); + tb.setAge(99); + + BindException ex = new BindException(tb, "tb"); + ex.reject("invalid", "someMessage"); + ex.rejectValue("age", "invalidField", "someMessage"); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(ex); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + + BindException ex2 = (BindException) ois.readObject(); + assertTrue(ex2.hasGlobalErrors()); + assertEquals("invalid", ex2.getGlobalError().getCode()); + assertTrue(ex2.hasFieldErrors("age")); + assertEquals("invalidField", ex2.getFieldError("age").getCode()); + assertEquals(new Integer(99), ex2.getFieldValue("age")); + + ex2.rejectValue("name", "invalidField", "someMessage"); + assertTrue(ex2.hasFieldErrors("name")); + assertEquals("invalidField", ex2.getFieldError("name").getCode()); + assertEquals("myName", ex2.getFieldValue("name")); + } + + public void testTrackDisallowedFields() throws Exception { + TestBean testBean = new TestBean(); + DataBinder binder = new DataBinder(testBean, "testBean"); + binder.setAllowedFields(new String[] {"name", "age"}); + + String name = "Rob Harrop"; + String beanName = "foobar"; + + MutablePropertyValues mpvs = new MutablePropertyValues(); + mpvs.addPropertyValue("name", name); + mpvs.addPropertyValue("beanName", beanName); + + binder.bind(mpvs); + + assertEquals(name, testBean.getName()); + String[] disallowedFields = binder.getBindingResult().getSuppressedFields(); + assertEquals(1, disallowedFields.length); + assertEquals("beanName", disallowedFields[0]); + } + + + private static class TestBeanValidator implements Validator { + + public boolean supports(Class clazz) { + return TestBean.class.isAssignableFrom(clazz); + } + + public void validate(Object obj, Errors errors) { + TestBean tb = (TestBean) obj; + if (tb.getAge() < 32) { + errors.rejectValue("age", "TOO_YOUNG", "simply too young"); + } + if (tb.getAge() % 2 == 0) { + errors.rejectValue("age", "AGE_NOT_ODD", "your age isn't odd"); + } + if (tb.getName() == null || !tb.getName().equals("Rod")) { + errors.rejectValue("name", "NOT_ROD", "are you sure you're not Rod?"); + } + if (tb.getTouchy() == null || !tb.getTouchy().equals(tb.getName())) { + errors.reject("NAME_TOUCHY_MISMATCH", "name and touchy do not match"); + } + if (tb.getAge() == 0) { + errors.reject("GENERAL_ERROR", new String[] {"arg"}, "msg"); + } + } + } + + + private static class SpouseValidator implements Validator { + + public boolean supports(Class clazz) { + return TestBean.class.isAssignableFrom(clazz); + } + + public void validate(Object obj, Errors errors) { + TestBean tb = (TestBean) obj; + if (tb == null || "XXX".equals(tb.getName())) { + errors.rejectValue("", "SPOUSE_NOT_AVAILABLE"); + return; + } + if (tb.getAge() < 32) { + errors.rejectValue("age", "TOO_YOUNG", "simply too young"); + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/validation/ValidationUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/validation/ValidationUtilsTests.java new file mode 100644 index 00000000000..83ad9cb58e5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/validation/ValidationUtilsTests.java @@ -0,0 +1,181 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.test.AssertThrows; + +/** + * @author Juergen Hoeller + * @author Rick Evans + * @since 08.10.2004 + */ +public class ValidationUtilsTests extends TestCase { + + public void testInvokeValidatorWithNullValidator() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TestBean tb = new TestBean(); + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + ValidationUtils.invokeValidator(null, tb, errors); + } + }.runTest(); + } + + public void testInvokeValidatorWithNullErrors() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + TestBean tb = new TestBean(); + ValidationUtils.invokeValidator(new EmptyValidator(), tb, null); + } + }.runTest(); + } + + public void testInvokeValidatorSunnyDay() throws Exception { + TestBean tb = new TestBean(); + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + ValidationUtils.invokeValidator(new EmptyValidator(), tb, errors); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY", errors.getFieldError("name").getCode()); + } + + public void testValidationUtilsSunnyDay() throws Exception { + TestBean tb = new TestBean(""); + + Validator testValidator = new EmptyValidator(); + tb.setName(" "); + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + testValidator.validate(tb, errors); + assertFalse(errors.hasFieldErrors("name")); + + tb.setName("Roddy"); + errors = new BeanPropertyBindingResult(tb, "tb"); + testValidator.validate(tb, errors); + assertFalse(errors.hasFieldErrors("name")); + } + + public void testValidationUtilsNull() throws Exception { + TestBean tb = new TestBean(); + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + Validator testValidator = new EmptyValidator(); + testValidator.validate(tb, errors); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY", errors.getFieldError("name").getCode()); + } + + public void testValidationUtilsEmpty() throws Exception { + TestBean tb = new TestBean(""); + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + Validator testValidator = new EmptyValidator(); + testValidator.validate(tb, errors); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY", errors.getFieldError("name").getCode()); + } + + public void testValidationUtilsEmptyVariants() { + TestBean tb = new TestBean(); + + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + ValidationUtils.rejectIfEmpty(errors, "name", "EMPTY_OR_WHITESPACE", new Object[] {"arg"}); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY_OR_WHITESPACE", errors.getFieldError("name").getCode()); + assertEquals("arg", errors.getFieldError("name").getArguments()[0]); + + errors = new BeanPropertyBindingResult(tb, "tb"); + ValidationUtils.rejectIfEmpty(errors, "name", "EMPTY_OR_WHITESPACE", new Object[] {"arg"}, "msg"); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY_OR_WHITESPACE", errors.getFieldError("name").getCode()); + assertEquals("arg", errors.getFieldError("name").getArguments()[0]); + assertEquals("msg", errors.getFieldError("name").getDefaultMessage()); + } + + public void testValidationUtilsEmptyOrWhitespace() throws Exception { + TestBean tb = new TestBean(); + Validator testValidator = new EmptyOrWhitespaceValidator(); + + // Test null + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + testValidator.validate(tb, errors); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY_OR_WHITESPACE", errors.getFieldError("name").getCode()); + + // Test empty String + tb.setName(""); + errors = new BeanPropertyBindingResult(tb, "tb"); + testValidator.validate(tb, errors); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY_OR_WHITESPACE", errors.getFieldError("name").getCode()); + + // Test whitespace String + tb.setName(" "); + errors = new BeanPropertyBindingResult(tb, "tb"); + testValidator.validate(tb, errors); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY_OR_WHITESPACE", errors.getFieldError("name").getCode()); + + // Test OK + tb.setName("Roddy"); + errors = new BeanPropertyBindingResult(tb, "tb"); + testValidator.validate(tb, errors); + assertFalse(errors.hasFieldErrors("name")); + } + + public void testValidationUtilsEmptyOrWhitespaceVariants() { + TestBean tb = new TestBean(); + tb.setName(" "); + + Errors errors = new BeanPropertyBindingResult(tb, "tb"); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "EMPTY_OR_WHITESPACE", new Object[] {"arg"}); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY_OR_WHITESPACE", errors.getFieldError("name").getCode()); + assertEquals("arg", errors.getFieldError("name").getArguments()[0]); + + errors = new BeanPropertyBindingResult(tb, "tb"); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "EMPTY_OR_WHITESPACE", new Object[] {"arg"}, "msg"); + assertTrue(errors.hasFieldErrors("name")); + assertEquals("EMPTY_OR_WHITESPACE", errors.getFieldError("name").getCode()); + assertEquals("arg", errors.getFieldError("name").getArguments()[0]); + assertEquals("msg", errors.getFieldError("name").getDefaultMessage()); + } + + + private static class EmptyValidator implements Validator { + + public boolean supports(Class clazz) { + return TestBean.class.isAssignableFrom(clazz); + } + + public void validate(Object obj, Errors errors) { + ValidationUtils.rejectIfEmpty(errors, "name", "EMPTY", "You must enter a name!"); + } + } + + + private static class EmptyOrWhitespaceValidator implements Validator { + + public boolean supports(Class clazz) { + return TestBean.class.isAssignableFrom(clazz); + } + + public void validate(Object obj, Errors errors) { + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "EMPTY_OR_WHITESPACE", "You must enter a name!"); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/validation/messages1.properties b/org.springframework.testsuite/src/test/java/org/springframework/validation/messages1.properties new file mode 100644 index 00000000000..2b2adb247a7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/validation/messages1.properties @@ -0,0 +1 @@ +typeMismatch=Field {0} did not have correct type diff --git a/org.springframework.testsuite/src/test/java/org/springframework/validation/messages2.properties b/org.springframework.testsuite/src/test/java/org/springframework/validation/messages2.properties new file mode 100644 index 00000000000..69f01910567 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/validation/messages2.properties @@ -0,0 +1,2 @@ +typeMismatch=Field {0} did not have correct type +age=Age diff --git a/org.springframework.testsuite/src/test/java/org/springframework/validation/messages3.properties b/org.springframework.testsuite/src/test/java/org/springframework/validation/messages3.properties new file mode 100644 index 00000000000..7b829927974 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/validation/messages3.properties @@ -0,0 +1,2 @@ +typeMismatch=Field {0} did not have correct type +person.age=Person Age diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/bind/EscapedErrorsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/EscapedErrorsTests.java new file mode 100644 index 00000000000..a279ceab4b2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/EscapedErrorsTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; + +/** + * @author Juergen Hoeller + * @since 02.05.2003 + */ +public class EscapedErrorsTests extends TestCase { + + public void testEscapedErrors() { + TestBean tb = new TestBean(); + tb.setName("empty &"); + + Errors errors = new EscapedErrors(new BindException(tb, "tb")); + errors.rejectValue("name", "NAME_EMPTY &", null, "message: &"); + errors.rejectValue("age", "AGE_NOT_SET ", null, "message: "); + errors.rejectValue("age", "AGE_NOT_32 ", null, "message: "); + errors.reject("GENERAL_ERROR \" '", null, "message: \" '"); + + assertTrue("Correct errors flag", errors.hasErrors()); + assertTrue("Correct number of errors", errors.getErrorCount() == 4); + assertTrue("Correct object name", "tb".equals(errors.getObjectName())); + + assertTrue("Correct global errors flag", errors.hasGlobalErrors()); + assertTrue("Correct number of global errors", errors.getGlobalErrorCount() == 1); + ObjectError globalError = errors.getGlobalError(); + assertTrue("Global error message escaped", "message: " '".equals(globalError.getDefaultMessage())); + assertTrue("Global error code not escaped", "GENERAL_ERROR \" '".equals(globalError.getCode())); + ObjectError globalErrorInList = (ObjectError) errors.getGlobalErrors().get(0); + assertTrue("Same global error in list", globalError.getDefaultMessage().equals(globalErrorInList.getDefaultMessage())); + ObjectError globalErrorInAllList = (ObjectError) errors.getAllErrors().get(3); + assertTrue("Same global error in list", globalError.getDefaultMessage().equals(globalErrorInAllList.getDefaultMessage())); + + assertTrue("Correct field errors flag", errors.hasFieldErrors()); + assertTrue("Correct number of field errors", errors.getFieldErrorCount() == 3); + assertTrue("Correct number of field errors in list", errors.getFieldErrors().size() == 3); + FieldError fieldError = errors.getFieldError(); + assertTrue("Field error code not escaped", "NAME_EMPTY &".equals(fieldError.getCode())); + assertTrue("Field value escaped", "empty &".equals(errors.getFieldValue("name"))); + FieldError fieldErrorInList = (FieldError) errors.getFieldErrors().get(0); + assertTrue("Same field error in list", fieldError.getDefaultMessage().equals(fieldErrorInList.getDefaultMessage())); + + assertTrue("Correct name errors flag", errors.hasFieldErrors("name")); + assertTrue("Correct number of name errors", errors.getFieldErrorCount("name") == 1); + assertTrue("Correct number of name errors in list", errors.getFieldErrors("name").size() == 1); + FieldError nameError = errors.getFieldError("name"); + assertTrue("Name error message escaped", "message: &".equals(nameError.getDefaultMessage())); + assertTrue("Name error code not escaped", "NAME_EMPTY &".equals(nameError.getCode())); + assertTrue("Name value escaped", "empty &".equals(errors.getFieldValue("name"))); + FieldError nameErrorInList = (FieldError) errors.getFieldErrors("name").get(0); + assertTrue("Same name error in list", nameError.getDefaultMessage().equals(nameErrorInList.getDefaultMessage())); + + assertTrue("Correct age errors flag", errors.hasFieldErrors("age")); + assertTrue("Correct number of age errors", errors.getFieldErrorCount("age") == 2); + assertTrue("Correct number of age errors in list", errors.getFieldErrors("age").size() == 2); + FieldError ageError = errors.getFieldError("age"); + assertTrue("Age error message escaped", "message: <tag>".equals(ageError.getDefaultMessage())); + assertTrue("Age error code not escaped", "AGE_NOT_SET ".equals(ageError.getCode())); + assertTrue("Age value not escaped", (new Integer(0)).equals(errors.getFieldValue("age"))); + FieldError ageErrorInList = (FieldError) errors.getFieldErrors("age").get(0); + assertTrue("Same name error in list", ageError.getDefaultMessage().equals(ageErrorInList.getDefaultMessage())); + FieldError ageError2 = (FieldError) errors.getFieldErrors("age").get(1); + assertTrue("Age error 2 message escaped", "message: <tag>".equals(ageError2.getDefaultMessage())); + assertTrue("Age error 2 code not escaped", "AGE_NOT_32 ".equals(ageError2.getCode())); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/bind/RequestUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/RequestUtilsTests.java new file mode 100644 index 00000000000..f2569f8bea3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/RequestUtilsTests.java @@ -0,0 +1,413 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * @author Juergen Hoeller + * @since 06.08.2003 + */ +public class RequestUtilsTests extends TestCase { + + public void testRejectMethod() throws ServletRequestBindingException { + String methodGet = "GET"; + String methodPost = "POST"; + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod(methodPost); + + try { + RequestUtils.rejectRequestMethod(request, methodGet); + } catch (ServletException ex) { + fail("Shouldn't have thrown ServletException"); + } + try { + RequestUtils.rejectRequestMethod(request, methodPost); + fail("Should have thrown ServletException"); + } catch (ServletException ex) { + } + } + + public void testIntParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertEquals(RequestUtils.getIntParameter(request, "param1"), new Integer(5)); + assertEquals(RequestUtils.getIntParameter(request, "param1", 6), 5); + assertEquals(RequestUtils.getRequiredIntParameter(request, "param1"), 5); + + assertEquals(RequestUtils.getIntParameter(request, "param2", 6), 6); + try { + RequestUtils.getRequiredIntParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertEquals(RequestUtils.getIntParameter(request, "param3"), null); + assertEquals(RequestUtils.getIntParameter(request, "param3", 6), 6); + try { + RequestUtils.getRequiredIntParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + RequestUtils.getRequiredIntParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testIntParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"1", "2", "3"}); + + request.addParameter("param2", "1"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + int[] array = new int[] { 1, 2, 3 }; + int[] values = RequestUtils.getRequiredIntParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + try { + RequestUtils.getRequiredIntParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + } + + public void testLongParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertEquals(RequestUtils.getLongParameter(request, "param1"), new Long(5L)); + assertEquals(RequestUtils.getLongParameter(request, "param1", 6L), 5L); + assertEquals(RequestUtils.getRequiredIntParameter(request, "param1"), 5L); + + assertEquals(RequestUtils.getLongParameter(request, "param2", 6L), 6L); + try { + RequestUtils.getRequiredLongParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertEquals(RequestUtils.getLongParameter(request, "param3"), null); + assertEquals(RequestUtils.getLongParameter(request, "param3", 6L), 6L); + try { + RequestUtils.getRequiredLongParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + RequestUtils.getRequiredLongParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testLongParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter("param", new String[] {"1", "2", "3"}); + + request.setParameter("param2", "0"); + request.setParameter("param2", "1"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + long[] array = new long[] { 1L, 2L, 3L }; + long[] values = RequestUtils.getRequiredLongParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + try { + RequestUtils.getRequiredLongParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + request.setParameter("param2", new String[] {"1", "2"}); + values = RequestUtils.getRequiredLongParameters(request, "param2"); + assertEquals(2, values.length); + assertEquals(1, values[0]); + assertEquals(2, values[1]); + + request.removeParameter("param2"); + try { + RequestUtils.getRequiredLongParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testFloatParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5.5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertTrue(RequestUtils.getFloatParameter(request, "param1").equals(new Float(5.5f))); + assertTrue(RequestUtils.getFloatParameter(request, "param1", 6.5f) == 5.5f); + assertTrue(RequestUtils.getRequiredFloatParameter(request, "param1") == 5.5f); + + assertTrue(RequestUtils.getFloatParameter(request, "param2", 6.5f) == 6.5f); + try { + RequestUtils.getRequiredFloatParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertTrue(RequestUtils.getFloatParameter(request, "param3") == null); + assertTrue(RequestUtils.getFloatParameter(request, "param3", 6.5f) == 6.5f); + try { + RequestUtils.getRequiredFloatParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + RequestUtils.getRequiredFloatParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testFloatParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"1.5", "2.5", "3"}); + + request.addParameter("param2", "1.5"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + float[] array = new float[] { 1.5F, 2.5F, 3 }; + float[] values = RequestUtils.getRequiredFloatParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i], 0); + } + + try { + RequestUtils.getRequiredFloatParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testDoubleParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5.5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertTrue(RequestUtils.getDoubleParameter(request, "param1").equals(new Double(5.5))); + assertTrue(RequestUtils.getDoubleParameter(request, "param1", 6.5) == 5.5); + assertTrue(RequestUtils.getRequiredDoubleParameter(request, "param1") == 5.5); + + assertTrue(RequestUtils.getDoubleParameter(request, "param2", 6.5) == 6.5); + try { + RequestUtils.getRequiredDoubleParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertTrue(RequestUtils.getDoubleParameter(request, "param3") == null); + assertTrue(RequestUtils.getDoubleParameter(request, "param3", 6.5) == 6.5); + try { + RequestUtils.getRequiredDoubleParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + RequestUtils.getRequiredDoubleParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testDoubleParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"1.5", "2.5", "3"}); + + request.addParameter("param2", "1.5"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + double[] array = new double[] { 1.5, 2.5, 3 }; + double[] values = RequestUtils.getRequiredDoubleParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i], 0); + } + + try { + RequestUtils.getRequiredDoubleParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testBooleanParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "true"); + request.addParameter("param2", "e"); + request.addParameter("param4", "yes"); + request.addParameter("param5", "1"); + request.addParameter("paramEmpty", ""); + + assertTrue(RequestUtils.getBooleanParameter(request, "param1").equals(Boolean.TRUE)); + assertTrue(RequestUtils.getBooleanParameter(request, "param1", false)); + assertTrue(RequestUtils.getRequiredBooleanParameter(request, "param1")); + + assertFalse(RequestUtils.getBooleanParameter(request, "param2", true)); + assertFalse(RequestUtils.getRequiredBooleanParameter(request, "param2")); + + assertTrue(RequestUtils.getBooleanParameter(request, "param3") == null); + assertTrue(RequestUtils.getBooleanParameter(request, "param3", true)); + try { + RequestUtils.getRequiredBooleanParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertTrue(RequestUtils.getBooleanParameter(request, "param4", false)); + assertTrue(RequestUtils.getRequiredBooleanParameter(request, "param4")); + + assertTrue(RequestUtils.getBooleanParameter(request, "param5", false)); + assertTrue(RequestUtils.getRequiredBooleanParameter(request, "param5")); + try { + RequestUtils.getRequiredBooleanParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testBooleanParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"true", "yes", "off", "1", "bogus"}); + + request.addParameter("param2", "false"); + request.addParameter("param2", "true"); + request.addParameter("param2", ""); + + boolean[] array = new boolean[] { true, true, false, true, false }; + boolean[] values = RequestUtils.getRequiredBooleanParameters(request, "param"); + assertEquals(5, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + try { + RequestUtils.getRequiredBooleanParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testStringParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "str"); + request.addParameter("paramEmpty", ""); + + assertEquals(RequestUtils.getStringParameter(request, "param1"), "str"); + assertEquals(RequestUtils.getStringParameter(request, "param1", "string"), "str"); + assertEquals(RequestUtils.getRequiredStringParameter(request, "param1"), "str"); + + assertEquals(RequestUtils.getStringParameter(request, "param3"), null); + assertEquals(RequestUtils.getStringParameter(request, "param3", "string"), "string"); + try { + RequestUtils.getRequiredStringParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + RequestUtils.getStringParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + try { + RequestUtils.getRequiredStringParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestDataBinderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestDataBinderTests.java new file mode 100644 index 00000000000..e347e067257 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestDataBinderTests.java @@ -0,0 +1,161 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind; + +import java.beans.PropertyEditorSupport; +import java.util.Arrays; + +import org.springframework.beans.AbstractPropertyValuesTests; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class ServletRequestDataBinderTests extends AbstractPropertyValuesTests { + + public void testBindingWithNestedObjectCreation() throws Exception { + TestBean tb = new TestBean(); + + ServletRequestDataBinder binder = new ServletRequestDataBinder(tb, "person"); + binder.registerCustomEditor(ITestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean()); + } + }); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("spouse", "someValue"); + request.addParameter("spouse.name", "test"); + binder.bind(request); + + assertNotNull(tb.getSpouse()); + assertEquals("test", tb.getSpouse().getName()); + } + + public void testFieldPrefixCausesFieldReset() throws Exception { + TestBean target = new TestBean(); + ServletRequestDataBinder binder = new ServletRequestDataBinder(target); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("_postProcessed", "visible"); + request.addParameter("postProcessed", "on"); + binder.bind(request); + assertTrue(target.isPostProcessed()); + + request.removeParameter("postProcessed"); + binder.bind(request); + assertFalse(target.isPostProcessed()); + } + + public void testFieldPrefixCausesFieldResetWithIgnoreUnknownFields() throws Exception { + TestBean target = new TestBean(); + ServletRequestDataBinder binder = new ServletRequestDataBinder(target); + binder.setIgnoreUnknownFields(false); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("_postProcessed", "visible"); + request.addParameter("postProcessed", "on"); + binder.bind(request); + assertTrue(target.isPostProcessed()); + + request.removeParameter("postProcessed"); + binder.bind(request); + assertFalse(target.isPostProcessed()); + } + + public void testWithCommaSeparatedStringArray() throws Exception { + TestBean target = new TestBean(); + ServletRequestDataBinder binder = new ServletRequestDataBinder(target); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("stringArray", "bar"); + request.addParameter("stringArray", "abc"); + request.addParameter("stringArray", "123,def"); + binder.bind(request); + assertEquals("Expected all three items to be bound", 3, target.getStringArray().length); + + request.removeParameter("stringArray"); + request.addParameter("stringArray", "123,def"); + binder.bind(request); + assertEquals("Expected only 1 item to be bound", 1, target.getStringArray().length); + } + + public void testBindingWithNestedObjectCreationAndWrongOrder() throws Exception { + TestBean tb = new TestBean(); + + ServletRequestDataBinder binder = new ServletRequestDataBinder(tb, "person"); + binder.registerCustomEditor(ITestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean()); + } + }); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("spouse.name", "test"); + request.addParameter("spouse", "someValue"); + binder.bind(request); + + assertNotNull(tb.getSpouse()); + assertEquals("test", tb.getSpouse().getName()); + } + + public void testNoPrefix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("forname", "Tony"); + request.addParameter("surname", "Blair"); + request.addParameter("age", "" + 50); + + ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request); + doTestTony(pvs); + } + + public void testPrefix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("test_forname", "Tony"); + request.addParameter("test_surname", "Blair"); + request.addParameter("test_age", "" + 50); + + ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request); + assertTrue("Didn't fidn normal when given prefix", !pvs.contains("forname")); + assertTrue("Did treat prefix as normal when not given prefix", pvs.contains("test_forname")); + + pvs = new ServletRequestParameterPropertyValues(request, "test"); + doTestTony(pvs); + } + + public void testNoParameters() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request); + assertTrue("Found no parameters", pvs.getPropertyValues().length == 0); + } + + public void testMultipleValuesForParameter() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + String[] original = new String[] {"Tony", "Rod"}; + request.addParameter("forname", original); + + ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request); + assertTrue("Found 1 parameter", pvs.getPropertyValues().length == 1); + assertTrue("Found array value", pvs.getPropertyValue("forname").getValue() instanceof String[]); + String[] values = (String[]) pvs.getPropertyValue("forname").getValue(); + assertEquals("Correct values", Arrays.asList(values), Arrays.asList(original)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestUtilsTests.java new file mode 100644 index 00000000000..7f18e0ffcf4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/bind/ServletRequestUtilsTests.java @@ -0,0 +1,446 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.util.StopWatch; + +/** + * @author Juergen Hoeller + * @since 06.08.2003 + */ +public class ServletRequestUtilsTests extends TestCase { + + public void testIntParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertEquals(ServletRequestUtils.getIntParameter(request, "param1"), new Integer(5)); + assertEquals(ServletRequestUtils.getIntParameter(request, "param1", 6), 5); + assertEquals(ServletRequestUtils.getRequiredIntParameter(request, "param1"), 5); + + assertEquals(ServletRequestUtils.getIntParameter(request, "param2", 6), 6); + try { + ServletRequestUtils.getRequiredIntParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertEquals(ServletRequestUtils.getIntParameter(request, "param3"), null); + assertEquals(ServletRequestUtils.getIntParameter(request, "param3", 6), 6); + try { + ServletRequestUtils.getRequiredIntParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + ServletRequestUtils.getRequiredIntParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testIntParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"1", "2", "3"}); + + request.addParameter("param2", "1"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + int[] array = new int[] {1, 2, 3}; + int[] values = ServletRequestUtils.getRequiredIntParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + try { + ServletRequestUtils.getRequiredIntParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testLongParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertEquals(ServletRequestUtils.getLongParameter(request, "param1"), new Long(5L)); + assertEquals(ServletRequestUtils.getLongParameter(request, "param1", 6L), 5L); + assertEquals(ServletRequestUtils.getRequiredIntParameter(request, "param1"), 5L); + + assertEquals(ServletRequestUtils.getLongParameter(request, "param2", 6L), 6L); + try { + ServletRequestUtils.getRequiredLongParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertEquals(ServletRequestUtils.getLongParameter(request, "param3"), null); + assertEquals(ServletRequestUtils.getLongParameter(request, "param3", 6L), 6L); + try { + ServletRequestUtils.getRequiredLongParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + ServletRequestUtils.getRequiredLongParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testLongParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter("param", new String[] {"1", "2", "3"}); + + request.setParameter("param2", "0"); + request.setParameter("param2", "1"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + long[] array = new long[] {1L, 2L, 3L}; + long[] values = ServletRequestUtils.getRequiredLongParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + try { + ServletRequestUtils.getRequiredLongParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + request.setParameter("param2", new String[] {"1", "2"}); + values = ServletRequestUtils.getRequiredLongParameters(request, "param2"); + assertEquals(2, values.length); + assertEquals(1, values[0]); + assertEquals(2, values[1]); + + request.removeParameter("param2"); + try { + ServletRequestUtils.getRequiredLongParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testFloatParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5.5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertTrue(ServletRequestUtils.getFloatParameter(request, "param1").equals(new Float(5.5f))); + assertTrue(ServletRequestUtils.getFloatParameter(request, "param1", 6.5f) == 5.5f); + assertTrue(ServletRequestUtils.getRequiredFloatParameter(request, "param1") == 5.5f); + + assertTrue(ServletRequestUtils.getFloatParameter(request, "param2", 6.5f) == 6.5f); + try { + ServletRequestUtils.getRequiredFloatParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertTrue(ServletRequestUtils.getFloatParameter(request, "param3") == null); + assertTrue(ServletRequestUtils.getFloatParameter(request, "param3", 6.5f) == 6.5f); + try { + ServletRequestUtils.getRequiredFloatParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + ServletRequestUtils.getRequiredFloatParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testFloatParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"1.5", "2.5", "3"}); + + request.addParameter("param2", "1.5"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + float[] array = new float[] {1.5F, 2.5F, 3}; + float[] values = ServletRequestUtils.getRequiredFloatParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i], 0); + } + + try { + ServletRequestUtils.getRequiredFloatParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testDoubleParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "5.5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertTrue(ServletRequestUtils.getDoubleParameter(request, "param1").equals(new Double(5.5))); + assertTrue(ServletRequestUtils.getDoubleParameter(request, "param1", 6.5) == 5.5); + assertTrue(ServletRequestUtils.getRequiredDoubleParameter(request, "param1") == 5.5); + + assertTrue(ServletRequestUtils.getDoubleParameter(request, "param2", 6.5) == 6.5); + try { + ServletRequestUtils.getRequiredDoubleParameter(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertTrue(ServletRequestUtils.getDoubleParameter(request, "param3") == null); + assertTrue(ServletRequestUtils.getDoubleParameter(request, "param3", 6.5) == 6.5); + try { + ServletRequestUtils.getRequiredDoubleParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + try { + ServletRequestUtils.getRequiredDoubleParameter(request, "paramEmpty"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testDoubleParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"1.5", "2.5", "3"}); + + request.addParameter("param2", "1.5"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + double[] array = new double[] {1.5, 2.5, 3}; + double[] values = ServletRequestUtils.getRequiredDoubleParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i], 0); + } + + try { + ServletRequestUtils.getRequiredDoubleParameters(request, "param2"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + } + + public void testBooleanParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "true"); + request.addParameter("param2", "e"); + request.addParameter("param4", "yes"); + request.addParameter("param5", "1"); + request.addParameter("paramEmpty", ""); + + assertTrue(ServletRequestUtils.getBooleanParameter(request, "param1").equals(Boolean.TRUE)); + assertTrue(ServletRequestUtils.getBooleanParameter(request, "param1", false)); + assertTrue(ServletRequestUtils.getRequiredBooleanParameter(request, "param1")); + + assertFalse(ServletRequestUtils.getBooleanParameter(request, "param2", true)); + assertFalse(ServletRequestUtils.getRequiredBooleanParameter(request, "param2")); + + assertTrue(ServletRequestUtils.getBooleanParameter(request, "param3") == null); + assertTrue(ServletRequestUtils.getBooleanParameter(request, "param3", true)); + try { + ServletRequestUtils.getRequiredBooleanParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertTrue(ServletRequestUtils.getBooleanParameter(request, "param4", false)); + assertTrue(ServletRequestUtils.getRequiredBooleanParameter(request, "param4")); + + assertTrue(ServletRequestUtils.getBooleanParameter(request, "param5", false)); + assertTrue(ServletRequestUtils.getRequiredBooleanParameter(request, "param5")); + assertFalse(ServletRequestUtils.getRequiredBooleanParameter(request, "paramEmpty")); + } + + public void testBooleanParameters() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param", new String[] {"true", "yes", "off", "1", "bogus"}); + + request.addParameter("param2", "false"); + request.addParameter("param2", "true"); + request.addParameter("param2", ""); + + boolean[] array = new boolean[] {true, true, false, true, false}; + boolean[] values = ServletRequestUtils.getRequiredBooleanParameters(request, "param"); + assertEquals(array.length, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + array = new boolean[] {false, true, false}; + values = ServletRequestUtils.getRequiredBooleanParameters(request, "param2"); + assertEquals(array.length, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + } + + public void testStringParameter() throws ServletRequestBindingException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("param1", "str"); + request.addParameter("paramEmpty", ""); + + assertEquals("str", ServletRequestUtils.getStringParameter(request, "param1")); + assertEquals("str", ServletRequestUtils.getStringParameter(request, "param1", "string")); + assertEquals("str", ServletRequestUtils.getRequiredStringParameter(request, "param1")); + + assertEquals(null, ServletRequestUtils.getStringParameter(request, "param3")); + assertEquals("string", ServletRequestUtils.getStringParameter(request, "param3", "string")); + assertNull(ServletRequestUtils.getStringParameter(request, "param3", null)); + try { + ServletRequestUtils.getRequiredStringParameter(request, "param3"); + fail("Should have thrown ServletRequestBindingException"); + } + catch (ServletRequestBindingException ex) { + // expected + } + + assertEquals("", ServletRequestUtils.getStringParameter(request, "paramEmpty")); + assertEquals("", ServletRequestUtils.getRequiredStringParameter(request, "paramEmpty")); + } + + public void testGetIntParameterWithDefaultValueHandlingIsFastEnough() { + MockHttpServletRequest request = new MockHttpServletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + ServletRequestUtils.getIntParameter(request, "nonExistingParam", 0); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetLongParameterWithDefaultValueHandlingIsFastEnough() { + MockHttpServletRequest request = new MockHttpServletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + ServletRequestUtils.getLongParameter(request, "nonExistingParam", 0); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetFloatParameterWithDefaultValueHandlingIsFastEnough() { + MockHttpServletRequest request = new MockHttpServletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + ServletRequestUtils.getFloatParameter(request, "nonExistingParam", 0f); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetDoubleParameterWithDefaultValueHandlingIsFastEnough() { + MockHttpServletRequest request = new MockHttpServletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + ServletRequestUtils.getDoubleParameter(request, "nonExistingParam", 0d); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetBooleanParameterWithDefaultValueHandlingIsFastEnough() { + MockHttpServletRequest request = new MockHttpServletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + ServletRequestUtils.getBooleanParameter(request, "nonExistingParam", false); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetStringParameterWithDefaultValueHandlingIsFastEnough() { + MockHttpServletRequest request = new MockHttpServletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + ServletRequestUtils.getStringParameter(request, "nonExistingParam", "defaultValue"); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/ContextLoaderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ContextLoaderTests.java new file mode 100644 index 00000000000..1eb8fbabf29 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ContextLoaderTests.java @@ -0,0 +1,272 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.http.HttpServlet; + +import junit.framework.TestCase; + +import org.springframework.beans.BeansException; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.LifecycleBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextException; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.SimpleWebApplicationContext; + +/** + * JUnit 3.8 based tests for {@link ContextLoader}, + * {@link ContextLoaderListener}, {@link ContextLoaderServlet}, and related + * classes. + * + * @author Juergen Hoeller + * @author Sam Brannen + * @since 12.08.2003 + */ +public class ContextLoaderTests extends TestCase { + + public void testContextLoaderListenerWithDefaultContext() throws Exception { + MockServletContext sc = new MockServletContext(""); + sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, + "/org/springframework/web/context/WEB-INF/applicationContext.xml " + + "/org/springframework/web/context/WEB-INF/context-addition.xml"); + ServletContextListener listener = new ContextLoaderListener(); + ServletContextEvent event = new ServletContextEvent(sc); + listener.contextInitialized(event); + WebApplicationContext context = (WebApplicationContext) sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + assertTrue("Correct WebApplicationContext exposed in ServletContext", + context instanceof XmlWebApplicationContext); + LifecycleBean lb = (LifecycleBean) context.getBean("lifecycle"); + assertTrue("Has father", context.containsBean("father")); + assertTrue("Has rod", context.containsBean("rod")); + assertTrue("Has kerry", context.containsBean("kerry")); + assertTrue("Not destroyed", !lb.isDestroyed()); + assertFalse(context.containsBean("beans1.bean1")); + assertFalse(context.containsBean("beans1.bean2")); + listener.contextDestroyed(event); + assertTrue("Destroyed", lb.isDestroyed()); + } + + /** + * Addresses the issues raised in SPR-4008: Supply an opportunity to customize + * context before calling refresh in ContextLoaders. + */ + public void testContextLoaderListenerWithCustomizedContextLoader() throws Exception { + final StringBuffer buffer = new StringBuffer(); + final String expectedContents = "customizeContext() was called"; + final MockServletContext sc = new MockServletContext(""); + sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, + "/org/springframework/web/context/WEB-INF/applicationContext.xml"); + final ServletContextListener listener = new ContextLoaderListener() { + protected ContextLoader createContextLoader() { + return new ContextLoader() { + protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) { + assertNotNull("The ServletContext should not be null.", servletContext); + assertEquals("Verifying that we received the expected ServletContext.", sc, servletContext); + assertFalse("The ApplicationContext should not yet have been refreshed.", applicationContext.isActive()); + buffer.append(expectedContents); + } + }; + } + }; + listener.contextInitialized(new ServletContextEvent(sc)); + assertEquals("customizeContext() should have been called.", expectedContents, buffer.toString()); + } + + public void testContextLoaderServletWithDefaultContext() throws Exception { + MockServletContext sc = new MockServletContext(""); + sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, + "/org/springframework/web/context/WEB-INF/applicationContext.xml"); + HttpServlet servlet = new ContextLoaderServlet(); + ServletConfig config = new MockServletConfig(sc, "test"); + servlet.init(config); + WebApplicationContext context = (WebApplicationContext) sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + assertTrue("Correct WebApplicationContext exposed in ServletContext", + context instanceof XmlWebApplicationContext); + LifecycleBean lb = (LifecycleBean) context.getBean("lifecycle"); + assertTrue("Not destroyed", !lb.isDestroyed()); + assertFalse(context.containsBean("beans1.bean1")); + assertFalse(context.containsBean("beans1.bean2")); + servlet.destroy(); + assertTrue("Destroyed", lb.isDestroyed()); + } + + public void testContextLoaderWithDefaultContextAndParent() throws Exception { + MockServletContext sc = new MockServletContext(""); + sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, + "/org/springframework/web/context/WEB-INF/applicationContext.xml " + + "/org/springframework/web/context/WEB-INF/context-addition.xml"); + sc.addInitParameter(ContextLoader.LOCATOR_FACTORY_SELECTOR_PARAM, + "classpath:org/springframework/beans/factory/access/ref1.xml"); + sc.addInitParameter(ContextLoader.LOCATOR_FACTORY_KEY_PARAM, "a.qualified.name.of.some.sort"); + ServletContextListener listener = new ContextLoaderListener(); + ServletContextEvent event = new ServletContextEvent(sc); + listener.contextInitialized(event); + WebApplicationContext context = (WebApplicationContext) sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + assertTrue("Correct WebApplicationContext exposed in ServletContext", + context instanceof XmlWebApplicationContext); + LifecycleBean lb = (LifecycleBean) context.getBean("lifecycle"); + assertTrue("Has father", context.containsBean("father")); + assertTrue("Has rod", context.containsBean("rod")); + assertTrue("Has kerry", context.containsBean("kerry")); + assertTrue("Not destroyed", !lb.isDestroyed()); + assertTrue(context.containsBean("beans1.bean1")); + assertTrue(context.isTypeMatch("beans1.bean1", org.springframework.beans.factory.access.TestBean.class)); + assertTrue(context.containsBean("beans1.bean2")); + assertTrue(context.isTypeMatch("beans1.bean2", org.springframework.beans.factory.access.TestBean.class)); + listener.contextDestroyed(event); + assertTrue("Destroyed", lb.isDestroyed()); + } + + public void testContextLoaderWithCustomContext() throws Exception { + MockServletContext sc = new MockServletContext(""); + sc.addInitParameter(ContextLoader.CONTEXT_CLASS_PARAM, + "org.springframework.web.servlet.SimpleWebApplicationContext"); + ServletContextListener listener = new ContextLoaderListener(); + ServletContextEvent event = new ServletContextEvent(sc); + listener.contextInitialized(event); + WebApplicationContext wc = (WebApplicationContext) sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + assertTrue("Correct WebApplicationContext exposed in ServletContext", wc instanceof SimpleWebApplicationContext); + } + + public void testContextLoaderWithInvalidLocation() throws Exception { + MockServletContext sc = new MockServletContext(""); + sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, "/WEB-INF/myContext.xml"); + ServletContextListener listener = new ContextLoaderListener(); + ServletContextEvent event = new ServletContextEvent(sc); + try { + listener.contextInitialized(event); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + assertTrue(ex.getCause() instanceof FileNotFoundException); + } + } + + public void testContextLoaderWithInvalidContext() throws Exception { + MockServletContext sc = new MockServletContext(""); + sc.addInitParameter(ContextLoader.CONTEXT_CLASS_PARAM, + "org.springframework.web.context.support.InvalidWebApplicationContext"); + ServletContextListener listener = new ContextLoaderListener(); + ServletContextEvent event = new ServletContextEvent(sc); + try { + listener.contextInitialized(event); + fail("Should have thrown ApplicationContextException"); + } + catch (ApplicationContextException ex) { + // expected + assertTrue(ex.getCause() instanceof ClassNotFoundException); + } + } + + public void testContextLoaderWithDefaultLocation() throws Exception { + MockServletContext sc = new MockServletContext(""); + ServletContextListener listener = new ContextLoaderListener(); + ServletContextEvent event = new ServletContextEvent(sc); + try { + listener.contextInitialized(event); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + assertTrue(ex.getCause() instanceof IOException); + assertTrue(ex.getCause().getMessage().indexOf("/WEB-INF/applicationContext.xml") != -1); + } + } + + public void testFrameworkServletWithDefaultLocation() throws Exception { + DispatcherServlet servlet = new DispatcherServlet(); + servlet.setContextClass(XmlWebApplicationContext.class); + try { + servlet.init(new MockServletConfig(new MockServletContext(""), "test")); + fail("Should have thrown BeanDefinitionStoreException"); + } + catch (BeanDefinitionStoreException ex) { + // expected + assertTrue(ex.getCause() instanceof IOException); + assertTrue(ex.getCause().getMessage().indexOf("/WEB-INF/test-servlet.xml") != -1); + } + } + + public void testFrameworkServletWithCustomLocation() throws Exception { + DispatcherServlet servlet = new DispatcherServlet(); + servlet.setContextConfigLocation("/org/springframework/web/context/WEB-INF/testNamespace.xml " + + "/org/springframework/web/context/WEB-INF/context-addition.xml"); + servlet.init(new MockServletConfig(new MockServletContext(""), "test")); + assertTrue(servlet.getWebApplicationContext().containsBean("kerry")); + assertTrue(servlet.getWebApplicationContext().containsBean("kerryX")); + } + + public void testClassPathXmlApplicationContext() throws IOException { + ApplicationContext context = new ClassPathXmlApplicationContext( + "/org/springframework/web/context/WEB-INF/applicationContext.xml"); + assertTrue("Has father", context.containsBean("father")); + assertTrue("Has rod", context.containsBean("rod")); + assertFalse("Hasn't kerry", context.containsBean("kerry")); + assertTrue("Doesn't have spouse", ((TestBean) context.getBean("rod")).getSpouse() == null); + assertTrue("myinit not evaluated", "Roderick".equals(((TestBean) context.getBean("rod")).getName())); + + context = new ClassPathXmlApplicationContext(new String[] { + "/org/springframework/web/context/WEB-INF/applicationContext.xml", + "/org/springframework/web/context/WEB-INF/context-addition.xml" }); + assertTrue("Has father", context.containsBean("father")); + assertTrue("Has rod", context.containsBean("rod")); + assertTrue("Has kerry", context.containsBean("kerry")); + } + + public void testSingletonDestructionOnStartupFailure() throws IOException { + try { + new ClassPathXmlApplicationContext(new String[] { + "/org/springframework/web/context/WEB-INF/applicationContext.xml", + "/org/springframework/web/context/WEB-INF/fail.xml" }) { + + public void refresh() throws BeansException { + try { + super.refresh(); + } + catch (BeanCreationException ex) { + DefaultListableBeanFactory factory = (DefaultListableBeanFactory) getBeanFactory(); + assertEquals(0, factory.getSingletonCount()); + throw ex; + } + } + }; + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/ResourceBundleMessageSourceTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ResourceBundleMessageSourceTests.java new file mode 100644 index 00000000000..f231c749219 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ResourceBundleMessageSourceTests.java @@ -0,0 +1,279 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import java.util.Date; +import java.util.Locale; + +import org.springframework.context.AbstractApplicationContextTests; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.support.AbstractMessageSource; +import org.springframework.mock.web.MockServletContext; +import org.springframework.ui.context.Theme; +import org.springframework.ui.context.ThemeSource; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.theme.AbstractThemeResolver; + +/** + * Creates a WebApplicationContext that points to a "web.xml" file that + * contains the entry for what file to use for the applicationContext + * (file "org/springframework/web/context/WEB-INF/applicationContext.xml"). + * That file then has an entry for a bean called "messageSource". + * Whatever the basename property is set to for this bean is what the name of + * a properties file in the classpath must be (in our case the name is + * "messages" - note no package names). + * Thus the catalog filename will be in the root of where the classes are compiled + * to and will be called "messages_XX_YY.properties" where "XX" and "YY" are the + * language and country codes known by the ResourceBundle class. + * + *

NOTE: The main method of this class is the "createWebApplicationContext(...)" method, + * and it was copied from org.springframework.web.context.XmlWebApplicationContextTests. + * + * @author Rod Johnson + * @author Jean-Pierre Pawlak + */ +public class ResourceBundleMessageSourceTests extends AbstractApplicationContextTests { + + /** + * We use ticket WAR root for file structure. + * We don't attempt to read web.xml. + */ + public static final String WAR_ROOT = "/org/springframework/web/context"; + + private ConfigurableWebApplicationContext root; + + private MessageSource themeMsgSource; + + protected ConfigurableApplicationContext createContext() throws Exception { + root = new XmlWebApplicationContext(); + MockServletContext sc = new MockServletContext(); + root.setServletContext(sc); + root.setConfigLocations(new String[] {"/org/springframework/web/context/WEB-INF/applicationContext.xml"}); + root.refresh(); + + ConfigurableWebApplicationContext wac = new XmlWebApplicationContext(); + wac.setParent(root); + wac.setServletContext(sc); + wac.setNamespace("test-servlet"); + wac.setConfigLocations(new String[] {"/org/springframework/web/context/WEB-INF/test-servlet.xml"}); + wac.refresh(); + + Theme theme = ((ThemeSource) wac).getTheme(AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME); + assertNotNull(theme); + assertTrue("Theme name has to be the default theme name", AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME.equals(theme.getName())); + themeMsgSource = theme.getMessageSource(); + assertNotNull(themeMsgSource); + return wac; + } + + public void testCount() { + assertTrue("should have 14 beans, not " + + this.applicationContext.getBeanDefinitionCount(), + this.applicationContext.getBeanDefinitionCount() == 14); + } + + /** + * Overridden as we can't trust superclass method. + * @see org.springframework.context.AbstractApplicationContextTests#testEvents() + */ + public void testEvents() throws Exception { + // Do nothing + } + + public void testRootMessageSourceWithUseCodeAsDefaultMessage() throws NoSuchMessageException { + AbstractMessageSource messageSource = (AbstractMessageSource) root.getBean("messageSource"); + messageSource.setUseCodeAsDefaultMessage(true); + + assertEquals("message1", applicationContext.getMessage("code1", null, Locale.getDefault())); + assertEquals("message2", applicationContext.getMessage("code2", null, Locale.getDefault())); + + try { + applicationContext.getMessage("code0", null, Locale.getDefault()); + fail("looking for code0 should throw a NoSuchMessageException"); + } + catch (NoSuchMessageException ex) { + // that's how it should be + } + } + + /** + * @see org.springframework.context.support.AbstractMessageSource for more details. + * NOTE: Messages are contained within the "test/org/springframework/web/context/WEB-INF/messagesXXX.properties" files. + */ + public void testGetMessageWithDefaultPassedInAndFoundInMsgCatalog() { + assertTrue("valid msg from resourcebundle with default msg passed in returned default msg. Expected msg from catalog.", + getApplicationContext().getMessage("message.format.example2", null, "This is a default msg if not found in msg.cat.", Locale.US + ) + .equals("This is a test message in the message catalog with no args.")); + // getApplicationContext().getTheme("theme").getMessageSource().getMessage() + } + + /** + * @see org.springframework.context.support.AbstractMessageSource for more details. + * NOTE: Messages are contained within the "test/org/springframework/web/context/WEB-INF/messagesXXX.properties" files. + */ + public void testGetMessageWithDefaultPassedInAndNotFoundInMsgCatalog() { + assertTrue("bogus msg from resourcebundle with default msg passed in returned default msg", + getApplicationContext().getMessage("bogus.message", null, "This is a default msg if not found in msg.cat.", Locale.UK + ) + .equals("This is a default msg if not found in msg.cat.")); + } + + /** + * The underlying implementation uses a hashMap to cache messageFormats + * once a message has been asked for. This test is an attempt to + * make sure the cache is being used properly. + * NOTE: Messages are contained within the "test/org/springframework/web/context/WEB-INF/messagesXXX.properties" files. + * @see org.springframework.context.support.AbstractMessageSource for more details. + */ + public void testGetMessageWithMessageAlreadyLookedFor() throws Exception { + Object[] arguments = { + new Integer(7), new Date(System.currentTimeMillis()), + "a disturbance in the Force" + }; + + // The first time searching, we don't care about for this test + getApplicationContext().getMessage("message.format.example1", arguments, Locale.US); + + // Now msg better be as expected + assertTrue("2nd search within MsgFormat cache returned expected message for Locale.US", + getApplicationContext().getMessage("message.format.example1", arguments, Locale.US + ) + .indexOf("there was \"a disturbance in the Force\" on planet 7.") != -1); + + Object[] newArguments = { + new Integer(8), new Date(System.currentTimeMillis()), + "a disturbance in the Force" + }; + + // Now msg better be as expected even with different args + assertTrue("2nd search within MsgFormat cache with different args returned expected message for Locale.US", + getApplicationContext().getMessage("message.format.example1", newArguments, Locale.US + ) + .indexOf("there was \"a disturbance in the Force\" on planet 8.") != -1); + } + + /** + * @see org.springframework.context.support.AbstractMessageSource for more details. + * NOTE: Messages are contained within the "test/org/springframework/web/context/WEB-INF/messagesXXX.properties" files. + * Example taken from the javadocs for the java.text.MessageFormat class + */ + public void testGetMessageWithNoDefaultPassedInAndFoundInMsgCatalog() throws Exception { + Object[] arguments = { + new Integer(7), new Date(System.currentTimeMillis()), + "a disturbance in the Force" + }; + + /* + Try with Locale.US + Since the msg has a time value in it, we will use String.indexOf(...) + to just look for a substring without the time. This is because it is + possible that by the time we store a time variable in this method + and the time the ResourceBundleMessageSource resolves the msg the + minutes of the time might not be the same. + */ + assertTrue("msg from resourcebundle for Locale.US substituting args for placeholders is as expected", + getApplicationContext().getMessage("message.format.example1", arguments, Locale.US + ) + .indexOf("there was \"a disturbance in the Force\" on planet 7.") != -1); + + // Try with Locale.UK + assertTrue("msg from resourcebundle for Locale.UK substituting args for placeholders is as expected", + getApplicationContext().getMessage("message.format.example1", arguments, Locale.UK + ) + .indexOf("there was \"a disturbance in the Force\" on station number 7.") != -1); + + // Try with Locale.US - different test msg that requires no args + assertTrue("msg from resourcebundle that requires no args for Locale.US is as expected", + getApplicationContext().getMessage("message.format.example2", null, Locale.US) + .equals("This is a test message in the message catalog with no args.")); + } + + /** + * @see org.springframework.context.support.AbstractMessageSource for more details. + * NOTE: Messages are contained within the "test/org/springframework/web/context/WEB-INF/messagesXXX.properties" files. + */ + public void testGetMessageWithNoDefaultPassedInAndNotFoundInMsgCatalog() { + // Expecting an exception + try { + getApplicationContext().getMessage("bogus.message", null, Locale.UK); + fail("bogus msg from resourcebundle without default msg should have thrown exception"); + } + catch (NoSuchMessageException tExcept) { + assertTrue("bogus msg from resourcebundle without default msg threw expected exception", + true); + } + } + + public void testGetMultipleBasenamesForMessageSource() throws NoSuchMessageException { + assertEquals("message1", getApplicationContext().getMessage("code1", null, Locale.UK)); + assertEquals("message2", getApplicationContext().getMessage("code2", null, Locale.UK)); + assertEquals("message3", getApplicationContext().getMessage("code3", null, Locale.UK)); + } + + /** + * @see org.springframework.context.support.AbstractMessageSource for more details. + * NOTE: Messages are contained within the "test/org/springframework/web/context/WEB-INF/themeXXX.properties" files. + */ + public void testGetMessageWithDefaultPassedInAndFoundInThemeCatalog() { + // Try with Locale.US + String msg = getThemeMessage("theme.example1", null, "This is a default theme msg if not found in theme cat.", Locale.US); + assertTrue("valid msg from theme resourcebundle with default msg passed in returned default msg. Expected msg from catalog. Received: " + msg, + msg.equals("This is a test message in the theme message catalog.")); + // Try with Locale.UK + msg = getThemeMessage("theme.example1", null, "This is a default theme msg if not found in theme cat.", Locale.UK); + assertTrue("valid msg from theme resourcebundle with default msg passed in returned default msg. Expected msg from catalog.", + msg.equals("This is a test message in the theme message catalog with no args.")); + } + + /** + * @see org.springframework.context.support.AbstractMessageSource for more details. + * NOTE: Messages are contained within the "test/org/springframework/web/context/WEB-INF/themeXXX.properties" files. + */ + public void testGetMessageWithDefaultPassedInAndNotFoundInThemeCatalog() { + assertTrue("bogus msg from theme resourcebundle with default msg passed in returned default msg", + getThemeMessage("bogus.message", null, "This is a default msg if not found in theme cat.", Locale.UK + ) + .equals("This is a default msg if not found in theme cat.")); + } + + public void testThemeSourceNesting() throws NoSuchMessageException { + String overriddenMsg = getThemeMessage("theme.example2", null, null, Locale.UK); + MessageSource ms = ((ThemeSource) root).getTheme(AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME).getMessageSource(); + String originalMsg = ms.getMessage("theme.example2", null, Locale.UK); + assertTrue("correct overridden msg", "test-message2".equals(overriddenMsg)); + assertTrue("correct original msg", "message2".equals(originalMsg)); + } + + public void testThemeSourceNestingWithParentDefault() throws NoSuchMessageException { + StaticWebApplicationContext leaf = new StaticWebApplicationContext(); + leaf.setParent(getApplicationContext()); + leaf.refresh(); + assertNotNull("theme still found", leaf.getTheme("theme")); + MessageSource ms = leaf.getTheme("theme").getMessageSource(); + String msg = ms.getMessage("theme.example2", null, null, Locale.UK); + assertEquals("correct overridden msg", "test-message2", msg); + } + + private String getThemeMessage(String code, Object args[], String defaultMessage, Locale locale) { + return themeMsgSource.getMessage(code, args, defaultMessage, locale); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletConfigAwareBean.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletConfigAwareBean.java new file mode 100644 index 00000000000..5dfa1a7bacb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletConfigAwareBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import javax.servlet.ServletConfig; + +/** + * @author Juergen Hoeller + */ +public class ServletConfigAwareBean implements ServletConfigAware { + + private ServletConfig servletConfig; + + public void setServletConfig(ServletConfig servletConfig) { + this.servletConfig = servletConfig; + } + + public ServletConfig getServletConfig() { + return servletConfig; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareBean.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareBean.java new file mode 100644 index 00000000000..ecaaae502bc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import javax.servlet.ServletContext; + +/** + * @author Juergen Hoeller + */ +public class ServletContextAwareBean implements ServletContextAware { + + private ServletContext servletContext; + + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public ServletContext getServletContext() { + return servletContext; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareProcessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareProcessorTests.java new file mode 100644 index 00000000000..3b68b7508ea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/ServletContextAwareProcessorTests.java @@ -0,0 +1,156 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.ServletContextAwareProcessor; + +/** + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class ServletContextAwareProcessorTests extends TestCase { + + public void testServletContextAwareWithServletContext() { + ServletContext servletContext = new MockServletContext(); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext); + ServletContextAwareBean bean = new ServletContextAwareBean(); + assertNull(bean.getServletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletContext should have been set", bean.getServletContext()); + assertEquals(servletContext, bean.getServletContext()); + } + + public void testServletContextAwareWithServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletConfig servletConfig = new MockServletConfig(servletContext); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletConfig); + ServletContextAwareBean bean = new ServletContextAwareBean(); + assertNull(bean.getServletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletContext should have been set", bean.getServletContext()); + assertEquals(servletContext, bean.getServletContext()); + } + + public void testServletContextAwareWithServletContextAndServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletConfig servletConfig = new MockServletConfig(servletContext); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext, servletConfig); + ServletContextAwareBean bean = new ServletContextAwareBean(); + assertNull(bean.getServletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletContext should have been set", bean.getServletContext()); + assertEquals(servletContext, bean.getServletContext()); + } + + public void testServletContextAwareWithNullServletContextAndNonNullServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletConfig servletConfig = new MockServletConfig(servletContext); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(null, servletConfig); + ServletContextAwareBean bean = new ServletContextAwareBean(); + assertNull(bean.getServletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletContext should have been set", bean.getServletContext()); + assertEquals(servletContext, bean.getServletContext()); + } + + public void testServletContextAwareWithNonNullServletContextAndNullServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext, null); + ServletContextAwareBean bean = new ServletContextAwareBean(); + assertNull(bean.getServletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletContext should have been set", bean.getServletContext()); + assertEquals(servletContext, bean.getServletContext()); + } + + public void testServletContextAwareWithNullServletContext() { + ServletContext servletContext = null; + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext); + ServletContextAwareBean bean = new ServletContextAwareBean(); + assertNull(bean.getServletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getServletContext()); + } + + public void testServletConfigAwareWithServletContextOnly() { + ServletContext servletContext = new MockServletContext(); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext); + ServletConfigAwareBean bean = new ServletConfigAwareBean(); + assertNull(bean.getServletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getServletConfig()); + } + + public void testServletConfigAwareWithServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletConfig servletConfig = new MockServletConfig(servletContext); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletConfig); + ServletConfigAwareBean bean = new ServletConfigAwareBean(); + assertNull(bean.getServletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletConfig should have been set", bean.getServletConfig()); + assertEquals(servletConfig, bean.getServletConfig()); + } + + public void testServletConfigAwareWithServletContextAndServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletConfig servletConfig = new MockServletConfig(servletContext); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext, servletConfig); + ServletConfigAwareBean bean = new ServletConfigAwareBean(); + assertNull(bean.getServletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletConfig should have been set", bean.getServletConfig()); + assertEquals(servletConfig, bean.getServletConfig()); + } + + public void testServletConfigAwareWithNullServletContextAndNonNullServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletConfig servletConfig = new MockServletConfig(servletContext); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(null, servletConfig); + ServletConfigAwareBean bean = new ServletConfigAwareBean(); + assertNull(bean.getServletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("ServletConfig should have been set", bean.getServletConfig()); + assertEquals(servletConfig, bean.getServletConfig()); + } + + public void testServletConfigAwareWithNonNullServletContextAndNullServletConfig() { + ServletContext servletContext = new MockServletContext(); + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext, null); + ServletConfigAwareBean bean = new ServletConfigAwareBean(); + assertNull(bean.getServletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getServletConfig()); + } + + public void testServletConfigAwareWithNullServletContext() { + ServletContext servletContext = null; + ServletContextAwareProcessor processor = new ServletContextAwareProcessor(servletContext); + ServletConfigAwareBean bean = new ServletConfigAwareBean(); + assertNull(bean.getServletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getServletConfig()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/applicationContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/applicationContext.xml new file mode 100644 index 00000000000..105055c2d68 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/applicationContext.xml @@ -0,0 +1,81 @@ + + +]> + + + + + + + + + + + + + + + + + + + + + + + dummy + + + -1 + + + + + + + + + true + + + &contextInclude; + + + + /org/springframework/web/context/WEB-INF/myoverride.properties + + + + + + + classpath:/org/springframework/web/context/WEB-INF/myplace*.properties + classpath:/org/springframework/web/context/WEB-INF/myover*.properties + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-addition.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-addition.xml new file mode 100644 index 00000000000..c888047524d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-addition.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + Roderick + 31 + + + + + + Kerry + 34 + + + + + typeMismatch + 34x + + + + + + + + + false + + + + + listenerVeto + 66 + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages.properties new file mode 100644 index 00000000000..57aa4782a7b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages.properties @@ -0,0 +1,6 @@ +code1=message1 +code2=message2 + +# Example taken from the javadocs for the java.text.MessageFormat class +message.format.example1=At '{1,time}' on "{1,date}", there was "{2}" on planet {0,number,integer}. +message.format.example2=This is a test message in the message catalog with no args. diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_GB.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_GB.properties new file mode 100644 index 00000000000..623a71a8401 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_GB.properties @@ -0,0 +1,2 @@ +# Example taken from the javadocs for the java.text.MessageFormat class +message.format.example1=At '{1,time}' on "{1,date}", there was "{2}" on station number {0,number,integer}. \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_US.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_US.properties new file mode 100644 index 00000000000..2bdc0944860 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/context-messages_en_US.properties @@ -0,0 +1,5 @@ +code1=message1 + +# Example taken from the javadocs for the java.text.MessageFormat class +message.format.example1=At '{1,time}' on "{1,date}", there was "{2}" on planet {0,number,integer}. +message.format.example2=This is a test message in the message catalog with no args. \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/contextInclude.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/contextInclude.xml new file mode 100644 index 00000000000..2e4938383be --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/contextInclude.xml @@ -0,0 +1,6 @@ + + + + yetanotherdummy + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/empty-servlet.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/empty-servlet.xml new file mode 100644 index 00000000000..b49584e11dd --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/empty-servlet.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/fail.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/fail.xml new file mode 100644 index 00000000000..54d05ef2a3b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/fail.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/more-context-messages.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/more-context-messages.properties new file mode 100644 index 00000000000..c703c78757c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/more-context-messages.properties @@ -0,0 +1,2 @@ +code1=message1x +code3=message3 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myoverride.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myoverride.properties new file mode 100644 index 00000000000..62b6240c8ef --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myoverride.properties @@ -0,0 +1,3 @@ +father.name=Albert +rod.age=31 +rod.name=Roderick diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myplaceholder.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myplaceholder.properties new file mode 100644 index 00000000000..1d454bdb1a2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/myplaceholder.properties @@ -0,0 +1,4 @@ +useCodeAsDefaultMessage=false +message-file=context-messages +objectName=test:service=myservice +theme-base=org/springframework/web/context/WEB-INF/ diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/messageSource.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/messageSource.xml new file mode 100644 index 00000000000..a40e827ba9a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/messageSource.xml @@ -0,0 +1,24 @@ + + + + + + + + ${useCodeAsDefaultMessage} + + + + org/springframework/web/context/WEB-INF/${message-file} + org/springframework/web/context/WEB-INF/more-context-messages + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/themeSource.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/themeSource.xml new file mode 100644 index 00000000000..1e7d04517db --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/resources/themeSource.xml @@ -0,0 +1,12 @@ + + + + + + + + ${theme-base} + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/sessionContext.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/sessionContext.xml new file mode 100644 index 00000000000..7da590d1f21 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/sessionContext.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-messages.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-messages.properties new file mode 100644 index 00000000000..98686bf3827 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-messages.properties @@ -0,0 +1 @@ +code2=message2 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-servlet.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-servlet.xml new file mode 100644 index 00000000000..115e118427a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-servlet.xml @@ -0,0 +1,59 @@ + + + + + + + org/springframework/web/context/WEB-INF/test-messages + + + + org/springframework/web/context/WEB-INF/test- + + + + + + + + Rod + 31 + + + + + + + Roderick + 31 + + + + + + Kerry + 34 + + + + + typeMismatch + 34x + + + + + + + + false + + + + listenerVeto + 66 + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-theme.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-theme.properties new file mode 100644 index 00000000000..019517d124f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/test-theme.properties @@ -0,0 +1 @@ +theme.example2=test-message2 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/testNamespace.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/testNamespace.xml new file mode 100644 index 00000000000..dd10e5fcab7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/testNamespace.xml @@ -0,0 +1,17 @@ + + + + + + + Rod + 31 + + + + Kerry + 34 + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme.properties new file mode 100644 index 00000000000..8e5e4c2614d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme.properties @@ -0,0 +1,2 @@ +theme.example1=This is a test message in the theme message catalog with no args. +theme.example2=message2 diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme_en_GB.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme_en_GB.properties new file mode 100644 index 00000000000..e69de29bb2d diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme_en_US.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme_en_US.properties new file mode 100644 index 00000000000..cbe5be548d2 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/theme_en_US.properties @@ -0,0 +1 @@ +theme.example1=This is a test message in the theme message catalog. \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/web.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/web.xml new file mode 100644 index 00000000000..1d412973bea --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/WEB-INF/web.xml @@ -0,0 +1,151 @@ + + + + + ticket-webapp + Web interface for ticket application + + + + + + + + + config + org.springframework.framework.web.context.ContextLoaderServlet + + contextClass + org.springframework.framework.web.context.XMLWebApplicationContext + + + log4jPropertiesUrl + /WEB-INF/log4j_PRODUCTION.properties + + + 1 + + + + + boxOffice + org.springframework.framework.web.workflow.CommandServlet + + + + + + + boxOffice + /*.html + + + + config + /context/context.html + + + + +60 + + + + + /welcome.jsp + + + + 403 + /jsp/layout/twocolumn/403-Forbidden.jsp + + + + 404 + /jsp/layout/twocolumn/404-NotFound.jsp + + + + java.lang.Throwable + /jsp/layout/twocolumn/uncaughtException.jsp + + + + /bind + /WEB-INF/tlds/b11.tld + + + + /events + /WEB-INF/tlds/event11.tld + + + + + SalesInfo + + purchase.html + GET + POST + + + registeredUsers + + + NONE + + + + + + FORM + + + ticket + + + login.jsp + loginError.jsp + + + + + + registeredUsers + + + + + + + ejb/FixtureManager + Session + com.wrox.j2eedd.ticket.ejb.fixturemanager.FixtureManagerRemoteHome + com.wrox.j2eedd.ticket.ejb.fixturemanager.FixtureManagerRemote + FixtureManager + + + + + ejb/BoxOffice + Session + com.wrox.j2eedd.ticket.ejb.booking.BoxOfficeRemoteHome + com.wrox.j2eedd.ticket.ejb.booking.BoxOfficeRemote + BookingManager + + + + ejb/CustomerManager + Session + com.wrox.j2eedd.ticket.ejb.customer.CustomerManagerRemoteHoms + com.wrox.j2eedd.ticket.ejb.customer.CustomerManagerRemote + CustomerManager + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/XmlWebApplicationContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/XmlWebApplicationContextTests.java new file mode 100644 index 00000000000..16270d62a4a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/XmlWebApplicationContextTests.java @@ -0,0 +1,191 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import java.util.Locale; + +import javax.servlet.ServletException; + +import org.springframework.beans.BeansException; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.AbstractApplicationContextTests; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.TestListener; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class XmlWebApplicationContextTests extends AbstractApplicationContextTests { + + private ConfigurableWebApplicationContext root; + + protected ConfigurableApplicationContext createContext() throws Exception { + InitAndIB.constructed = false; + root = new XmlWebApplicationContext(); + MockServletContext sc = new MockServletContext(""); + root.setServletContext(sc); + root.setConfigLocations(new String[] {"/org/springframework/web/context/WEB-INF/applicationContext.xml"}); + root.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() { + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + beanFactory.addBeanPostProcessor(new BeanPostProcessor() { + public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException { + if (bean instanceof TestBean) { + ((TestBean) bean).getFriends().add("myFriend"); + } + return bean; + } + public Object postProcessAfterInitialization(Object bean, String name) throws BeansException { + return bean; + } + }); + } + }); + root.refresh(); + XmlWebApplicationContext wac = new XmlWebApplicationContext(); + wac.setParent(root); + wac.setServletContext(sc); + wac.setNamespace("test-servlet"); + wac.setConfigLocations(new String[] {"/org/springframework/web/context/WEB-INF/test-servlet.xml"}); + wac.refresh(); + return wac; + } + + /** + * Overridden as we can't trust superclass method + * @see org.springframework.context.AbstractApplicationContextTests#testEvents() + */ + public void testEvents() throws Exception { + TestListener listener = (TestListener) this.applicationContext.getBean("testListener"); + listener.zeroCounter(); + TestListener parentListener = (TestListener) this.applicationContext.getParent().getBean("parentListener"); + parentListener.zeroCounter(); + + parentListener.zeroCounter(); + assertTrue("0 events before publication", listener.getEventCount() == 0); + assertTrue("0 parent events before publication", parentListener.getEventCount() == 0); + this.applicationContext.publishEvent(new MyEvent(this)); + assertTrue("1 events after publication, not " + listener.getEventCount(), listener.getEventCount() == 1); + assertTrue("1 parent events after publication", parentListener.getEventCount() == 1); + } + + public void testCount() { + assertTrue("should have 14 beans, not "+ this.applicationContext.getBeanDefinitionCount(), + this.applicationContext.getBeanDefinitionCount() == 14); + } + + public void testWithoutMessageSource() throws Exception { + MockServletContext sc = new MockServletContext(""); + XmlWebApplicationContext wac = new XmlWebApplicationContext(); + wac.setParent(root); + wac.setServletContext(sc); + wac.setNamespace("testNamespace"); + wac.setConfigLocations(new String[] {"/org/springframework/web/context/WEB-INF/test-servlet.xml"}); + wac.refresh(); + try { + wac.getMessage("someMessage", null, Locale.getDefault()); + fail("Should have thrown NoSuchMessageException"); + } + catch (NoSuchMessageException ex) { + // expected; + } + String msg = wac.getMessage("someMessage", null, "default", Locale.getDefault()); + assertTrue("Default message returned", "default".equals(msg)); + } + + public void testContextNesting() { + TestBean father = (TestBean) this.applicationContext.getBean("father"); + assertTrue("Bean from root context", father != null); + assertTrue("Custom BeanPostProcessor applied", father.getFriends().contains("myFriend")); + + TestBean rod = (TestBean) this.applicationContext.getBean("rod"); + assertTrue("Bean from child context", "Rod".equals(rod.getName())); + assertTrue("Bean has external reference", rod.getSpouse() == father); + assertTrue("Custom BeanPostProcessor not applied", !rod.getFriends().contains("myFriend")); + + rod = (TestBean) this.root.getBean("rod"); + assertTrue("Bean from root context", "Roderick".equals(rod.getName())); + assertTrue("Custom BeanPostProcessor applied", rod.getFriends().contains("myFriend")); + } + + public void testInitializingBeanAndInitMethod() throws Exception { + assertFalse(InitAndIB.constructed); + InitAndIB iib = (InitAndIB) this.applicationContext.getBean("init-and-ib"); + assertTrue(InitAndIB.constructed); + assertTrue(iib.afterPropertiesSetInvoked && iib.initMethodInvoked); + assertTrue(!iib.destroyed && !iib.customDestroyed); + this.applicationContext.close(); + assertTrue(!iib.destroyed && !iib.customDestroyed); + ConfigurableApplicationContext parent = (ConfigurableApplicationContext) this.applicationContext.getParent(); + parent.close(); + assertTrue(iib.destroyed && iib.customDestroyed); + parent.close(); + assertTrue(iib.destroyed && iib.customDestroyed); + } + + + public static class InitAndIB implements InitializingBean, DisposableBean { + + public static boolean constructed; + + public boolean afterPropertiesSetInvoked, initMethodInvoked, destroyed, customDestroyed; + + public InitAndIB() { + constructed = true; + } + + public void afterPropertiesSet() { + if (this.initMethodInvoked) + fail(); + this.afterPropertiesSetInvoked = true; + } + + /** Init method */ + public void customInit() throws ServletException { + if (!this.afterPropertiesSetInvoked) + fail(); + this.initMethodInvoked = true; + } + + public void destroy() { + if (this.customDestroyed) + fail(); + if (this.destroyed) { + throw new IllegalStateException("Already destroyed"); + } + this.destroyed = true; + } + + public void customDestroy() { + if (!this.destroyed) + fail(); + if (this.customDestroyed) { + throw new IllegalStateException("Already customDestroyed"); + } + this.customDestroyed = true; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestAndSessionScopedProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestAndSessionScopedProxyTests.java new file mode 100644 index 00000000000..bdd42b60a07 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestAndSessionScopedProxyTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import javax.servlet.http.HttpServletRequest; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.context.support.StaticWebApplicationContext; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class RequestAndSessionScopedProxyTests extends TestCase { + + public void testPutBeanInRequest() throws Exception { + String targetBeanName = "target"; + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.setScope(WebApplicationContext.SCOPE_REQUEST); + bd.getPropertyValues().addPropertyValue("name", "abc"); + wac.registerBeanDefinition(targetBeanName, bd); + wac.refresh(); + + HttpServletRequest request = new MockHttpServletRequest(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + TestBean target = (TestBean) wac.getBean(targetBeanName); + assertEquals("abc", target.getName()); + assertSame(target, request.getAttribute(targetBeanName)); + + TestBean target2 = (TestBean) wac.getBean(targetBeanName); + assertEquals("abc", target2.getName()); + assertSame(target2, target); + assertSame(target2, request.getAttribute(targetBeanName)); + + request = new MockHttpServletRequest(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + TestBean target3 = (TestBean) wac.getBean(targetBeanName); + assertEquals("abc", target3.getName()); + assertSame(target3, request.getAttribute(targetBeanName)); + assertNotSame(target3, target); + + RequestContextHolder.setRequestAttributes(null); + try { + wac.getBean(targetBeanName); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + } + } + + public void testPutBeanInSession() throws Exception { + String targetBeanName = "target"; + HttpServletRequest request = new MockHttpServletRequest(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.setScope(WebApplicationContext.SCOPE_SESSION); + bd.getPropertyValues().addPropertyValue("name", "abc"); + wac.registerBeanDefinition(targetBeanName, bd); + wac.refresh(); + + TestBean target = (TestBean) wac.getBean(targetBeanName); + assertEquals("abc", target.getName()); + assertSame(target, request.getSession().getAttribute(targetBeanName)); + + RequestContextHolder.setRequestAttributes(null); + try { + wac.getBean(targetBeanName); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestContextListenerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestContextListenerTests.java new file mode 100644 index 00000000000..a84c73d83d8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestContextListenerTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import javax.servlet.ServletRequestEvent; + +import junit.framework.TestCase; + +import org.springframework.core.task.MockRunnable; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; + +/** + * @author Juergen Hoeller + */ +public class RequestContextListenerTests extends TestCase { + + public void testRequestContextListenerWithSameThread() { + RequestContextListener listener = new RequestContextListener(); + MockServletContext context = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(context); + request.setAttribute("test", "value"); + + assertNull(RequestContextHolder.getRequestAttributes()); + listener.requestInitialized(new ServletRequestEvent(context, request)); + assertNotNull(RequestContextHolder.getRequestAttributes()); + assertEquals("value", + RequestContextHolder.getRequestAttributes().getAttribute("test", RequestAttributes.SCOPE_REQUEST)); + MockRunnable runnable = new MockRunnable(); + RequestContextHolder.getRequestAttributes().registerDestructionCallback( + "test", runnable, RequestAttributes.SCOPE_REQUEST); + + listener.requestDestroyed(new ServletRequestEvent(context, request)); + assertNull(RequestContextHolder.getRequestAttributes()); + assertTrue(runnable.wasExecuted()); + } + + public void testRequestContextListenerWithSameThreadAndAttributesGone() { + RequestContextListener listener = new RequestContextListener(); + MockServletContext context = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(context); + request.setAttribute("test", "value"); + + assertNull(RequestContextHolder.getRequestAttributes()); + listener.requestInitialized(new ServletRequestEvent(context, request)); + assertNotNull(RequestContextHolder.getRequestAttributes()); + assertEquals("value", + RequestContextHolder.getRequestAttributes().getAttribute("test", RequestAttributes.SCOPE_REQUEST)); + MockRunnable runnable = new MockRunnable(); + RequestContextHolder.getRequestAttributes().registerDestructionCallback( + "test", runnable, RequestAttributes.SCOPE_REQUEST); + + request.clearAttributes(); + listener.requestDestroyed(new ServletRequestEvent(context, request)); + assertNull(RequestContextHolder.getRequestAttributes()); + assertTrue(runnable.wasExecuted()); + } + + public void testRequestContextListenerWithDifferentThread() { + final RequestContextListener listener = new RequestContextListener(); + final MockServletContext context = new MockServletContext(); + final MockHttpServletRequest request = new MockHttpServletRequest(context); + request.setAttribute("test", "value"); + + assertNull(RequestContextHolder.getRequestAttributes()); + listener.requestInitialized(new ServletRequestEvent(context, request)); + assertNotNull(RequestContextHolder.getRequestAttributes()); + assertEquals("value", + RequestContextHolder.getRequestAttributes().getAttribute("test", RequestAttributes.SCOPE_REQUEST)); + MockRunnable runnable = new MockRunnable(); + RequestContextHolder.getRequestAttributes().registerDestructionCallback( + "test", runnable, RequestAttributes.SCOPE_REQUEST); + + // Execute requestDestroyed callback in different thread. + Thread thread = new Thread() { + public void run() { + listener.requestDestroyed(new ServletRequestEvent(context, request)); + } + }; + thread.start(); + try { + thread.join(); + } + catch (InterruptedException ex) { + } + // Still bound to original thread, but at least completed. + assertNotNull(RequestContextHolder.getRequestAttributes()); + assertTrue(runnable.wasExecuted()); + + // Check that a repeated execution in the same thread works and performs cleanup. + listener.requestInitialized(new ServletRequestEvent(context, request)); + listener.requestDestroyed(new ServletRequestEvent(context, request)); + assertNull(RequestContextHolder.getRequestAttributes()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopeTests.java new file mode 100644 index 00000000000..ecf5b153ff1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopeTests.java @@ -0,0 +1,172 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import junit.framework.TestCase; + +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanCurrentlyInCreationException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + * @author Mark Fisher + * @since 2.0 + */ +public class RequestScopeTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new DefaultListableBeanFactory(); + this.beanFactory.registerScope("request", new RequestScope()); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.loadBeanDefinitions(new ClassPathResource("requestScopeTests.xml", getClass())); + this.beanFactory.preInstantiateSingletons(); + } + + public void testGetFromScope() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + String name = "requestScopedObject"; + assertNull(request.getAttribute(name)); + TestBean bean = (TestBean) this.beanFactory.getBean(name); + assertSame(bean, request.getAttribute(name)); + assertSame(bean, this.beanFactory.getBean(name)); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testDestructionAtRequestCompletion() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + String name = "requestScopedDisposableObject"; + assertNull(request.getAttribute(name)); + DerivedTestBean bean = (DerivedTestBean) this.beanFactory.getBean(name); + assertSame(bean, request.getAttribute(name)); + assertSame(bean, this.beanFactory.getBean(name)); + + requestAttributes.requestCompleted(); + assertTrue(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testGetFromFactoryBeanInScope() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + String name = "requestScopedFactoryBean"; + assertNull(request.getAttribute(name)); + TestBean bean = (TestBean) this.beanFactory.getBean(name); + assertTrue(request.getAttribute(name) instanceof FactoryBean); + assertSame(bean, this.beanFactory.getBean(name)); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testCircleLeadsToException() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + String name = "requestScopedObjectCircle1"; + assertNull(request.getAttribute(name)); + this.beanFactory.getBean(name); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + assertTrue(ex.contains(BeanCurrentlyInCreationException.class)); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testInnerBeanInheritsContainingBeanScopeByDefault() { + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + String outerBeanName = "requestScopedOuterBean"; + assertNull(request.getAttribute(outerBeanName)); + TestBean outer1 = (TestBean) this.beanFactory.getBean(outerBeanName); + assertNotNull(request.getAttribute(outerBeanName)); + TestBean inner1 = (TestBean) outer1.getSpouse(); + assertSame(outer1, this.beanFactory.getBean(outerBeanName)); + requestAttributes.requestCompleted(); + assertTrue(outer1.wasDestroyed()); + assertTrue(inner1.wasDestroyed()); + request = new MockHttpServletRequest(); + requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + TestBean outer2 = (TestBean) this.beanFactory.getBean(outerBeanName); + assertNotSame(outer1, outer2); + assertNotSame(inner1, outer2.getSpouse()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testRequestScopedInnerBeanDestroyedWhileContainedBySingleton() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + String outerBeanName = "singletonOuterBean"; + TestBean outer1 = (TestBean) this.beanFactory.getBean(outerBeanName); + assertNull(request.getAttribute(outerBeanName)); + TestBean inner1 = (TestBean) outer1.getSpouse(); + TestBean outer2 = (TestBean) this.beanFactory.getBean(outerBeanName); + assertSame(outer1, outer2); + assertSame(inner1, outer2.getSpouse()); + requestAttributes.requestCompleted(); + assertTrue(inner1.wasDestroyed()); + assertFalse(outer1.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopedProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopedProxyTests.java new file mode 100644 index 00000000000..1ba7a8d0a6a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/RequestScopedProxyTests.java @@ -0,0 +1,187 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import junit.framework.TestCase; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.DummyFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * @author Juergen Hoeller + */ +public class RequestScopedProxyTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new DefaultListableBeanFactory(); + this.beanFactory.registerScope("request", new RequestScope()); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.loadBeanDefinitions(new ClassPathResource("requestScopedProxyTests.xml", getClass())); + this.beanFactory.preInstantiateSingletons(); + } + + public void testGetFromScope() throws Exception { + String name = "requestScopedObject"; + TestBean bean = (TestBean) this.beanFactory.getBean(name); + assertTrue(AopUtils.isCglibProxy(bean)); + + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + assertNull(request.getAttribute("scopedTarget." + name)); + assertEquals("scoped", bean.getName()); + assertNotNull(request.getAttribute("scopedTarget." + name)); + assertEquals(TestBean.class, request.getAttribute("scopedTarget." + name).getClass()); + assertEquals("scoped", ((TestBean) request.getAttribute("scopedTarget." + name)).getName()); + assertSame(bean, this.beanFactory.getBean(name)); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testGetFromScopeThroughDynamicProxy() throws Exception { + String name = "requestScopedProxy"; + ITestBean bean = (ITestBean) this.beanFactory.getBean(name); + assertTrue(AopUtils.isJdkDynamicProxy(bean)); + + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + assertNull(request.getAttribute("scopedTarget." + name)); + assertEquals("scoped", bean.getName()); + assertNotNull(request.getAttribute("scopedTarget." + name)); + assertEquals(TestBean.class, request.getAttribute("scopedTarget." + name).getClass()); + assertEquals("scoped", ((TestBean) request.getAttribute("scopedTarget." + name)).getName()); + assertSame(bean, this.beanFactory.getBean(name)); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testDestructionAtRequestCompletion() throws Exception { + String name = "requestScopedDisposableObject"; + DerivedTestBean bean = (DerivedTestBean) this.beanFactory.getBean(name); + assertTrue(AopUtils.isCglibProxy(bean)); + + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + assertNull(request.getAttribute("scopedTarget." + name)); + assertEquals("scoped", bean.getName()); + assertNotNull(request.getAttribute("scopedTarget." + name)); + assertEquals(DerivedTestBean.class, request.getAttribute("scopedTarget." + name).getClass()); + assertEquals("scoped", ((TestBean) request.getAttribute("scopedTarget." + name)).getName()); + assertSame(bean, this.beanFactory.getBean(name)); + + requestAttributes.requestCompleted(); + assertTrue(((TestBean) request.getAttribute("scopedTarget." + name)).wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testGetFromFactoryBeanInScope() throws Exception { + String name = "requestScopedFactoryBean"; + TestBean bean = (TestBean) this.beanFactory.getBean(name); + assertTrue(AopUtils.isCglibProxy(bean)); + + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + assertNull(request.getAttribute("scopedTarget." + name)); + assertEquals(DummyFactory.SINGLETON_NAME, bean.getName()); + assertNotNull(request.getAttribute("scopedTarget." + name)); + assertEquals(DummyFactory.class, request.getAttribute("scopedTarget." + name).getClass()); + assertSame(bean, this.beanFactory.getBean(name)); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testGetInnerBeanFromScope() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("outerBean"); + assertFalse(AopUtils.isAopProxy(bean)); + assertTrue(AopUtils.isCglibProxy(bean.getSpouse())); + + String name = "scopedInnerBean"; + + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + assertNull(request.getAttribute("scopedTarget." + name)); + assertEquals("scoped", bean.getSpouse().getName()); + assertNotNull(request.getAttribute("scopedTarget." + name)); + assertEquals(TestBean.class, request.getAttribute("scopedTarget." + name).getClass()); + assertEquals("scoped", ((TestBean) request.getAttribute("scopedTarget." + name)).getName()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testGetAnonymousInnerBeanFromScope() throws Exception { + TestBean bean = (TestBean) this.beanFactory.getBean("outerBean"); + assertFalse(AopUtils.isAopProxy(bean)); + assertTrue(AopUtils.isCglibProxy(bean.getSpouse())); + + BeanDefinition beanDef = this.beanFactory.getBeanDefinition("outerBean"); + BeanDefinitionHolder innerBeanDef = + (BeanDefinitionHolder) beanDef.getPropertyValues().getPropertyValue("spouse").getValue(); + String name = innerBeanDef.getBeanName(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + + try { + assertNull(request.getAttribute("scopedTarget." + name)); + assertEquals("scoped", bean.getSpouse().getName()); + assertNotNull(request.getAttribute("scopedTarget." + name)); + assertEquals(TestBean.class, request.getAttribute("scopedTarget." + name).getClass()); + assertEquals("scoped", ((TestBean) request.getAttribute("scopedTarget." + name)).getName()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletRequestAttributesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletRequestAttributesTests.java new file mode 100644 index 00000000000..d6c83b12387 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletRequestAttributesTests.java @@ -0,0 +1,169 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import java.io.Serializable; + +import javax.servlet.http.HttpServletRequest; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.AssertThrows; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class ServletRequestAttributesTests extends TestCase { + + private static final String KEY = "ThatThingThatThing"; + + + private static final Serializable VALUE = new Serializable() { + }; + + + public void testCtorRejectsNullArg() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new ServletRequestAttributes(null); + } + }.runTest(); + } + + public void testUpdateAccessedAttributes() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute(KEY, VALUE); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + Object value = attrs.getAttribute(KEY, RequestAttributes.SCOPE_SESSION); + assertSame(VALUE, value); + attrs.requestCompleted(); + } + + public void testSetRequestScopedAttribute() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_REQUEST); + Object value = request.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetRequestScopedAttributeAfterCompletion() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + request.close(); + try { + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_REQUEST); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testSetSessionScopedAttribute() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute(KEY, VALUE); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetSessionScopedAttributeAfterCompletion() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute(KEY, VALUE); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + attrs.requestCompleted(); + request.close(); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetGlobalSessionScopedAttribute() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute(KEY, VALUE); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_GLOBAL_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetGlobalSessionScopedAttributeAfterCompletion() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute(KEY, VALUE); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + attrs.requestCompleted(); + request.close(); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_GLOBAL_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testGetSessionScopedAttributeDoesNotForceCreationOfSession() throws Exception { + MockControl mockRequest = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) mockRequest.getMock(); + request.getSession(false); + mockRequest.setReturnValue(null, 1); + mockRequest.replay(); + + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + Object value = attrs.getAttribute(KEY, RequestAttributes.SCOPE_SESSION); + assertNull(value); + + mockRequest.verify(); + } + + public void testRemoveSessionScopedAttribute() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute(KEY, VALUE); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + attrs.removeAttribute(KEY, RequestAttributes.SCOPE_SESSION); + Object value = session.getAttribute(KEY); + assertNull(value); + } + + public void testRemoveSessionScopedAttributeDoesNotForceCreationOfSession() throws Exception { + MockControl mockRequest = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) mockRequest.getMock(); + request.getSession(false); + mockRequest.setReturnValue(null, 1); + mockRequest.replay(); + + ServletRequestAttributes attrs = new ServletRequestAttributes(request); + attrs.removeAttribute(KEY, RequestAttributes.SCOPE_SESSION); + + mockRequest.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java new file mode 100644 index 00000000000..3280b533149 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import java.util.Locale; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * @author Juergen Hoeller + * @since 26.07.2006 + */ +public class ServletWebRequestTests extends TestCase { + + public void testParameters() { + MockHttpServletRequest servletRequest = new MockHttpServletRequest(); + servletRequest.addParameter("param1", "value1"); + servletRequest.addParameter("param2", "value2"); + servletRequest.addParameter("param2", "value2a"); + + ServletWebRequest request = new ServletWebRequest(servletRequest); + assertEquals("value1", request.getParameter("param1")); + assertEquals(1, request.getParameterValues("param1").length); + assertEquals("value1", request.getParameterValues("param1")[0]); + assertEquals("value2", request.getParameter("param2")); + assertEquals(2, request.getParameterValues("param2").length); + assertEquals("value2", request.getParameterValues("param2")[0]); + assertEquals("value2a", request.getParameterValues("param2")[1]); + + Map paramMap = request.getParameterMap(); + assertEquals(2, paramMap.size()); + assertEquals(1, ((String[]) paramMap.get("param1")).length); + assertEquals("value1", ((String[]) paramMap.get("param1"))[0]); + assertEquals(2, ((String[]) paramMap.get("param2")).length); + assertEquals("value2", ((String[]) paramMap.get("param2"))[0]); + assertEquals("value2a", ((String[]) paramMap.get("param2"))[1]); + } + + public void testLocale() { + MockHttpServletRequest servletRequest = new MockHttpServletRequest(); + servletRequest.addPreferredLocale(Locale.UK); + + ServletWebRequest request = new ServletWebRequest(servletRequest); + assertEquals(Locale.UK, request.getLocale()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/SessionScopeTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/SessionScopeTests.java new file mode 100644 index 00000000000..b3d1d3925b9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/SessionScopeTests.java @@ -0,0 +1,196 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import java.io.Serializable; + +import junit.framework.TestCase; + +import org.springframework.beans.BeansException; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.util.SerializationTestUtils; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class SessionScopeTests extends TestCase { + + private DefaultListableBeanFactory beanFactory; + + protected void setUp() throws Exception { + this.beanFactory = new DefaultListableBeanFactory(); + this.beanFactory.registerScope("session", new SessionScope()); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.loadBeanDefinitions(new ClassPathResource("sessionScopeTests.xml", getClass())); + } + + public void testGetFromScope() throws Exception { + MockHttpSession session = new MockHttpSession(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + String name = "sessionScopedObject"; + assertNull(session.getAttribute(name)); + TestBean bean = (TestBean) this.beanFactory.getBean(name); + assertEquals(session.getAttribute(name), bean); + assertSame(bean, this.beanFactory.getBean(name)); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testDestructionAtSessionTermination() throws Exception { + MockHttpSession session = new MockHttpSession(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + String name = "sessionScopedDisposableObject"; + assertNull(session.getAttribute(name)); + DerivedTestBean bean = (DerivedTestBean) this.beanFactory.getBean(name); + assertEquals(session.getAttribute(name), bean); + assertSame(bean, this.beanFactory.getBean(name)); + + requestAttributes.requestCompleted(); + session.invalidate(); + assertTrue(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + public void testDestructionWithSessionSerialization() throws Exception { + doTestDestructionWithSessionSerialization(false); + } + + public void testDestructionWithSessionSerializationAndBeanPostProcessor() throws Exception { + this.beanFactory.addBeanPostProcessor(new CustomDestructionAwareBeanPostProcessor()); + doTestDestructionWithSessionSerialization(false); + } + + public void testDestructionWithSessionSerializationAndSerializableBeanPostProcessor() throws Exception { + this.beanFactory.addBeanPostProcessor(new CustomSerializableDestructionAwareBeanPostProcessor()); + doTestDestructionWithSessionSerialization(true); + } + + private void doTestDestructionWithSessionSerialization(boolean beanNameReset) throws Exception { + Serializable serializedState = null; + + MockHttpSession session = new MockHttpSession(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + String name = "sessionScopedDisposableObject"; + assertNull(session.getAttribute(name)); + DerivedTestBean bean = (DerivedTestBean) this.beanFactory.getBean(name); + assertEquals(session.getAttribute(name), bean); + assertSame(bean, this.beanFactory.getBean(name)); + + requestAttributes.requestCompleted(); + serializedState = session.serializeState(); + assertFalse(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + + serializedState = (Serializable) SerializationTestUtils.serializeAndDeserialize(serializedState); + + session = new MockHttpSession(); + session.deserializeState(serializedState); + request = new MockHttpServletRequest(); + request.setSession(session); + requestAttributes = new ServletRequestAttributes(request); + + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + String name = "sessionScopedDisposableObject"; + assertNotNull(session.getAttribute(name)); + DerivedTestBean bean = (DerivedTestBean) this.beanFactory.getBean(name); + assertEquals(session.getAttribute(name), bean); + assertSame(bean, this.beanFactory.getBean(name)); + + requestAttributes.requestCompleted(); + session.invalidate(); + assertTrue(bean.wasDestroyed()); + + if (beanNameReset) { + assertNull(bean.getBeanName()); + } + else { + assertNotNull(bean.getBeanName()); + } + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + + private static class CustomDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor { + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { + } + } + + + private static class CustomSerializableDestructionAwareBeanPostProcessor + implements DestructionAwareBeanPostProcessor, Serializable { + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { + if (bean instanceof BeanNameAware) { + ((BeanNameAware) bean).setBeanName(null); + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopeTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopeTests.xml new file mode 100644 index 00000000000..badc6d6cf20 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopeTests.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopedProxyTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopedProxyTests.xml new file mode 100644 index 00000000000..ee1313d4dc1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/requestScopedProxyTests.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/sessionScopeTests.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/sessionScopeTests.xml new file mode 100644 index 00000000000..e4f05b9abe5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/request/sessionScopeTests.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/HttpRequestHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/HttpRequestHandlerTests.java new file mode 100644 index 00000000000..376211bde70 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/HttpRequestHandlerTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.support; + +import java.io.IOException; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.HttpRequestHandler; +import org.springframework.web.context.WebApplicationContext; + +/** + * @author Juergen Hoeller + * @since 2.0 + */ +public class HttpRequestHandlerTests extends TestCase { + + public void testHttpRequestHandlerServletPassThrough() throws Exception { + MockServletContext servletContext = new MockServletContext(); + final MockHttpServletRequest request = new MockHttpServletRequest(); + final MockHttpServletResponse response = new MockHttpServletResponse(); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.getBeanFactory().registerSingleton("myHandler", new HttpRequestHandler() { + public void handleRequest(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + assertSame(request, req); + assertSame(response, res); + String exception = request.getParameter("exception"); + if ("ServletException".equals(exception)) { + throw new ServletException("test"); + } + if ("IOException".equals(exception)) { + throw new IOException("test"); + } + res.getWriter().write("myResponse"); + } + }); + wac.setServletContext(servletContext); + wac.refresh(); + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + + Servlet servlet = new HttpRequestHandlerServlet(); + servlet.init(new MockServletConfig(servletContext, "myHandler")); + + servlet.service(request, response); + assertEquals("myResponse", response.getContentAsString()); + + try { + request.setParameter("exception", "ServletException"); + servlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + assertEquals("test", ex.getMessage()); + } + + try { + request.setParameter("exception", "IOException"); + servlet.service(request, response); + fail("Should have thrown IOException"); + } + catch (IOException ex) { + assertEquals("test", ex.getMessage()); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/ServletContextSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/ServletContextSupportTests.java new file mode 100644 index 00000000000..6d9c13d2a34 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/ServletContextSupportTests.java @@ -0,0 +1,474 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.support; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.ChildBeanDefinition; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.ManagedSet; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.io.Resource; +import org.springframework.mock.web.MockServletContext; + +/** + * Tests for various ServletContext-related support classes. + * + * @author Juergen Hoeller + * @since 22.12.2004 + */ +public class ServletContextSupportTests extends TestCase { + + public void testServletContextFactoryBean() { + MockServletContext sc = new MockServletContext(); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + MutablePropertyValues pvs = new MutablePropertyValues(); + wac.registerSingleton("servletContext", ServletContextFactoryBean.class, pvs); + wac.refresh(); + + Object value = wac.getBean("servletContext"); + assertEquals(sc, value); + } + + public void testServletContextAttributeFactoryBean() { + MockServletContext sc = new MockServletContext(); + sc.setAttribute("myAttr", "myValue"); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("attributeName", "myAttr"); + wac.registerSingleton("importedAttr", ServletContextAttributeFactoryBean.class, pvs); + wac.refresh(); + + Object value = wac.getBean("importedAttr"); + assertEquals("myValue", value); + } + + public void testServletContextAttributeFactoryBeanWithAttributeNotFound() { + MockServletContext sc = new MockServletContext(); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("attributeName", "myAttr"); + wac.registerSingleton("importedAttr", ServletContextAttributeFactoryBean.class, pvs); + + try { + wac.refresh(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + assertTrue(ex.getCause() instanceof IllegalStateException); + assertTrue(ex.getCause().getMessage().indexOf("myAttr") != -1); + } + } + + public void testServletContextParameterFactoryBean() { + MockServletContext sc = new MockServletContext(); + sc.addInitParameter("myParam", "myValue"); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("initParamName", "myParam"); + wac.registerSingleton("importedParam", ServletContextParameterFactoryBean.class, pvs); + wac.refresh(); + + Object value = wac.getBean("importedParam"); + assertEquals("myValue", value); + } + + public void testServletContextParameterFactoryBeanWithAttributeNotFound() { + MockServletContext sc = new MockServletContext(); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("initParamName", "myParam"); + wac.registerSingleton("importedParam", ServletContextParameterFactoryBean.class, pvs); + + try { + wac.refresh(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + // expected + assertTrue(ex.getCause() instanceof IllegalStateException); + assertTrue(ex.getCause().getMessage().indexOf("myParam") != -1); + } + } + + public void testServletContextAttributeExporter() { + TestBean tb = new TestBean(); + Map attributes = new HashMap(); + attributes.put("attr1", "value1"); + attributes.put("attr2", tb); + + MockServletContext sc = new MockServletContext(); + ServletContextAttributeExporter exporter = new ServletContextAttributeExporter(); + exporter.setAttributes(attributes); + exporter.setServletContext(sc); + + assertEquals("value1", sc.getAttribute("attr1")); + assertSame(tb, sc.getAttribute("attr2")); + } + + public void testServletContextPropertyPlaceholderConfigurer() { + MockServletContext sc = new MockServletContext(); + sc.addInitParameter("key4", "mykey4"); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "${age}"); + pvs.addPropertyValue("name", "${key4}name${var}${var}${"); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + wac.registerSingleton("tb1", TestBean.class, pvs); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, null); + wac.getDefaultListableBeanFactory().registerBeanDefinition("tb2", bd); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "age=98\nvar=${m}var\nref=tb2\nm=my"); + wac.registerSingleton("configurer", ServletContextPropertyPlaceholderConfigurer.class, pvs); + + wac.refresh(); + + TestBean tb1 = (TestBean) wac.getBean("tb1"); + TestBean tb2 = (TestBean) wac.getBean("tb2"); + assertEquals(98, tb1.getAge()); + assertEquals("mykey4namemyvarmyvar${", tb1.getName()); + assertEquals(tb2, tb1.getSpouse()); + } + + public void testServletContextPropertyPlaceholderConfigurerWithLocalOverriding() { + MockServletContext sc = new MockServletContext(); + sc.addInitParameter("key4", "mykey4"); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "${age}"); + pvs.addPropertyValue("name", "${key4}name${var}${var}${"); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + wac.registerSingleton("tb1", TestBean.class, pvs); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, null); + wac.getDefaultListableBeanFactory().registerBeanDefinition("tb2", bd); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "age=98\nvar=${m}var\nref=tb2\nm=my\nkey4=yourkey4"); + wac.registerSingleton("configurer", ServletContextPropertyPlaceholderConfigurer.class, pvs); + + wac.refresh(); + + TestBean tb1 = (TestBean) wac.getBean("tb1"); + TestBean tb2 = (TestBean) wac.getBean("tb2"); + assertEquals(98, tb1.getAge()); + assertEquals("yourkey4namemyvarmyvar${", tb1.getName()); + assertEquals(tb2, tb1.getSpouse()); + } + + public void testServletContextPropertyPlaceholderConfigurerWithContextOverride() { + MockServletContext sc = new MockServletContext(); + sc.addInitParameter("key4", "mykey4"); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "${age}"); + pvs.addPropertyValue("name", "${key4}name${var}${var}${"); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + wac.registerSingleton("tb1", TestBean.class, pvs); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, null); + wac.getDefaultListableBeanFactory().registerBeanDefinition("tb2", bd); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "age=98\nvar=${m}var\nref=tb2\nm=my\nkey4=yourkey4"); + pvs.addPropertyValue("contextOverride", Boolean.TRUE); + wac.registerSingleton("configurer", ServletContextPropertyPlaceholderConfigurer.class, pvs); + + wac.refresh(); + + TestBean tb1 = (TestBean) wac.getBean("tb1"); + TestBean tb2 = (TestBean) wac.getBean("tb2"); + assertEquals(98, tb1.getAge()); + assertEquals("mykey4namemyvarmyvar${", tb1.getName()); + assertEquals(tb2, tb1.getSpouse()); + } + + public void testServletContextPropertyPlaceholderConfigurerWithContextOverrideAndAttributes() { + MockServletContext sc = new MockServletContext(); + sc.addInitParameter("key4", "mykey4"); + sc.setAttribute("key4", "attrkey4"); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "${age}"); + pvs.addPropertyValue("name", "${key4}name${var}${var}${"); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + wac.registerSingleton("tb1", TestBean.class, pvs); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, null); + wac.getDefaultListableBeanFactory().registerBeanDefinition("tb2", bd); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "age=98\nvar=${m}var\nref=tb2\nm=my\nkey4=yourkey4"); + pvs.addPropertyValue("contextOverride", Boolean.TRUE); + pvs.addPropertyValue("searchContextAttributes", Boolean.TRUE); + wac.registerSingleton("configurer", ServletContextPropertyPlaceholderConfigurer.class, pvs); + + wac.refresh(); + + TestBean tb1 = (TestBean) wac.getBean("tb1"); + TestBean tb2 = (TestBean) wac.getBean("tb2"); + assertEquals(98, tb1.getAge()); + assertEquals("attrkey4namemyvarmyvar${", tb1.getName()); + assertEquals(tb2, tb1.getSpouse()); + } + + public void testServletContextPropertyPlaceholderConfigurerWithAttributes() { + MockServletContext sc = new MockServletContext(); + sc.addInitParameter("key4", "mykey4"); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("age", "${age}"); + pvs.addPropertyValue("name", "name${var}${var}${"); + pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}")); + wac.registerSingleton("tb1", TestBean.class, pvs); + + ConstructorArgumentValues cas = new ConstructorArgumentValues(); + cas.addIndexedArgumentValue(1, "${age}"); + cas.addGenericArgumentValue("${var}name${age}"); + + pvs = new MutablePropertyValues(); + List friends = new ManagedList(); + friends.add("na${age}me"); + friends.add(new RuntimeBeanReference("${ref}")); + pvs.addPropertyValue("friends", friends); + + Set someSet = new ManagedSet(); + someSet.add("na${age}me"); + someSet.add(new RuntimeBeanReference("${ref}")); + pvs.addPropertyValue("someSet", someSet); + + Map someMap = new ManagedMap(); + someMap.put("key1", new RuntimeBeanReference("${ref}")); + someMap.put("key2", "${age}name"); + MutablePropertyValues innerPvs = new MutablePropertyValues(); + innerPvs.addPropertyValue("touchy", "${os.name}"); + someMap.put("key3", new RootBeanDefinition(TestBean.class, innerPvs)); + MutablePropertyValues innerPvs2 = new MutablePropertyValues(innerPvs); + someMap.put("${key4}", new BeanDefinitionHolder(new ChildBeanDefinition("tb1", innerPvs2), "child")); + pvs.addPropertyValue("someMap", someMap); + + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, cas, pvs); + wac.getDefaultListableBeanFactory().registerBeanDefinition("tb2", bd); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("properties", "var=${m}var\nref=tb2\nm=my"); + pvs.addPropertyValue("searchContextAttributes", Boolean.TRUE); + wac.registerSingleton("configurer", ServletContextPropertyPlaceholderConfigurer.class, pvs); + sc.setAttribute("age", new Integer(98)); + + wac.refresh(); + + TestBean tb1 = (TestBean) wac.getBean("tb1"); + TestBean tb2 = (TestBean) wac.getBean("tb2"); + assertEquals(98, tb1.getAge()); + assertEquals(98, tb2.getAge()); + assertEquals("namemyvarmyvar${", tb1.getName()); + assertEquals("myvarname98", tb2.getName()); + assertEquals(tb2, tb1.getSpouse()); + assertEquals(2, tb2.getFriends().size()); + assertEquals("na98me", tb2.getFriends().iterator().next()); + assertEquals(tb2, tb2.getFriends().toArray()[1]); + assertEquals(2, tb2.getSomeSet().size()); + assertTrue(tb2.getSomeSet().contains("na98me")); + assertTrue(tb2.getSomeSet().contains(tb2)); + assertEquals(4, tb2.getSomeMap().size()); + assertEquals(tb2, tb2.getSomeMap().get("key1")); + assertEquals("98name", tb2.getSomeMap().get("key2")); + TestBean inner1 = (TestBean) tb2.getSomeMap().get("key3"); + TestBean inner2 = (TestBean) tb2.getSomeMap().get("mykey4"); + assertEquals(0, inner1.getAge()); + assertEquals(null, inner1.getName()); + assertEquals(System.getProperty("os.name"), inner1.getTouchy()); + assertEquals(98, inner2.getAge()); + assertEquals("namemyvarmyvar${", inner2.getName()); + assertEquals(System.getProperty("os.name"), inner2.getTouchy()); + } + + public void testServletContextResourceLoader() { + MockServletContext sc = new MockServletContext("classpath:org/springframework/web/context"); + ServletContextResourceLoader rl = new ServletContextResourceLoader(sc); + assertTrue(rl.getResource("/WEB-INF/web.xml").exists()); + assertTrue(rl.getResource("WEB-INF/web.xml").exists()); + assertTrue(rl.getResource("../context/WEB-INF/web.xml").exists()); + assertTrue(rl.getResource("/../context/WEB-INF/web.xml").exists()); + } + + public void testServletContextResourcePatternResolver() throws IOException { + final Set paths = new HashSet(); + paths.add("/WEB-INF/context1.xml"); + paths.add("/WEB-INF/context2.xml"); + + MockServletContext sc = new MockServletContext("classpath:org/springframework/web/context") { + public Set getResourcePaths(String path) { + if ("/WEB-INF/".equals(path)) { + return paths; + } + return null; + } + }; + + ServletContextResourcePatternResolver rpr = new ServletContextResourcePatternResolver(sc); + Resource[] found = rpr.getResources("/WEB-INF/*.xml"); + Set foundPaths = new HashSet(); + for (int i = 0; i < found.length; i++) { + foundPaths.add(((ServletContextResource) found[i]).getPath()); + } + assertEquals(2, foundPaths.size()); + assertTrue(foundPaths.contains("/WEB-INF/context1.xml")); + assertTrue(foundPaths.contains("/WEB-INF/context2.xml")); + } + + public void testServletContextResourcePatternResolverWithPatternPath() throws IOException { + final Set dirs = new HashSet(); + dirs.add("/WEB-INF/mydir1/"); + dirs.add("/WEB-INF/mydir2/"); + + MockServletContext sc = new MockServletContext("classpath:org/springframework/web/context") { + public Set getResourcePaths(String path) { + if ("/WEB-INF/".equals(path)) { + return dirs; + } + if ("/WEB-INF/mydir1/".equals(path)) { + return Collections.singleton("/WEB-INF/mydir1/context1.xml"); + } + if ("/WEB-INF/mydir2/".equals(path)) { + return Collections.singleton("/WEB-INF/mydir2/context2.xml"); + } + return null; + } + }; + + ServletContextResourcePatternResolver rpr = new ServletContextResourcePatternResolver(sc); + Resource[] found = rpr.getResources("/WEB-INF/*/*.xml"); + Set foundPaths = new HashSet(); + for (int i = 0; i < found.length; i++) { + foundPaths.add(((ServletContextResource) found[i]).getPath()); + } + assertEquals(2, foundPaths.size()); + assertTrue(foundPaths.contains("/WEB-INF/mydir1/context1.xml")); + assertTrue(foundPaths.contains("/WEB-INF/mydir2/context2.xml")); + } + + public void testServletContextResourcePatternResolverWithUnboundedPatternPath() throws IOException { + final Set dirs = new HashSet(); + dirs.add("/WEB-INF/mydir1/"); + dirs.add("/WEB-INF/mydir2/"); + + final Set paths = new HashSet(); + paths.add("/WEB-INF/mydir2/context2.xml"); + paths.add("/WEB-INF/mydir2/mydir3/"); + + MockServletContext sc = new MockServletContext("classpath:org/springframework/web/context") { + public Set getResourcePaths(String path) { + if ("/WEB-INF/".equals(path)) { + return dirs; + } + if ("/WEB-INF/mydir1/".equals(path)) { + return Collections.singleton("/WEB-INF/mydir1/context1.xml"); + } + if ("/WEB-INF/mydir2/".equals(path)) { + return paths; + } + if ("/WEB-INF/mydir2/mydir3/".equals(path)) { + return Collections.singleton("/WEB-INF/mydir2/mydir3/context3.xml"); + } + return null; + } + }; + + ServletContextResourcePatternResolver rpr = new ServletContextResourcePatternResolver(sc); + Resource[] found = rpr.getResources("/WEB-INF/**/*.xml"); + Set foundPaths = new HashSet(); + for (int i = 0; i < found.length; i++) { + foundPaths.add(((ServletContextResource) found[i]).getPath()); + } + assertEquals(3, foundPaths.size()); + assertTrue(foundPaths.contains("/WEB-INF/mydir1/context1.xml")); + assertTrue(foundPaths.contains("/WEB-INF/mydir2/context2.xml")); + assertTrue(foundPaths.contains("/WEB-INF/mydir2/mydir3/context3.xml")); + } + + public void testServletContextResourcePatternResolverWithAbsolutePaths() throws IOException { + final Set paths = new HashSet(); + paths.add("C:/webroot/WEB-INF/context1.xml"); + paths.add("C:/webroot/WEB-INF/context2.xml"); + paths.add("C:/webroot/someOtherDirThatDoesntContainPath"); + + MockServletContext sc = new MockServletContext("classpath:org/springframework/web/context") { + public Set getResourcePaths(String path) { + if ("/WEB-INF/".equals(path)) { + return paths; + } + return null; + } + }; + + ServletContextResourcePatternResolver rpr = new ServletContextResourcePatternResolver(sc); + Resource[] found = rpr.getResources("/WEB-INF/*.xml"); + Set foundPaths = new HashSet(); + for (int i = 0; i < found.length; i++) { + foundPaths.add(((ServletContextResource) found[i]).getPath()); + } + assertEquals(2, foundPaths.size()); + assertTrue(foundPaths.contains("/WEB-INF/context1.xml")); + assertTrue(foundPaths.contains("/WEB-INF/context2.xml")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/WebApplicationObjectSupportTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/WebApplicationObjectSupportTests.java new file mode 100644 index 00000000000..b7d7cc19c52 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/context/support/WebApplicationObjectSupportTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.support; + +import java.io.File; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.util.WebUtils; + +/** + * @author Juergen Hoeller + * @since 28.08.2003 + */ +public class WebApplicationObjectSupportTests extends TestCase { + + public void testWebApplicationObjectSupport() { + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(new MockServletContext()); + File tempDir = new File(""); + wac.getServletContext().setAttribute(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, tempDir); + wac.registerBeanDefinition("test", new RootBeanDefinition(TestWebApplicationObject.class)); + wac.refresh(); + WebApplicationObjectSupport wao = (WebApplicationObjectSupport) wac.getBean("test"); + assertEquals(wao.getServletContext(), wac.getServletContext()); + assertEquals(wao.getTempDir(), tempDir); + } + + public void testWebApplicationObjectSupportWithWrongContext() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerBeanDefinition("test", new RootBeanDefinition(TestWebApplicationObject.class)); + WebApplicationObjectSupport wao = (WebApplicationObjectSupport) ac.getBean("test"); + try { + wao.getWebApplicationContext(); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + + public static class TestWebApplicationObject extends WebApplicationObjectSupport { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/filter/CharacterEncodingFilterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/filter/CharacterEncodingFilterTests.java new file mode 100644 index 00000000000..801c05440cf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/filter/CharacterEncodingFilterTests.java @@ -0,0 +1,199 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.filter; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class CharacterEncodingFilterTests extends TestCase { + + private static final String FILTER_NAME = "boot"; + + private static final String ENCODING = "UTF-8"; + + + public void testForceAlwaysSetsEncoding() throws Exception { + MockControl mockRequest = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) mockRequest.getMock(); + request.setCharacterEncoding(ENCODING); + mockRequest.setVoidCallable(); + request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setReturnValue(null); + request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE); + mockRequest.setVoidCallable(); + request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setVoidCallable(); + mockRequest.replay(); + + MockControl mockResponse = MockControl.createControl(HttpServletResponse.class); + HttpServletResponse response = (HttpServletResponse) mockResponse.getMock(); + response.setCharacterEncoding(ENCODING); + mockResponse.setVoidCallable(); + mockResponse.replay(); + + MockControl mockFilter = MockControl.createControl(FilterChain.class); + FilterChain filterChain = (FilterChain) mockFilter.getMock(); + filterChain.doFilter(request, response); + mockFilter.replay(); + + CharacterEncodingFilter filter = new CharacterEncodingFilter(); + filter.setForceEncoding(true); + filter.setEncoding(ENCODING); + filter.init(new MockFilterConfig(FILTER_NAME)); + filter.doFilter(request, response, filterChain); + + mockRequest.verify(); + mockResponse.verify(); + mockFilter.verify(); + } + + public void testEncodingIfEmptyAndNotForced() throws Exception { + MockControl mockRequest = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) mockRequest.getMock(); + request.getCharacterEncoding(); + mockRequest.setReturnValue(null); + request.setCharacterEncoding(ENCODING); + mockRequest.setVoidCallable(); + request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setReturnValue(null); + request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE); + mockRequest.setVoidCallable(); + request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setVoidCallable(); + mockRequest.replay(); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockControl mockFilter = MockControl.createControl(FilterChain.class); + FilterChain filterChain = (FilterChain) mockFilter.getMock(); + filterChain.doFilter(request, response); + mockFilter.replay(); + + CharacterEncodingFilter filter = new CharacterEncodingFilter(); + filter.setForceEncoding(false); + filter.setEncoding(ENCODING); + filter.init(new MockFilterConfig(FILTER_NAME)); + filter.doFilter(request, response, filterChain); + + mockRequest.verify(); + mockFilter.verify(); + } + + public void testDoesNowtIfEncodingIsNotEmptyAndNotForced() throws Exception { + MockControl mockRequest = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) mockRequest.getMock(); + request.getCharacterEncoding(); + mockRequest.setReturnValue(ENCODING); + request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setReturnValue(null); + request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE); + mockRequest.setVoidCallable(); + request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setVoidCallable(); + mockRequest.replay(); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockControl mockFilter = MockControl.createControl(FilterChain.class); + FilterChain filterChain = (FilterChain) mockFilter.getMock(); + filterChain.doFilter(request, response); + mockFilter.replay(); + + CharacterEncodingFilter filter = new CharacterEncodingFilter(); + filter.setEncoding(ENCODING); + filter.init(new MockFilterConfig(FILTER_NAME)); + filter.doFilter(request, response, filterChain); + + mockRequest.verify(); + mockFilter.verify(); + } + + public void testWithBeanInitialization() throws Exception { + MockControl mockRequest = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) mockRequest.getMock(); + request.getCharacterEncoding(); + mockRequest.setReturnValue(null); + request.setCharacterEncoding(ENCODING); + mockRequest.setVoidCallable(); + request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setReturnValue(null); + request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE); + mockRequest.setVoidCallable(); + request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setVoidCallable(); + mockRequest.replay(); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockControl mockFilter = MockControl.createControl(FilterChain.class); + FilterChain filterChain = (FilterChain) mockFilter.getMock(); + filterChain.doFilter(request, response); + mockFilter.replay(); + + CharacterEncodingFilter filter = new CharacterEncodingFilter(); + filter.setEncoding(ENCODING); + filter.setBeanName(FILTER_NAME); + filter.setServletContext(new MockServletContext()); + filter.doFilter(request, response, filterChain); + + mockRequest.verify(); + mockFilter.verify(); + } + + public void testWithIncompleteInitialization() throws Exception { + MockControl mockRequest = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) mockRequest.getMock(); + request.getCharacterEncoding(); + mockRequest.setReturnValue(null); + request.setCharacterEncoding(ENCODING); + mockRequest.setVoidCallable(); + request.getAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setReturnValue(null); + request.setAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE); + mockRequest.setVoidCallable(); + request.removeAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX); + mockRequest.setVoidCallable(); + mockRequest.replay(); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockControl mockFilter = MockControl.createControl(FilterChain.class); + FilterChain filterChain = (FilterChain) mockFilter.getMock(); + filterChain.doFilter(request, response); + mockFilter.replay(); + + CharacterEncodingFilter filter = new CharacterEncodingFilter(); + filter.setEncoding(ENCODING); + filter.doFilter(request, response, filterChain); + + mockRequest.verify(); + mockFilter.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java new file mode 100644 index 00000000000..51bea2e6502 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java @@ -0,0 +1,170 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.filter; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; + +/** + * @author Juergen Hoeller + * @since 08.05.2005 + */ +public class DelegatingFilterProxyTests extends TestCase { + + public void testDelegatingFilterProxy() throws ServletException, IOException { + ServletContext sc = new MockServletContext(); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.registerSingleton("targetFilter", MockFilter.class); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + + MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter"); + + MockFilterConfig proxyConfig = new MockFilterConfig(sc); + proxyConfig.addInitParameter("targetBeanName", "targetFilter"); + DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(); + filterProxy.init(proxyConfig); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + filterProxy.doFilter(request, response, null); + + assertNull(targetFilter.filterConfig); + assertEquals(Boolean.TRUE, request.getAttribute("called")); + + filterProxy.destroy(); + assertNull(targetFilter.filterConfig); + } + + public void testDelegatingFilterProxyWithFilterName() throws ServletException, IOException { + ServletContext sc = new MockServletContext(); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.registerSingleton("targetFilter", MockFilter.class); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + + MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter"); + + MockFilterConfig proxyConfig = new MockFilterConfig(sc, "targetFilter"); + DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(); + filterProxy.init(proxyConfig); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + filterProxy.doFilter(request, response, null); + + assertNull(targetFilter.filterConfig); + assertEquals(Boolean.TRUE, request.getAttribute("called")); + + filterProxy.destroy(); + assertNull(targetFilter.filterConfig); + } + + public void testDelegatingFilterProxyWithLazyContextStartup() throws ServletException, IOException { + ServletContext sc = new MockServletContext(); + + MockFilterConfig proxyConfig = new MockFilterConfig(sc); + proxyConfig.addInitParameter("targetBeanName", "targetFilter"); + DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(); + filterProxy.init(proxyConfig); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.registerSingleton("targetFilter", MockFilter.class); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + + MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter"); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + filterProxy.doFilter(request, response, null); + + assertNull(targetFilter.filterConfig); + assertEquals(Boolean.TRUE, request.getAttribute("called")); + + filterProxy.destroy(); + assertNull(targetFilter.filterConfig); + } + + public void testDelegatingFilterProxyWithTargetFilterLifecycle() throws ServletException, IOException { + ServletContext sc = new MockServletContext(); + + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(sc); + wac.registerSingleton("targetFilter", MockFilter.class); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + + MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter"); + + MockFilterConfig proxyConfig = new MockFilterConfig(sc); + proxyConfig.addInitParameter("targetBeanName", "targetFilter"); + proxyConfig.addInitParameter("targetFilterLifecycle", "true"); + DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(); + filterProxy.init(proxyConfig); + assertEquals(proxyConfig, targetFilter.filterConfig); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + filterProxy.doFilter(request, response, null); + + assertEquals(proxyConfig, targetFilter.filterConfig); + assertEquals(Boolean.TRUE, request.getAttribute("called")); + + filterProxy.destroy(); + assertNull(targetFilter.filterConfig); + } + + + public static class MockFilter implements Filter { + + public FilterConfig filterConfig; + + public void init(FilterConfig filterConfig) throws ServletException { + this.filterConfig = filterConfig; + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { + request.setAttribute("called", Boolean.TRUE); + } + + public void destroy() { + this.filterConfig = null; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/filter/RequestContextFilterTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/filter/RequestContextFilterTests.java new file mode 100644 index 00000000000..a1272ad66c4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/filter/RequestContextFilterTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.filter; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class RequestContextFilterTests extends TestCase { + + public void testHappyPath() throws Exception { + testFilterInvocation(null); + } + + public void testWithException() throws Exception { + testFilterInvocation(new ServletException()); + } + + public void testFilterInvocation(final ServletException sex) throws Exception { + final MockHttpServletRequest req = new MockHttpServletRequest(); + req.setAttribute("myAttr", "myValue"); + final MockHttpServletResponse resp = new MockHttpServletResponse(); + + // Expect one invocation by the filter being tested + class DummyFilterChain implements FilterChain { + public int invocations = 0; + public void doFilter(ServletRequest req, ServletResponse resp) throws IOException, ServletException { + ++invocations; + if (invocations == 1) { + assertSame("myValue", + RequestContextHolder.currentRequestAttributes().getAttribute("myAttr", RequestAttributes.SCOPE_REQUEST)); + if (sex != null) { + throw sex; + } + } + else { + throw new IllegalStateException("Too many invocations"); + } + } + }; + + DummyFilterChain fc = new DummyFilterChain(); + MockFilterConfig mfc = new MockFilterConfig(new MockServletContext(), "foo"); + + RequestContextFilter rbf = new RequestContextFilter(); + rbf.init(mfc); + + try { + rbf.doFilter(req, resp, fc); + if (sex != null) { + fail(); + } + } + catch (ServletException ex) { + assertNotNull(sex); + } + + try { + RequestContextHolder.currentRequestAttributes(); + fail(); + } + catch (IllegalStateException ex) { + // Ok + } + + assertEquals(1, fc.invocations); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingNavigationHandlerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingNavigationHandlerTests.java new file mode 100644 index 00000000000..6e58058bf0e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingNavigationHandlerTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.jsf; + +import javax.faces.application.NavigationHandler; +import javax.faces.context.FacesContext; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.support.StaticListableBeanFactory; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + */ +public class DelegatingNavigationHandlerTests extends TestCase { + + private MockFacesContext facesContext; + private StaticListableBeanFactory beanFactory; + private TestNavigationHandler origNavHandler; + private DelegatingNavigationHandlerProxy delNavHandler; + + protected void setUp() { + facesContext = new MockFacesContext(); + beanFactory = new StaticListableBeanFactory(); + origNavHandler = new TestNavigationHandler(); + + delNavHandler = new DelegatingNavigationHandlerProxy(origNavHandler) { + protected BeanFactory getBeanFactory(FacesContext facesContext) { + return beanFactory; + } + }; + } + + public void testHandleNavigationWithoutDecoration() { + TestNavigationHandler targetHandler = new TestNavigationHandler(); + beanFactory.addBean("jsfNavigationHandler", targetHandler); + + delNavHandler.handleNavigation(facesContext, "fromAction", "myViewId"); + assertEquals(targetHandler.lastFromAction, "fromAction"); + assertEquals(targetHandler.lastOutcome, "myViewId"); + } + + public void testHandleNavigationWithDecoration() { + TestDecoratingNavigationHandler targetHandler = new TestDecoratingNavigationHandler(); + beanFactory.addBean("jsfNavigationHandler", targetHandler); + + delNavHandler.handleNavigation(facesContext, "fromAction", "myViewId"); + assertEquals(targetHandler.lastFromAction, "fromAction"); + assertEquals(targetHandler.lastOutcome, "myViewId"); + + // Original handler must have been invoked as well... + assertEquals(origNavHandler.lastFromAction, "fromAction"); + assertEquals(origNavHandler.lastOutcome, "myViewId"); + } + + + public static class TestNavigationHandler extends NavigationHandler { + + private String lastFromAction; + private String lastOutcome; + + public void handleNavigation(FacesContext facesContext, String fromAction, String outcome) { + lastFromAction = fromAction; + lastOutcome = outcome; + } + } + + + public static class TestDecoratingNavigationHandler extends DecoratingNavigationHandler { + + private String lastFromAction; + private String lastOutcome; + + public void handleNavigation( + FacesContext facesContext, String fromAction, String outcome, NavigationHandler originalNavigationHandler) { + lastFromAction = fromAction; + lastOutcome = outcome; + if (originalNavigationHandler != null) { + originalNavigationHandler.handleNavigation(facesContext, fromAction, outcome); + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingPhaseListenerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingPhaseListenerTests.java new file mode 100644 index 00000000000..48af11100d6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingPhaseListenerTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.jsf; + +import javax.faces.context.FacesContext; +import javax.faces.event.PhaseEvent; +import javax.faces.event.PhaseId; +import javax.faces.event.PhaseListener; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.support.StaticListableBeanFactory; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + */ +public class DelegatingPhaseListenerTests extends TestCase { + + private MockFacesContext facesContext; + private StaticListableBeanFactory beanFactory; + private DelegatingPhaseListenerMulticaster delPhaseListener; + + protected void setUp() { + facesContext = new MockFacesContext(); + beanFactory = new StaticListableBeanFactory(); + + delPhaseListener = new DelegatingPhaseListenerMulticaster() { + protected ListableBeanFactory getBeanFactory(FacesContext facesContext) { + return beanFactory; + } + }; + } + + public void testBeforeAndAfterPhaseWithSingleTarget() { + TestListener target = new TestListener(); + beanFactory.addBean("testListener", target); + + assertEquals(delPhaseListener.getPhaseId(), PhaseId.ANY_PHASE); + PhaseEvent event = new PhaseEvent(facesContext, PhaseId.INVOKE_APPLICATION, new MockLifecycle()); + + delPhaseListener.beforePhase(event); + assertTrue(target.beforeCalled); + + delPhaseListener.afterPhase(event); + assertTrue(target.afterCalled); + } + + public void testBeforeAndAfterPhaseWithMultipleTargets() { + TestListener target1 = new TestListener(); + TestListener target2 = new TestListener(); + beanFactory.addBean("testListener1", target1); + beanFactory.addBean("testListener2", target2); + + assertEquals(delPhaseListener.getPhaseId(), PhaseId.ANY_PHASE); + PhaseEvent event = new PhaseEvent(facesContext, PhaseId.INVOKE_APPLICATION, new MockLifecycle()); + + delPhaseListener.beforePhase(event); + assertTrue(target1.beforeCalled); + assertTrue(target2.beforeCalled); + + delPhaseListener.afterPhase(event); + assertTrue(target1.afterCalled); + assertTrue(target2.afterCalled); + } + + + public static class TestListener implements PhaseListener { + + boolean beforeCalled = false; + boolean afterCalled = false; + + public PhaseId getPhaseId() { + return PhaseId.ANY_PHASE; + } + + public void beforePhase(PhaseEvent arg0) { + beforeCalled = true; + } + + public void afterPhase(PhaseEvent arg0) { + afterCalled = true; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingVariableResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingVariableResolverTests.java new file mode 100644 index 00000000000..76e8c829b14 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/DelegatingVariableResolverTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.jsf; + +import javax.faces.context.FacesContext; +import javax.faces.el.EvaluationException; +import javax.faces.el.VariableResolver; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; + +/** + * @author Juergen Hoeller + * @since 02.08.2004 + */ +public class DelegatingVariableResolverTests extends TestCase { + + public void testDelegatingVariableResolver() { + final StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("bean1", TestBean.class, null); + wac.registerSingleton("var1", TestBean.class, null); + wac.refresh(); + TestBean bean1 = (TestBean) wac.getBean("bean1"); + + // We need to override the getWebApplicationContext method here: + // FacesContext and ExternalContext are hard to mock. + DelegatingVariableResolver resolver = new DelegatingVariableResolver(new OriginalVariableResolver()) { + protected WebApplicationContext getWebApplicationContext(FacesContext facesContext) { + return wac; + } + }; + assertEquals(bean1, resolver.resolveVariable(null, "bean1")); + assertEquals("val1", resolver.resolveVariable(null, "var1")); + } + + public void testSpringBeanVariableResolver() { + final StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("bean1", TestBean.class, null); + wac.registerSingleton("var1", TestBean.class, null); + wac.refresh(); + TestBean bean1 = (TestBean) wac.getBean("bean1"); + TestBean var1 = (TestBean) wac.getBean("var1"); + + // We need to override the getWebApplicationContext method here: + // FacesContext and ExternalContext are hard to mock. + SpringBeanVariableResolver resolver = new SpringBeanVariableResolver(new OriginalVariableResolver()) { + protected WebApplicationContext getWebApplicationContext(FacesContext facesContext) { + return wac; + } + }; + assertEquals(bean1, resolver.resolveVariable(null, "bean1")); + assertEquals(var1, resolver.resolveVariable(null, "var1")); + } + + + private static class OriginalVariableResolver extends VariableResolver { + + public Object resolveVariable(FacesContext facesContext, String name) throws EvaluationException { + if ("var1".equals(name)) { + return "val1"; + } + return null; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockFacesContext.java b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockFacesContext.java new file mode 100644 index 00000000000..91c775c6a32 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockFacesContext.java @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.jsf; + +import java.util.Iterator; + +import javax.faces.application.Application; +import javax.faces.application.FacesMessage; +import javax.faces.application.FacesMessage.Severity; +import javax.faces.component.UIViewRoot; +import javax.faces.context.ExternalContext; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseStream; +import javax.faces.context.ResponseWriter; +import javax.faces.render.RenderKit; + +/** + * Mock implementation of the FacesContext class to facilitate + * standalone Action unit tests. + * + * @author Ulrik Sandberg + * @see javax.faces.context.FacesContext + */ +public class MockFacesContext extends FacesContext { + + private ExternalContext externalContext; + + private Application application; + + private UIViewRoot viewRoot; + + + public Application getApplication() { + return application; + } + + public void setApplication(Application application) { + this.application = application; + } + + public Iterator getClientIdsWithMessages() { + return null; + } + + public ExternalContext getExternalContext() { + return externalContext; + } + + public void setExternalContext(ExternalContext externalContext) { + this.externalContext = externalContext; + } + + public Severity getMaximumSeverity() { + return null; + } + + public Iterator getMessages() { + return null; + } + + public Iterator getMessages(String arg0) { + return null; + } + + public RenderKit getRenderKit() { + return null; + } + + public boolean getRenderResponse() { + return false; + } + + public boolean getResponseComplete() { + return false; + } + + public ResponseStream getResponseStream() { + return null; + } + + public void setResponseStream(ResponseStream arg0) { + } + + public ResponseWriter getResponseWriter() { + return null; + } + + public void setResponseWriter(ResponseWriter arg0) { + } + + public UIViewRoot getViewRoot() { + return viewRoot; + } + + public void setViewRoot(UIViewRoot viewRoot) { + this.viewRoot = viewRoot; + } + + public void addMessage(String arg0, FacesMessage arg1) { + } + + public void release() { + } + + public void renderResponse() { + } + + public void responseComplete() { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockLifecycle.java b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockLifecycle.java new file mode 100644 index 00000000000..29a22aa6fcf --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/jsf/MockLifecycle.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.jsf; + +import javax.faces.FacesException; +import javax.faces.context.FacesContext; +import javax.faces.event.PhaseListener; +import javax.faces.lifecycle.Lifecycle; + +/** + * @author Juergen Hoeller + * @since 29.01.2006 + */ +public class MockLifecycle extends Lifecycle { + + public void addPhaseListener(PhaseListener phaseListener) { + } + + public void execute(FacesContext facesContext) throws FacesException { + } + + public PhaseListener[] getPhaseListeners() { + return null; + } + + public void removePhaseListener(PhaseListener phaseListener) { + } + + public void render(FacesContext facesContext) throws FacesException { + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/MockMultipartHttpServletRequestTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/MockMultipartHttpServletRequestTests.java new file mode 100644 index 00000000000..6352a08bf04 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/MockMultipartHttpServletRequestTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.multipart; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.mock.web.MockMultipartHttpServletRequest; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.ObjectUtils; + +/** + * @author Juergen Hoeller + */ +public class MockMultipartHttpServletRequestTests extends TestCase { + + public void testMockMultipartHttpServletRequestWithByteArray() throws IOException { + MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); + assertFalse(request.getFileNames().hasNext()); + assertNull(request.getFile("file1")); + assertNull(request.getFile("file2")); + assertTrue(request.getFileMap().isEmpty()); + + request.addFile(new MockMultipartFile("file1", "myContent1".getBytes())); + request.addFile(new MockMultipartFile("file2", "myOrigFilename", "text/plain", "myContent2".getBytes())); + doTestMultipartHttpServletRequest(request); + } + + public void testMockMultipartHttpServletRequestWithInputStream() throws IOException { + MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); + request.addFile(new MockMultipartFile("file1", new ByteArrayInputStream("myContent1".getBytes()))); + request.addFile(new MockMultipartFile("file2", "myOrigFilename", "text/plain", new ByteArrayInputStream("myContent2".getBytes()))); + doTestMultipartHttpServletRequest(request); + } + + private void doTestMultipartHttpServletRequest(MultipartHttpServletRequest request) throws IOException { + Set fileNames = new HashSet(); + Iterator fileIter = request.getFileNames(); + while (fileIter.hasNext()) { + fileNames.add(fileIter.next()); + } + assertEquals(2, fileNames.size()); + assertTrue(fileNames.contains("file1")); + assertTrue(fileNames.contains("file2")); + MultipartFile file1 = request.getFile("file1"); + MultipartFile file2 = request.getFile("file2"); + Map fileMap = request.getFileMap(); + List fileMapKeys = new LinkedList(fileMap.keySet()); + assertEquals(2, fileMapKeys.size()); + assertEquals(file1, fileMap.get("file1")); + assertEquals(file2, fileMap.get("file2")); + + assertEquals("file1", file1.getName()); + assertEquals("", file1.getOriginalFilename()); + assertNull(file1.getContentType()); + assertTrue(ObjectUtils.nullSafeEquals("myContent1".getBytes(), file1.getBytes())); + assertTrue(ObjectUtils.nullSafeEquals("myContent1".getBytes(), FileCopyUtils.copyToByteArray(file1.getInputStream()))); + assertEquals("file2", file2.getName()); + assertEquals("myOrigFilename", file2.getOriginalFilename()); + assertEquals("text/plain", file2.getContentType()); + assertTrue(ObjectUtils.nullSafeEquals("myContent2".getBytes(), file2.getBytes())); + assertTrue(ObjectUtils.nullSafeEquals("myContent2".getBytes(), FileCopyUtils.copyToByteArray(file2.getInputStream()))); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/commons/CommonsMultipartResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/commons/CommonsMultipartResolverTests.java new file mode 100644 index 00000000000..015d4fdb738 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/commons/CommonsMultipartResolverTests.java @@ -0,0 +1,485 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.multipart.commons; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUpload; +import org.apache.commons.fileupload.servlet.ServletFileUpload; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.mock.web.PassThroughFilterChain; +import org.springframework.web.bind.ServletRequestDataBinder; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.support.ByteArrayMultipartFileEditor; +import org.springframework.web.multipart.support.MultipartFilter; +import org.springframework.web.multipart.support.StringMultipartFileEditor; +import org.springframework.web.util.WebUtils; + +/** + * @author Juergen Hoeller + * @since 08.10.2003 + */ +public class CommonsMultipartResolverTests extends TestCase { + + public void testWithApplicationContext() throws Exception { + doTestWithApplicationContext(false); + } + + public void testWithApplicationContextAndLazyResolution() throws Exception { + doTestWithApplicationContext(true); + } + + private void doTestWithApplicationContext(boolean lazy) throws Exception { + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(new MockServletContext()); + wac.getServletContext().setAttribute(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File("mytemp")); + wac.refresh(); + MockCommonsMultipartResolver resolver = new MockCommonsMultipartResolver(); + resolver.setMaxUploadSize(1000); + resolver.setMaxInMemorySize(100); + resolver.setDefaultEncoding("enc"); + if (lazy) { + resolver.setResolveLazily(false); + } + resolver.setServletContext(wac.getServletContext()); + assertEquals(1000, resolver.getFileUpload().getSizeMax()); + assertEquals(100, resolver.getFileItemFactory().getSizeThreshold()); + assertEquals("enc", resolver.getFileUpload().getHeaderEncoding()); + assertTrue(resolver.getFileItemFactory().getRepository().getAbsolutePath().endsWith("mytemp")); + + MockHttpServletRequest originalRequest = new MockHttpServletRequest(); + originalRequest.setMethod("POST"); + originalRequest.setContentType("multipart/form-data"); + originalRequest.addHeader("Content-type", "multipart/form-data"); + originalRequest.addParameter("getField", "getValue"); + assertTrue(resolver.isMultipart(originalRequest)); + MultipartHttpServletRequest request = resolver.resolveMultipart(originalRequest); + + Set parameterNames = new HashSet(); + Enumeration parameterEnum = request.getParameterNames(); + while (parameterEnum.hasMoreElements()) { + parameterNames.add(parameterEnum.nextElement()); + } + assertEquals(3, parameterNames.size()); + assertTrue(parameterNames.contains("field3")); + assertTrue(parameterNames.contains("field4")); + assertTrue(parameterNames.contains("getField")); + assertEquals("value3", request.getParameter("field3")); + List parameterValues = Arrays.asList(request.getParameterValues("field3")); + assertEquals(1, parameterValues.size()); + assertTrue(parameterValues.contains("value3")); + assertEquals("value4", request.getParameter("field4")); + parameterValues = Arrays.asList(request.getParameterValues("field4")); + assertEquals(2, parameterValues.size()); + assertTrue(parameterValues.contains("value4")); + assertTrue(parameterValues.contains("value5")); + assertEquals("value4", request.getParameter("field4")); + assertEquals("getValue", request.getParameter("getField")); + + List parameterMapKeys = new ArrayList(); + List parameterMapValues = new ArrayList(); + for (Iterator parameterMapIter = request.getParameterMap().keySet().iterator(); parameterMapIter.hasNext();) { + String key = (String) parameterMapIter.next(); + parameterMapKeys.add(key); + parameterMapValues.add(request.getParameterMap().get(key)); + } + assertEquals(3, parameterMapKeys.size()); + assertEquals(3, parameterMapValues.size()); + int field3Index = parameterMapKeys.indexOf("field3"); + int field4Index = parameterMapKeys.indexOf("field4"); + int getFieldIndex = parameterMapKeys.indexOf("getField"); + assertTrue(field3Index != -1); + assertTrue(field4Index != -1); + assertTrue(getFieldIndex != -1); + parameterValues = Arrays.asList((String[]) parameterMapValues.get(field3Index)); + assertEquals(1, parameterValues.size()); + assertTrue(parameterValues.contains("value3")); + parameterValues = Arrays.asList((String[]) parameterMapValues.get(field4Index)); + assertEquals(2, parameterValues.size()); + assertTrue(parameterValues.contains("value4")); + assertTrue(parameterValues.contains("value5")); + parameterValues = Arrays.asList((String[]) parameterMapValues.get(getFieldIndex)); + assertEquals(1, parameterValues.size()); + assertTrue(parameterValues.contains("getValue")); + + Set fileNames = new HashSet(); + Iterator fileIter = request.getFileNames(); + while (fileIter.hasNext()) { + fileNames.add(fileIter.next()); + } + assertEquals(3, fileNames.size()); + assertTrue(fileNames.contains("field1")); + assertTrue(fileNames.contains("field2")); + assertTrue(fileNames.contains("field2x")); + CommonsMultipartFile file1 = (CommonsMultipartFile) request.getFile("field1"); + CommonsMultipartFile file2 = (CommonsMultipartFile) request.getFile("field2"); + CommonsMultipartFile file2x = (CommonsMultipartFile) request.getFile("field2x"); + Map fileMap = request.getFileMap(); + assertEquals(3, fileMap.size()); + assertTrue(fileMap.containsKey("field1")); + assertTrue(fileMap.containsKey("field2")); + assertTrue(fileMap.containsKey("field2x")); + assertEquals(file1, fileMap.get("field1")); + assertEquals(file2, fileMap.get("field2")); + assertEquals(file2x, fileMap.get("field2x")); + + assertEquals("type1", file1.getContentType()); + assertEquals("type2", file2.getContentType()); + assertEquals("type2", file2x.getContentType()); + assertEquals("field1.txt", file1.getOriginalFilename()); + assertEquals("field2.txt", file2.getOriginalFilename()); + assertEquals("field2x.txt", file2x.getOriginalFilename()); + assertEquals("text1", new String(file1.getBytes())); + assertEquals("text2", new String(file2.getBytes())); + assertEquals(5, file1.getSize()); + assertEquals(5, file2.getSize()); + assertTrue(file1.getInputStream() instanceof ByteArrayInputStream); + assertTrue(file2.getInputStream() instanceof ByteArrayInputStream); + File transfer1 = new File("C:/transfer1"); + File transfer2 = new File("C:/transfer2"); + file1.transferTo(transfer1); + file2.transferTo(transfer2); + assertEquals(transfer1, ((MockFileItem) file1.getFileItem()).writtenFile); + assertEquals(transfer2, ((MockFileItem) file2.getFileItem()).writtenFile); + + MultipartTestBean1 mtb1 = new MultipartTestBean1(); + assertEquals(null, mtb1.getField1()); + assertEquals(null, mtb1.getField2()); + ServletRequestDataBinder binder = new ServletRequestDataBinder(mtb1, "mybean"); + binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor()); + binder.bind(request); + assertEquals(file1, mtb1.getField1()); + assertEquals(new String(file2.getBytes()), new String(mtb1.getField2())); + + MultipartTestBean2 mtb2 = new MultipartTestBean2(); + assertEquals(null, mtb2.getField1()); + assertEquals(null, mtb2.getField2()); + binder = new ServletRequestDataBinder(mtb2, "mybean"); + binder.registerCustomEditor(String.class, "field1", new StringMultipartFileEditor()); + binder.registerCustomEditor(String.class, "field2", new StringMultipartFileEditor("UTF-16")); + binder.bind(request); + assertEquals(new String(file1.getBytes()), mtb2.getField1()); + assertEquals(new String(file2.getBytes(), "UTF-16"), mtb2.getField2()); + + resolver.cleanupMultipart(request); + assertTrue(((MockFileItem) file1.getFileItem()).deleted); + assertTrue(((MockFileItem) file2.getFileItem()).deleted); + + resolver.setEmpty(true); + request = resolver.resolveMultipart(originalRequest); + binder.setBindEmptyMultipartFiles(false); + String firstBound = mtb2.getField1(); + binder.bind(request); + assertTrue(mtb2.getField1().length() > 0); + assertEquals(firstBound, mtb2.getField1()); + + request = resolver.resolveMultipart(originalRequest); + binder.setBindEmptyMultipartFiles(true); + binder.bind(request); + assertTrue(mtb2.getField1().length() == 0); + } + + public void testWithServletContextAndFilter() throws Exception { + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(new MockServletContext()); + wac.registerSingleton("filterMultipartResolver", MockCommonsMultipartResolver.class, new MutablePropertyValues()); + wac.getServletContext().setAttribute(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File("mytemp")); + wac.refresh(); + wac.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + CommonsMultipartResolver resolver = new CommonsMultipartResolver(wac.getServletContext()); + assertTrue(resolver.getFileItemFactory().getRepository().getAbsolutePath().endsWith("mytemp")); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + filterConfig.addInitParameter("class", "notWritable"); + filterConfig.addInitParameter("unknownParam", "someValue"); + final MultipartFilter filter = new MultipartFilter(); + filter.init(filterConfig); + + final List files = new ArrayList(); + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { + MultipartHttpServletRequest request = (MultipartHttpServletRequest) servletRequest; + files.addAll(request.getFileMap().values()); + } + }; + + FilterChain filterChain2 = new PassThroughFilterChain(filter, filterChain); + + MockHttpServletRequest originalRequest = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + originalRequest.setMethod("POST"); + originalRequest.setContentType("multipart/form-data"); + originalRequest.addHeader("Content-type", "multipart/form-data"); + filter.doFilter(originalRequest, response, filterChain2); + + CommonsMultipartFile file1 = (CommonsMultipartFile) files.get(0); + CommonsMultipartFile file2 = (CommonsMultipartFile) files.get(1); + assertTrue(((MockFileItem) file1.getFileItem()).deleted); + assertTrue(((MockFileItem) file2.getFileItem()).deleted); + } + + public void testWithServletContextAndFilterWithCustomBeanName() throws Exception { + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.setServletContext(new MockServletContext()); + wac.refresh(); + wac.registerSingleton("myMultipartResolver", MockCommonsMultipartResolver.class, new MutablePropertyValues()); + wac.getServletContext().setAttribute(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File("mytemp")); + wac.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + CommonsMultipartResolver resolver = new CommonsMultipartResolver(wac.getServletContext()); + assertTrue(resolver.getFileItemFactory().getRepository().getAbsolutePath().endsWith("mytemp")); + + MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); + filterConfig.addInitParameter("multipartResolverBeanName", "myMultipartResolver"); + + final List files = new ArrayList(); + FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest originalRequest, ServletResponse response) { + if (originalRequest instanceof MultipartHttpServletRequest) { + MultipartHttpServletRequest request = (MultipartHttpServletRequest) originalRequest; + files.addAll(request.getFileMap().values()); + } + } + }; + + MultipartFilter filter = new MultipartFilter() { + private boolean invoked = false; + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + super.doFilterInternal(request, response, filterChain); + super.doFilterInternal(request, response, filterChain); + if (invoked) { + throw new ServletException("Should not have been invoked twice"); + } + invoked = true; + } + }; + filter.init(filterConfig); + + MockHttpServletRequest originalRequest = new MockHttpServletRequest(); + originalRequest.setMethod("POST"); + originalRequest.setContentType("multipart/form-data"); + originalRequest.addHeader("Content-type", "multipart/form-data"); + HttpServletResponse response = new MockHttpServletResponse(); + filter.doFilter(originalRequest, response, filterChain); + CommonsMultipartFile file1 = (CommonsMultipartFile) files.get(0); + CommonsMultipartFile file2 = (CommonsMultipartFile) files.get(1); + assertTrue(((MockFileItem) file1.getFileItem()).deleted); + assertTrue(((MockFileItem) file2.getFileItem()).deleted); + } + + + public static class MockCommonsMultipartResolver extends CommonsMultipartResolver { + + private boolean empty; + + protected void setEmpty(boolean empty) { + this.empty = empty; + } + + protected FileUpload newFileUpload(FileItemFactory fileItemFactory) { + return new ServletFileUpload() { + public List parseRequest(HttpServletRequest request) { + if (request instanceof MultipartHttpServletRequest) { + throw new IllegalStateException("Already a multipart request"); + } + List fileItems = new ArrayList(); + MockFileItem fileItem1 = new MockFileItem( + "field1", "type1", empty ? "" : "field1.txt", empty ? "" : "text1"); + MockFileItem fileItem2 = new MockFileItem( + "field2", "type2", empty ? "" : "C:/field2.txt", empty ? "" : "text2"); + MockFileItem fileItem2x = new MockFileItem( + "field2x", "type2", empty ? "" : "C:\\field2x.txt", empty ? "" : "text2"); + MockFileItem fileItem3 = new MockFileItem("field3", null, null, "value3"); + MockFileItem fileItem4 = new MockFileItem("field4", null, null, "value4"); + MockFileItem fileItem5 = new MockFileItem("field4", null, null, "value5"); + fileItems.add(fileItem1); + fileItems.add(fileItem2); + fileItems.add(fileItem2x); + fileItems.add(fileItem3); + fileItems.add(fileItem4); + fileItems.add(fileItem5); + return fileItems; + } + }; + } + } + + + private static class MockFileItem implements FileItem { + + private String fieldName; + private String contentType; + private String name; + private String value; + + private File writtenFile; + private boolean deleted; + + public MockFileItem(String fieldName, String contentType, String name, String value) { + this.fieldName = fieldName; + this.contentType = contentType; + this.name = name; + this.value = value; + } + + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(value.getBytes()); + } + + public String getContentType() { + return contentType; + } + + public String getName() { + return name; + } + + public boolean isInMemory() { + return true; + } + + public long getSize() { + return value.length(); + } + + public byte[] get() { + return value.getBytes(); + } + + public String getString(String encoding) throws UnsupportedEncodingException { + return new String(get(), encoding); + } + + public String getString() { + return value; + } + + public void write(File file) throws Exception { + this.writtenFile = file; + } + + public File getWrittenFile() { + return writtenFile; + } + + public void delete() { + this.deleted = true; + } + + public boolean isDeleted() { + return deleted; + } + + public String getFieldName() { + return fieldName; + } + + public void setFieldName(String s) { + this.fieldName = s; + } + + public boolean isFormField() { + return (this.name == null); + } + + public void setFormField(boolean b) { + throw new UnsupportedOperationException(); + } + + public OutputStream getOutputStream() throws IOException { + throw new UnsupportedOperationException(); + } + } + + + public class MultipartTestBean1 { + + private MultipartFile field1; + private byte[] field2; + + public void setField1(MultipartFile field1) { + this.field1 = field1; + } + + public MultipartFile getField1() { + return field1; + } + + public void setField2(byte[] field2) { + this.field2 = field2; + } + + public byte[] getField2() { + return field2; + } + } + + + public class MultipartTestBean2 { + + private String field1; + private String field2; + + public void setField1(String field1) { + this.field1 = field1; + } + + public String getField1() { + return field1; + } + + public void setField2(String field2) { + this.field2 = field2; + } + + public String getField2() { + return field2; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/support/ByteArrayMultipartFileEditorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/support/ByteArrayMultipartFileEditorTests.java new file mode 100644 index 00000000000..169f2477e01 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/multipart/support/ByteArrayMultipartFileEditorTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.multipart.support; + +import java.io.IOException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.web.multipart.MultipartFile; + +/** + * @author Rick Evans + */ +public final class ByteArrayMultipartFileEditorTests extends TestCase { + + public void testSetValueAsByteArray() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + String expectedValue = "Shumwere, shumhow, a shuck ish washing you. - Drunken Far Side"; + editor.setValue(expectedValue.getBytes()); + assertEquals(expectedValue, editor.getAsText()); + } + + public void testSetValueAsString() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + String expectedValue = "'Green Wing' - classic British comedy"; + editor.setValue(expectedValue); + assertEquals(expectedValue, editor.getAsText()); + } + + public void testSetValueAsCustomObjectInvokesToString() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + final String expectedValue = "'Green Wing' - classic British comedy"; + Object object = new Object() { + public String toString() { + return expectedValue; + } + }; + editor.setValue(object); + assertEquals(expectedValue, editor.getAsText()); + } + + public void testSetValueAsNullGetsBackEmptyString() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + editor.setValue(null); + assertEquals("", editor.getAsText()); + } + + public void testSetValueAsMultipartFile() throws Exception { + String expectedValue = "That is comforting to know"; + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + MockControl mock = MockControl.createControl(MultipartFile.class); + MultipartFile file = (MultipartFile) mock.getMock(); + file.getBytes(); + mock.setReturnValue(expectedValue.getBytes()); + mock.replay(); + editor.setValue(file); + assertEquals(expectedValue, editor.getAsText()); + mock.verify(); + } + + public void testSetValueAsMultipartFileWithBadBytes() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + MockControl mock = MockControl.createControl(MultipartFile.class); + MultipartFile file = (MultipartFile) mock.getMock(); + file.getBytes(); + mock.setThrowable(new IOException()); + mock.replay(); + try { + editor.setValue(file); + fail("Must have thrown an IllegalArgumentException: IOException thrown when reading MultipartFile bytes"); + } + catch (IllegalArgumentException expected) { + } + mock.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java new file mode 100644 index 00000000000..f7aa8c1aad8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java @@ -0,0 +1,504 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.Portlet; +import javax.portlet.PortletConfig; +import javax.portlet.PortletException; +import javax.portlet.PortletRequest; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.core.Ordered; +import org.springframework.mock.web.portlet.MockPortletConfig; +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartException; +import org.springframework.web.portlet.bind.PortletRequestBindingException; +import org.springframework.web.portlet.context.PortletRequestHandledEvent; +import org.springframework.web.portlet.context.StaticPortletApplicationContext; +import org.springframework.web.portlet.handler.ParameterHandlerMapping; +import org.springframework.web.portlet.handler.ParameterMappingInterceptor; +import org.springframework.web.portlet.handler.PortletModeHandlerMapping; +import org.springframework.web.portlet.handler.PortletModeParameterHandlerMapping; +import org.springframework.web.portlet.handler.SimpleMappingExceptionResolver; +import org.springframework.web.portlet.handler.SimplePortletHandlerAdapter; +import org.springframework.web.portlet.handler.SimplePortletPostProcessor; +import org.springframework.web.portlet.handler.UserRoleAuthorizationInterceptor; +import org.springframework.web.portlet.multipart.DefaultMultipartActionRequest; +import org.springframework.web.portlet.multipart.MultipartActionRequest; +import org.springframework.web.portlet.multipart.PortletMultipartResolver; +import org.springframework.web.portlet.mvc.Controller; +import org.springframework.web.portlet.mvc.SimpleControllerHandlerAdapter; + +/** + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class ComplexPortletApplicationContext extends StaticPortletApplicationContext { + + public void refresh() throws BeansException { + registerSingleton("standardHandlerAdapter", SimpleControllerHandlerAdapter.class); + registerSingleton("portletHandlerAdapter", SimplePortletHandlerAdapter.class); + registerSingleton("myHandlerAdapter", MyHandlerAdapter.class); + + registerSingleton("viewController", ViewController.class); + registerSingleton("editController", EditController.class); + registerSingleton("helpController1", HelpController1.class); + registerSingleton("helpController2", HelpController2.class); + registerSingleton("testController1", TestController1.class); + registerSingleton("testController2", TestController2.class); + registerSingleton("requestLocaleCheckingController", RequestLocaleCheckingController.class); + registerSingleton("localeContextCheckingController", LocaleContextCheckingController.class); + + registerSingleton("exceptionThrowingHandler1", ExceptionThrowingHandler.class); + registerSingleton("exceptionThrowingHandler2", ExceptionThrowingHandler.class); + registerSingleton("unknownHandler", Object.class); + + registerSingleton("myPortlet", MyPortlet.class); + registerSingleton("portletMultipartResolver", MockMultipartResolver.class); + registerSingleton("portletPostProcessor", SimplePortletPostProcessor.class); + registerSingleton("testListener", TestApplicationListener.class); + + ConstructorArgumentValues cvs = new ConstructorArgumentValues(); + cvs.addIndexedArgumentValue(0, new MockPortletContext()); + cvs.addIndexedArgumentValue(1, "complex"); + registerBeanDefinition("portletConfig", new RootBeanDefinition(MockPortletConfig.class, cvs, null)); + + UserRoleAuthorizationInterceptor userRoleInterceptor = new UserRoleAuthorizationInterceptor(); + userRoleInterceptor.setAuthorizedRoles(new String[] {"role1", "role2"}); + + ParameterHandlerMapping interceptingHandlerMapping = new ParameterHandlerMapping(); + interceptingHandlerMapping.setParameterName("interceptingParam"); + ParameterMappingInterceptor parameterMappingInterceptor = new ParameterMappingInterceptor(); + parameterMappingInterceptor.setParameterName("interceptingParam"); + + List interceptors = new ArrayList(); + interceptors.add(parameterMappingInterceptor); + interceptors.add(userRoleInterceptor); + interceptors.add(new MyHandlerInterceptor1()); + interceptors.add(new MyHandlerInterceptor2()); + + MutablePropertyValues pvs = new MutablePropertyValues(); + Map portletModeMap = new ManagedMap(); + portletModeMap.put("view", new RuntimeBeanReference("viewController")); + portletModeMap.put("edit", new RuntimeBeanReference("editController")); + pvs.addPropertyValue("portletModeMap", portletModeMap); + pvs.addPropertyValue("interceptors", interceptors); + registerSingleton("handlerMapping3", PortletModeHandlerMapping.class, pvs); + + pvs = new MutablePropertyValues(); + Map parameterMap = new ManagedMap(); + parameterMap.put("test1", new RuntimeBeanReference("testController1")); + parameterMap.put("test2", new RuntimeBeanReference("testController2")); + parameterMap.put("requestLocaleChecker", new RuntimeBeanReference("requestLocaleCheckingController")); + parameterMap.put("contextLocaleChecker", new RuntimeBeanReference("localeContextCheckingController")); + parameterMap.put("exception1", new RuntimeBeanReference("exceptionThrowingHandler1")); + parameterMap.put("exception2", new RuntimeBeanReference("exceptionThrowingHandler2")); + parameterMap.put("myPortlet", new RuntimeBeanReference("myPortlet")); + parameterMap.put("unknown", new RuntimeBeanReference("unknownHandler")); + pvs.addPropertyValue("parameterMap", parameterMap); + pvs.addPropertyValue("parameterName", "myParam"); + pvs.addPropertyValue("order", "2"); + registerSingleton("handlerMapping2", ParameterHandlerMapping.class, pvs); + + pvs = new MutablePropertyValues(); + Map innerMap = new ManagedMap(); + innerMap.put("help1", new RuntimeBeanReference("helpController1")); + innerMap.put("help2", new RuntimeBeanReference("helpController2")); + Map outerMap = new ManagedMap(); + outerMap.put("help", innerMap); + pvs.addPropertyValue("portletModeParameterMap", outerMap); + pvs.addPropertyValue("order", "1"); + registerSingleton("handlerMapping1", PortletModeParameterHandlerMapping.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", "1"); + pvs.addPropertyValue("exceptionMappings", + "java.lang.IllegalAccessException=failed-illegalaccess\n" + + "PortletRequestBindingException=failed-binding\n" + + "UnavailableException=failed-unavailable"); + pvs.addPropertyValue("defaultErrorView", "failed-default-1"); + registerSingleton("exceptionResolver", SimpleMappingExceptionResolver.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", "0"); + pvs.addPropertyValue("exceptionMappings", + "java.lang.Exception=failed-exception\n" + + "java.lang.RuntimeException=failed-runtime"); + List mappedHandlers = new ManagedList(); + mappedHandlers.add(new RuntimeBeanReference("exceptionThrowingHandler1")); + pvs.addPropertyValue("mappedHandlers", mappedHandlers); + pvs.addPropertyValue("defaultErrorView", "failed-default-0"); + registerSingleton("handlerExceptionResolver", SimpleMappingExceptionResolver.class, pvs); + + addMessage("test", Locale.ENGLISH, "test message"); + addMessage("test", Locale.CANADA, "Canadian & test message"); + addMessage("test.args", Locale.ENGLISH, "test {0} and {1}"); + + super.refresh(); + } + + + public static class TestController1 implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) { + response.setRenderParameter("result", "test1-action"); + } + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) throws Exception { + return null; + } + } + + + public static class TestController2 implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) {} + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) throws Exception { + response.setProperty("result", "test2-view"); + return null; + } + } + + + public static class ViewController implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) {} + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) throws Exception { + return new ModelAndView("someViewName", "result", "view was here"); + } + } + + + public static class EditController implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) { + response.setRenderParameter("param", "edit was here"); + } + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) throws Exception { + return new ModelAndView(request.getParameter("param")); + } + } + + + public static class HelpController1 implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) { + response.setRenderParameter("param", "help1 was here"); + } + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) throws Exception { + return new ModelAndView("help1-view"); + } + } + + + public static class HelpController2 implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) { + response.setRenderParameter("param", "help2 was here"); + } + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) throws Exception { + return new ModelAndView("help2-view"); + } + } + + public static class RequestLocaleCheckingController implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) throws PortletException { + if (!Locale.CANADA.equals(request.getLocale())) { + throw new PortletException("Incorrect Locale in ActionRequest"); + } + } + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) + throws PortletException, IOException { + if (!Locale.CANADA.equals(request.getLocale())) { + throw new PortletException("Incorrect Locale in RenderRequest"); + } + response.getWriter().write("locale-ok"); + return null; + } + } + + + public static class LocaleContextCheckingController implements Controller { + + public void handleActionRequest(ActionRequest request, ActionResponse response) throws PortletException { + if (!Locale.CANADA.equals(LocaleContextHolder.getLocale())) { + throw new PortletException("Incorrect Locale in LocaleContextHolder"); + } + } + + public ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response) + throws PortletException, IOException { + if (!Locale.CANADA.equals(LocaleContextHolder.getLocale())) { + throw new PortletException("Incorrect Locale in LocaleContextHolder"); + } + response.getWriter().write("locale-ok"); + return null; + } + } + + + public static class MyPortlet implements Portlet { + + private PortletConfig portletConfig; + + public void init(PortletConfig portletConfig) throws PortletException { + this.portletConfig = portletConfig; + } + + public void processAction(ActionRequest request, ActionResponse response) throws PortletException { + response.setRenderParameter("result", "myPortlet action called"); + } + + public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException { + response.getWriter().write("myPortlet was here"); + } + + public PortletConfig getPortletConfig() { + return this.portletConfig; + } + + public void destroy() { + this.portletConfig = null; + } + } + + + public static interface MyHandler { + + public void doSomething(PortletRequest request) throws Exception; + } + + + public static class ExceptionThrowingHandler implements MyHandler { + + public void doSomething(PortletRequest request) throws Exception { + if (request.getParameter("fail") != null) { + throw new ModelAndViewDefiningException(new ModelAndView("failed-modelandview")); + } + if (request.getParameter("access") != null) { + throw new IllegalAccessException("portlet-illegalaccess"); + } + if (request.getParameter("binding") != null) { + throw new PortletRequestBindingException("portlet-binding"); + } + if (request.getParameter("generic") != null) { + throw new Exception("portlet-generic"); + } + if (request.getParameter("runtime") != null) { + throw new RuntimeException("portlet-runtime"); + } + throw new IllegalArgumentException("illegal argument"); + } + } + + + public static class MyHandlerAdapter implements HandlerAdapter, Ordered { + + public int getOrder() { + return 99; + } + + public boolean supports(Object handler) { + return handler != null && MyHandler.class.isAssignableFrom(handler.getClass()); + } + + public void handleAction(ActionRequest request, ActionResponse response, Object delegate) throws Exception { + ((MyHandler) delegate).doSomething(request); + } + + public ModelAndView handleRender(RenderRequest request, RenderResponse response, Object delegate) throws Exception { + ((MyHandler) delegate).doSomething(request); + return null; + } + } + + + public static class MyHandlerInterceptor1 implements HandlerInterceptor { + + public boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler) { + return true; + } + + public void afterActionCompletion(ActionRequest request, ActionResponse response, Object handler, Exception ex) { + } + + public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler) + throws PortletException { + if (request.getAttribute("test2-remove-never") != null) { + throw new PortletException("Wrong interceptor order"); + } + request.setAttribute("test1-remove-never", "test1-remove-never"); + request.setAttribute("test1-remove-post", "test1-remove-post"); + request.setAttribute("test1-remove-after", "test1-remove-after"); + return true; + } + + public void postHandleRender( + RenderRequest request, RenderResponse response, Object handler, ModelAndView modelAndView) + throws PortletException { + if (request.getAttribute("test2-remove-post") != null) { + throw new PortletException("Wrong interceptor order"); + } + if (!"test1-remove-post".equals(request.getAttribute("test1-remove-post"))) { + throw new PortletException("Incorrect request attribute"); + } + request.removeAttribute("test1-remove-post"); + } + + public void afterRenderCompletion( + RenderRequest request, RenderResponse response, Object handler, Exception ex) + throws PortletException { + if (request.getAttribute("test2-remove-after") != null) { + throw new PortletException("Wrong interceptor order"); + } + request.removeAttribute("test1-remove-after"); + } + } + + + public static class MyHandlerInterceptor2 implements HandlerInterceptor { + + public boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler) { + return true; + } + + public void afterActionCompletion(ActionRequest request, ActionResponse response, Object handler, Exception ex) { + } + + public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler) + throws PortletException { + if (request.getAttribute("test1-remove-post") == null) { + throw new PortletException("Wrong interceptor order"); + } + if ("true".equals(request.getParameter("abort"))) { + return false; + } + request.setAttribute("test2-remove-never", "test2-remove-never"); + request.setAttribute("test2-remove-post", "test2-remove-post"); + request.setAttribute("test2-remove-after", "test2-remove-after"); + return true; + } + + public void postHandleRender( + RenderRequest request, RenderResponse response, Object handler, ModelAndView modelAndView) + throws PortletException { + if ("true".equals(request.getParameter("noView"))) { + modelAndView.clear(); + } + if (request.getAttribute("test1-remove-post") == null) { + throw new PortletException("Wrong interceptor order"); + } + if (!"test2-remove-post".equals(request.getAttribute("test2-remove-post"))) { + throw new PortletException("Incorrect request attribute"); + } + request.removeAttribute("test2-remove-post"); + } + + public void afterRenderCompletion( + RenderRequest request, RenderResponse response, Object handler, Exception ex) + throws Exception { + if (request.getAttribute("test1-remove-after") == null) { + throw new PortletException("Wrong interceptor order"); + } + request.removeAttribute("test2-remove-after"); + } + } + + + public static class MultipartCheckingHandler implements MyHandler { + + public void doSomething(PortletRequest request) throws PortletException, IllegalAccessException { + if (!(request instanceof MultipartActionRequest)) { + throw new PortletException("Not in a MultipartActionRequest"); + } + } + } + + + public static class MockMultipartResolver implements PortletMultipartResolver { + + public boolean isMultipart(ActionRequest request) { + return true; + } + + public MultipartActionRequest resolveMultipart(ActionRequest request) throws MultipartException { + if (request.getAttribute("fail") != null) { + throw new MaxUploadSizeExceededException(1000); + } + if (request instanceof MultipartActionRequest) { + throw new IllegalStateException("Already a multipart request"); + } + if (request.getAttribute("resolved") != null) { + throw new IllegalStateException("Already resolved"); + } + request.setAttribute("resolved", Boolean.TRUE); + Map files = new HashMap(); + files.put("someFile", "someFile"); + Map params = new HashMap(); + params.put("someParam", "someParam"); + return new DefaultMultipartActionRequest(request, files, params); + } + + public void cleanupMultipart(MultipartActionRequest request) { + if (request.getAttribute("cleanedUp") != null) { + throw new IllegalStateException("Already cleaned up"); + } + request.setAttribute("cleanedUp", Boolean.TRUE); + } + } + + + public static class TestApplicationListener implements ApplicationListener { + + public int counter = 0; + + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof PortletRequestHandledEvent) { + this.counter++; + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java new file mode 100644 index 00000000000..8cef7bb6ee0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java @@ -0,0 +1,989 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet; + +import java.io.IOException; +import java.util.Locale; +import java.util.Map; + +import javax.portlet.PortletContext; +import javax.portlet.PortletException; +import javax.portlet.PortletMode; +import javax.portlet.PortletSecurityException; +import javax.portlet.PortletSession; +import javax.portlet.UnavailableException; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.mock.web.portlet.MockActionRequest; +import org.springframework.mock.web.portlet.MockActionResponse; +import org.springframework.mock.web.portlet.MockPortletConfig; +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.mock.web.portlet.MockPortletSession; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.portlet.context.PortletApplicationContextUtils; +import org.springframework.web.portlet.context.PortletConfigAwareBean; +import org.springframework.web.portlet.context.PortletContextAwareBean; +import org.springframework.web.portlet.handler.PortletSessionRequiredException; +import org.springframework.web.portlet.multipart.MultipartActionRequest; +import org.springframework.web.portlet.multipart.PortletMultipartResolver; +import org.springframework.web.servlet.ViewRendererServlet; +import org.springframework.web.servlet.view.InternalResourceView; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + * @author Dan McCallum + */ +public class DispatcherPortletTests extends TestCase { + + private MockPortletConfig simplePortletConfig; + + private MockPortletConfig complexPortletConfig; + + private DispatcherPortlet simpleDispatcherPortlet; + + private DispatcherPortlet complexDispatcherPortlet; + + + protected void setUp() throws PortletException { + simplePortletConfig = new MockPortletConfig(new MockPortletContext(), "simple"); + complexPortletConfig = new MockPortletConfig(simplePortletConfig.getPortletContext(), "complex"); + complexPortletConfig.addInitParameter("publishContext", "false"); + + simpleDispatcherPortlet = new DispatcherPortlet(); + simpleDispatcherPortlet.setContextClass(SimplePortletApplicationContext.class); + simpleDispatcherPortlet.init(simplePortletConfig); + + complexDispatcherPortlet = new DispatcherPortlet(); + complexDispatcherPortlet.setContextClass(ComplexPortletApplicationContext.class); + complexDispatcherPortlet.setNamespace("test"); + complexDispatcherPortlet.addRequiredProperty("publishContext"); + complexDispatcherPortlet.init(complexPortletConfig); + } + + private PortletContext getPortletContext() { + return complexPortletConfig.getPortletContext(); + } + + + public void testDispatcherPortletGetPortletNameDoesNotFailWithoutConfig() { + DispatcherPortlet dp = new DispatcherPortlet(); + assertEquals(null, dp.getPortletConfig()); + assertEquals(null, dp.getPortletName()); + assertEquals(null, dp.getPortletContext()); + } + + public void testDispatcherPortlets() { + assertTrue("Correct namespace", + ("simple" + FrameworkPortlet.DEFAULT_NAMESPACE_SUFFIX).equals(simpleDispatcherPortlet.getNamespace())); + assertTrue("Correct attribute", + (FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "simple").equals(simpleDispatcherPortlet.getPortletContextAttributeName())); + assertTrue("Context published", + simpleDispatcherPortlet.getPortletApplicationContext() == + getPortletContext().getAttribute(FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "simple")); + + assertTrue("Correct namespace", "test".equals(complexDispatcherPortlet.getNamespace())); + assertTrue("Correct attribute", + (FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "complex").equals(complexDispatcherPortlet.getPortletContextAttributeName())); + assertTrue("Context not published", + getPortletContext().getAttribute(FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "complex") == null); + } + + public void testSimpleValidActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("action", "form"); + request.setParameter("age", "29"); + simpleDispatcherPortlet.processAction(request, response); + String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertNull(exceptionParam); + SimplePortletApplicationContext ac = (SimplePortletApplicationContext)simpleDispatcherPortlet.getPortletApplicationContext(); + String commandAttribute = ac.getRenderCommandSessionAttributeName(); + TestBean testBean = (TestBean) request.getPortletSession().getAttribute(commandAttribute); + assertEquals(39, testBean.getAge()); + } + + public void testSimpleInvalidActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("action", "invalid"); + simpleDispatcherPortlet.processAction(request, response); + String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertNotNull(exceptionParam); + assertTrue(exceptionParam.startsWith(UnavailableException.class.getName())); + } + + public void testSimpleFormViewNoBindOnNewForm() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("action", "form"); + request.setParameter("age", "29"); + simpleDispatcherPortlet.doDispatch(request, response); + assertEquals("5", response.getContentAsString()); + } + + public void testSimpleFormViewBindOnNewForm() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("action", "form-bind"); + request.setParameter("age", "29"); + simpleDispatcherPortlet.doDispatch(request, response); + assertEquals("34", response.getContentAsString()); + } + + public void testSimpleFormViewWithSessionAndBindOnNewForm() throws Exception { + MockRenderRequest renderRequest = new MockRenderRequest(); + MockRenderResponse renderResponse = new MockRenderResponse(); + renderRequest.setParameter("action", "form-session-bind"); + renderRequest.setParameter("age", "30"); + TestBean testBean = new TestBean(); + testBean.setAge(40); + SimplePortletApplicationContext ac = + (SimplePortletApplicationContext)simpleDispatcherPortlet.getPortletApplicationContext(); + String formAttribute = ac.getFormSessionAttributeName(); + PortletSession session = new MockPortletSession(); + session.setAttribute(formAttribute, testBean); + renderRequest.setSession(session); + simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); + assertEquals("35", renderResponse.getContentAsString()); + } + + public void testSimpleFormViewWithSessionNoBindOnNewForm() throws Exception { + MockActionRequest actionRequest = new MockActionRequest(); + MockActionResponse actionResponse = new MockActionResponse(); + actionRequest.setSession(new MockPortletSession()); + actionRequest.setParameter("action", "form-session-nobind"); + actionRequest.setParameter("age", "27"); + simpleDispatcherPortlet.processAction(actionRequest, actionResponse); + Map renderParameters = actionResponse.getRenderParameterMap(); + + MockRenderRequest renderRequest = new MockRenderRequest(); + MockRenderResponse renderResponse = new MockRenderResponse(); + renderRequest.setParameters(renderParameters); + renderRequest.setParameter("action", "form-session-nobind"); + renderRequest.setParameter("age", "30"); + renderRequest.setSession(actionRequest.getPortletSession()); + simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); + assertEquals("finished42", renderResponse.getContentAsString()); + } + + public void testSimpleRequiredSessionFormWithoutSession() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("action", "form-session-bind"); + try { + simpleDispatcherPortlet.doDispatch(request, response); + fail("Should have thrown PortletSessionRequiredException"); + } + catch (PortletSessionRequiredException ex) { + // expected + } + } + + public void testSimpleFormSubmission() throws Exception { + MockActionRequest actionRequest = new MockActionRequest(); + MockActionResponse actionResponse = new MockActionResponse(); + actionRequest.setParameter("action", "form"); + actionRequest.setParameter("age", "29"); + simpleDispatcherPortlet.processAction(actionRequest, actionResponse); + + MockRenderRequest renderRequest = new MockRenderRequest(); + MockRenderResponse renderResponse = new MockRenderResponse(); + renderRequest.setSession(actionRequest.getPortletSession()); + renderRequest.setParameters(actionResponse.getRenderParameterMap()); + renderRequest.setParameter("action", "form"); + simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); + assertEquals("finished44", renderResponse.getContentAsString()); + } + + public void testSimpleFormSubmissionWithValidationError() throws Exception { + MockActionRequest actionRequest = new MockActionRequest(); + MockActionResponse actionResponse = new MockActionResponse(); + actionRequest.setParameter("action", "form"); + actionRequest.setParameter("age", "XX"); + simpleDispatcherPortlet.processAction(actionRequest, actionResponse); + + MockRenderRequest renderRequest = new MockRenderRequest(); + MockRenderResponse renderResponse = new MockRenderResponse(); + renderRequest.setSession(actionRequest.getPortletSession()); + renderRequest.setParameters(actionResponse.getRenderParameterMap()); + renderRequest.setParameter("action", "form"); + simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); + assertEquals("5", renderResponse.getContentAsString()); + } + + public void testSimpleInvalidRenderRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("action", "invalid"); + try { + simpleDispatcherPortlet.doDispatch(request, response); + fail("Should have thrown UnavailableException"); + } + catch (UnavailableException ex) { + // expected + } + } + + public void testPortletModeParameterMappingHelp1() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.HELP); + request.setParameter("action", "help1"); + complexDispatcherPortlet.processAction(request, response); + String param = response.getRenderParameter("param"); + assertEquals("help1 was here", param); + } + + public void testPortletModeParameterMappingHelp2() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.HELP); + request.setParameter("action", "help2"); + complexDispatcherPortlet.processAction(request, response); + String param = response.getRenderParameter("param"); + assertEquals("help2 was here", param); + } + + public void testPortletModeParameterMappingInvalidHelpActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.HELP); + request.setParameter("action", "help3"); + complexDispatcherPortlet.processAction(request, response); + String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertNotNull(exceptionParam); + assertTrue(exceptionParam.startsWith(UnavailableException.class.getName())); + } + + public void testPortletModeParameterMappingInvalidHelpRenderRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.HELP); + request.setParameter("action", "help3"); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + assertTrue(model.get("exception").getClass().equals(UnavailableException.class)); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-unavailable", view.getBeanName()); + } + + public void testPortletModeMappingValidEditActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.EDIT); + request.addUserRole("role1"); + request.setParameter("action", "not mapped"); + request.setParameter("myParam", "not mapped"); + complexDispatcherPortlet.processAction(request, response); + assertEquals("edit was here", response.getRenderParameter("param")); + } + + public void testPortletModeMappingEditActionRequestWithUnauthorizedUserRole() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.EDIT); + request.addUserRole("role3"); + request.setParameter("action", "not mapped"); + request.setParameter("myParam", "not mapped"); + complexDispatcherPortlet.processAction(request, response); + String exception = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertNotNull(exception); + String name = PortletSecurityException.class.getName(); + assertTrue(exception.startsWith(name)); + } + + public void testPortletModeMappingValidViewRenderRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role2"); + request.setParameter("action", "not mapped"); + request.setParameter("myParam", "not mapped"); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + assertEquals("view was here", model.get("result")); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("someViewName", view.getBeanName()); + } + + public void testPortletModeMappingViewRenderRequestWithUnauthorizedUserRole() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role3"); + request.setParameter("action", "not mapped"); + request.setParameter("myParam", "not mapped"); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + Exception exception = (Exception) model.get("exception"); + assertNotNull(exception); + assertTrue(exception.getClass().equals(PortletSecurityException.class)); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-default-1", view.getBeanName()); + } + + public void testParameterMappingValidActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.EDIT); + request.setParameter("action", "not mapped"); + request.setParameter("myParam", "test1"); + complexDispatcherPortlet.processAction(request, response); + assertEquals("test1-action", response.getRenderParameter("result")); + } + + public void testParameterMappingValidRenderRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + request.setParameter("action", "not mapped"); + request.setParameter("myParam", "test2"); + complexDispatcherPortlet.doDispatch(request, response); + assertEquals("test2-view", response.getProperty("result")); + } + + public void testUnknownHandlerActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("myParam", "unknown"); + complexDispatcherPortlet.processAction(request, response); + String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertNotNull(exceptionParam); + assertTrue(exceptionParam.startsWith(PortletException.class.getName())); + assertTrue(exceptionParam.indexOf("No adapter for handler") != -1); + } + + public void testUnknownHandlerRenderRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("myParam", "unknown"); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + Exception exception = (Exception)model.get("exception"); + assertTrue(exception.getClass().equals(PortletException.class)); + assertTrue(exception.getMessage().indexOf("No adapter for handler") != -1); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-default-1", view.getBeanName()); + } + + public void testNoDetectAllHandlerMappingsWithPortletModeActionRequest() throws Exception { + DispatcherPortlet complexDispatcherPortlet = new DispatcherPortlet(); + complexDispatcherPortlet.setContextClass(ComplexPortletApplicationContext.class); + complexDispatcherPortlet.setNamespace("test"); + complexDispatcherPortlet.setDetectAllHandlerMappings(false); + complexDispatcherPortlet.init(new MockPortletConfig(getPortletContext(), "complex")); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.EDIT); + complexDispatcherPortlet.processAction(request, response); + String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertNotNull(exceptionParam); + assertTrue(exceptionParam.startsWith(UnavailableException.class.getName())); + } + + public void testNoDetectAllHandlerMappingsWithParameterRenderRequest() throws Exception { + DispatcherPortlet complexDispatcherPortlet = new DispatcherPortlet(); + complexDispatcherPortlet.setContextClass(ComplexPortletApplicationContext.class); + complexDispatcherPortlet.setNamespace("test"); + complexDispatcherPortlet.setDetectAllHandlerMappings(false); + complexDispatcherPortlet.init(new MockPortletConfig(getPortletContext(), "complex")); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("myParam", "test1"); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + Exception exception = (Exception) model.get("exception"); + assertTrue(exception.getClass().equals(UnavailableException.class)); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-unavailable", view.getBeanName()); + } + + public void testExistingMultipartRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.EDIT); + ComplexPortletApplicationContext.MockMultipartResolver multipartResolver = + (ComplexPortletApplicationContext.MockMultipartResolver) + complexDispatcherPortlet.getPortletApplicationContext().getBean("portletMultipartResolver"); + MultipartActionRequest multipartRequest = multipartResolver.resolveMultipart(request); + complexDispatcherPortlet.processAction(multipartRequest, response); + multipartResolver.cleanupMultipart(multipartRequest); + assertNotNull(request.getAttribute("cleanedUp")); + } + + public void testMultipartResolutionFailed() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.EDIT); + request.addUserRole("role1"); + request.setAttribute("fail", Boolean.TRUE); + complexDispatcherPortlet.processAction(request, response); + String exception = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertTrue(exception.startsWith(MaxUploadSizeExceededException.class.getName())); + } + + public void testActionRequestHandledEvent() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + complexDispatcherPortlet.processAction(request, response); + ComplexPortletApplicationContext.TestApplicationListener listener = + (ComplexPortletApplicationContext.TestApplicationListener) + complexDispatcherPortlet.getPortletApplicationContext().getBean("testListener"); + assertEquals(1, listener.counter); + } + + public void testRenderRequestHandledEvent() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + ComplexPortletApplicationContext.TestApplicationListener listener = + (ComplexPortletApplicationContext.TestApplicationListener) + complexDispatcherPortlet.getPortletApplicationContext().getBean("testListener"); + assertEquals(1, listener.counter); + } + + public void testPublishEventsOff() throws Exception { + complexDispatcherPortlet.setPublishEvents(false); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("action", "checker"); + complexDispatcherPortlet.processAction(request, response); + ComplexPortletApplicationContext.TestApplicationListener listener = + (ComplexPortletApplicationContext.TestApplicationListener) + complexDispatcherPortlet.getPortletApplicationContext().getBean("testListener"); + assertEquals(0, listener.counter); + } + + public void testCorrectLocaleInRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("myParam", "requestLocaleChecker"); + request.addPreferredLocale(Locale.CANADA); + complexDispatcherPortlet.doDispatch(request, response); + assertEquals("locale-ok", response.getContentAsString()); + } + + public void testIncorrectLocaleInRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("myParam", "requestLocaleChecker"); + request.addPreferredLocale(Locale.ENGLISH); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + Exception exception = (Exception) model.get("exception"); + assertTrue(exception.getClass().equals(PortletException.class)); + assertEquals("Incorrect Locale in RenderRequest", exception.getMessage()); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-default-1", view.getBeanName()); + } + + public void testCorrectLocaleInLocaleContextHolder() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("myParam", "contextLocaleChecker"); + request.addPreferredLocale(Locale.CANADA); + complexDispatcherPortlet.doDispatch(request, response); + assertEquals("locale-ok", response.getContentAsString()); + } + + public void testIncorrectLocaleInLocalContextHolder() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("myParam", "contextLocaleChecker"); + request.addPreferredLocale(Locale.ENGLISH); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + Exception exception = (Exception) model.get("exception"); + assertTrue(exception.getClass().equals(PortletException.class)); + assertEquals("Incorrect Locale in LocaleContextHolder", exception.getMessage()); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-default-1", view.getBeanName()); + } + + public void testHandlerInterceptorNoAbort() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role1"); + request.addParameter("abort", "false"); + complexDispatcherPortlet.doDispatch(request, response); + assertTrue(request.getAttribute("test1-remove-never") != null); + assertTrue(request.getAttribute("test1-remove-post") == null); + assertTrue(request.getAttribute("test1-remove-after") == null); + assertTrue(request.getAttribute("test2-remove-never") != null); + assertTrue(request.getAttribute("test2-remove-post") == null); + assertTrue(request.getAttribute("test2-remove-after") == null); + } + + public void testHandlerInterceptorAbort() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role1"); + request.addParameter("abort", "true"); + complexDispatcherPortlet.doDispatch(request, response); + assertTrue(request.getAttribute("test1-remove-never") != null); + assertTrue(request.getAttribute("test1-remove-post") != null); + assertTrue(request.getAttribute("test1-remove-after") == null); + assertTrue(request.getAttribute("test2-remove-never") == null); + assertTrue(request.getAttribute("test2-remove-post") == null); + assertTrue(request.getAttribute("test2-remove-after") == null); + } + + public void testHandlerInterceptorNotClearingModelAndView() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role1"); + request.addParameter("noView", "false"); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + assertEquals("view was here", model.get("result")); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("someViewName", view.getBeanName()); + } + + public void testHandlerInterceptorClearingModelAndView() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role1"); + request.addParameter("noView", "true"); + complexDispatcherPortlet.doDispatch(request, response); + Map model = (Map) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE); + assertNull(model); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertNull(view); + } + + public void testParameterMappingInterceptorWithCorrectParam() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role1"); + request.addParameter("interceptingParam", "test1"); + complexDispatcherPortlet.processAction(request, response); + assertEquals("test1", response.getRenderParameter("interceptingParam")); + } + + public void testParameterMappingInterceptorWithIncorrectParam() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setPortletMode(PortletMode.VIEW); + request.addUserRole("role1"); + request.addParameter("incorrect", "test1"); + complexDispatcherPortlet.processAction(request, response); + assertNull(response.getRenderParameter("incorrect")); + assertNull(response.getRenderParameter("interceptingParam")); + } + + public void testPortletHandlerAdapterActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("myParam", "myPortlet"); + complexDispatcherPortlet.processAction(request, response); + assertEquals("myPortlet action called", response.getRenderParameter("result")); + ComplexPortletApplicationContext.MyPortlet myPortlet = + (ComplexPortletApplicationContext.MyPortlet) complexDispatcherPortlet.getPortletApplicationContext().getBean("myPortlet"); + assertEquals("complex", myPortlet.getPortletConfig().getPortletName()); + assertEquals(getPortletContext(), myPortlet.getPortletConfig().getPortletContext()); + assertEquals(complexDispatcherPortlet.getPortletContext(), myPortlet.getPortletConfig().getPortletContext()); + complexDispatcherPortlet.destroy(); + assertNull(myPortlet.getPortletConfig()); + } + + public void testPortletHandlerAdapterRenderRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("myParam", "myPortlet"); + complexDispatcherPortlet.doDispatch(request, response); + assertEquals("myPortlet was here", response.getContentAsString()); + ComplexPortletApplicationContext.MyPortlet myPortlet = + (ComplexPortletApplicationContext.MyPortlet) + complexDispatcherPortlet.getPortletApplicationContext().getBean("myPortlet"); + assertEquals("complex", myPortlet.getPortletConfig().getPortletName()); + assertEquals(getPortletContext(), myPortlet.getPortletConfig().getPortletContext()); + assertEquals(complexDispatcherPortlet.getPortletContext(), + myPortlet.getPortletConfig().getPortletContext()); + complexDispatcherPortlet.destroy(); + assertNull(myPortlet.getPortletConfig()); + } + + public void testModelAndViewDefiningExceptionInMappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception1"); + request.addParameter("fail", "yes"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-modelandview", view.getBeanName()); + } + + public void testModelAndViewDefiningExceptionInUnmappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception2"); + request.addParameter("fail", "yes"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-modelandview", view.getBeanName()); + } + + public void testIllegalAccessExceptionInMappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception1"); + request.addParameter("access", "illegal"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-exception", view.getBeanName()); + } + + public void testIllegalAccessExceptionInUnmappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception2"); + request.addParameter("access", "illegal"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-illegalaccess", view.getBeanName()); + } + + public void testPortletRequestBindingExceptionInMappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception1"); + request.addParameter("binding", "should fail"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-exception", view.getBeanName()); + } + + public void testPortletRequestBindingExceptionInUnmappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception2"); + request.addParameter("binding", "should fail"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-binding", view.getBeanName()); + } + + public void testIllegalArgumentExceptionInMappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception1"); + request.addParameter("unknown", ""); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-runtime", view.getBeanName()); + } + + public void testIllegalArgumentExceptionInUnmappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception2"); + request.addParameter("unknown", ""); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-default-1", view.getBeanName()); + } + + public void testExceptionInMappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception1"); + request.addParameter("generic", "123"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-exception", view.getBeanName()); + } + + public void testExceptionInUnmappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception2"); + request.addParameter("generic", "123"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-default-1", view.getBeanName()); + } + + public void testRuntimeExceptionInMappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception1"); + request.addParameter("runtime", "true"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-runtime", view.getBeanName()); + } + + public void testRuntimeExceptionInUnmappedHandler() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + request.setPortletMode(PortletMode.HELP); + request.addParameter("myParam", "exception2"); + request.addParameter("runtime", "true"); + MockRenderResponse response = new MockRenderResponse(); + complexDispatcherPortlet.doDispatch(request, response); + InternalResourceView view = (InternalResourceView) request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE); + assertEquals("failed-default-1", view.getBeanName()); + } + + public void testGetMessage() { + String message = complexDispatcherPortlet.getPortletApplicationContext().getMessage("test", null, Locale.ENGLISH); + assertEquals("test message", message); + } + + public void testGetMessageOtherLocale() { + String message = complexDispatcherPortlet.getPortletApplicationContext().getMessage("test", null, Locale.CANADA); + assertEquals("Canadian & test message", message); + } + + public void testGetMessageWithArgs() { + Object[] args = new String[] {"this", "that"}; + String message = complexDispatcherPortlet.getPortletApplicationContext().getMessage("test.args", args, Locale.ENGLISH); + assertEquals("test this and that", message); + } + + public void testPortletApplicationContextLookup() { + MockPortletContext portletContext = new MockPortletContext(); + ApplicationContext ac = PortletApplicationContextUtils.getWebApplicationContext(portletContext); + assertNull(ac); + try { + ac = PortletApplicationContextUtils.getRequiredWebApplicationContext(portletContext); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + portletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, + new StaticWebApplicationContext()); + try { + ac = PortletApplicationContextUtils.getRequiredWebApplicationContext(portletContext); + assertNotNull(ac); + } + catch (IllegalStateException ex) { + fail("Should not have thrown IllegalStateException: " + ex.getMessage()); + } + } + + public void testValidActionRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest httpRequest = new MockHttpServletRequest(servletContext); + httpRequest.addPreferredLocale(Locale.GERMAN); + + // see RequestContextListener.requestInitialized() + try { + LocaleContextHolder.setLocale(httpRequest.getLocale()); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpRequest)); + + LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); + RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); + + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("action", "form"); + request.setParameter("age", "29"); + simpleDispatcherPortlet.processAction(request, response); + + assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); + assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); + } + finally { + RequestContextHolder.resetRequestAttributes(); + LocaleContextHolder.resetLocaleContext(); + } + } + + public void testValidRenderRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest httpRequest = new MockHttpServletRequest(servletContext); + httpRequest.addPreferredLocale(Locale.GERMAN); + + // see RequestContextListener.requestInitialized() + try { + LocaleContextHolder.setLocale(httpRequest.getLocale()); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpRequest)); + + LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); + RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); + + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setParameter("action", "form"); + request.setParameter("age", "29"); + simpleDispatcherPortlet.doDispatch(request, response); + + assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); + assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); + } + finally { + RequestContextHolder.resetRequestAttributes(); + LocaleContextHolder.resetLocaleContext(); + } + } + + public void testInvalidActionRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest httpRequest = new MockHttpServletRequest(servletContext); + httpRequest.addPreferredLocale(Locale.GERMAN); + + // see RequestContextListener.requestInitialized() + try { + LocaleContextHolder.setLocale(httpRequest.getLocale()); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpRequest)); + + LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); + RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); + + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("action", "invalid"); + simpleDispatcherPortlet.processAction(request, response); + String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); + assertNotNull(exceptionParam); // ensure that an exceptional condition occured + + assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); + assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); + } + finally { + RequestContextHolder.resetRequestAttributes(); + LocaleContextHolder.resetLocaleContext(); + } + } + + public void testInvalidRenderRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest httpRequest = new MockHttpServletRequest(servletContext); + httpRequest.addPreferredLocale(Locale.GERMAN); + + // see RequestContextListener.requestInitialized() + try { + LocaleContextHolder.setLocale(httpRequest.getLocale()); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpRequest)); + + LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); + RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); + + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + try { + simpleDispatcherPortlet.doDispatch(request, response); + fail("should have failed to find a handler and raised an UnavailableException"); + } + catch (UnavailableException ex) { + // expected + } + + assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); + assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); + } + finally { + RequestContextHolder.resetRequestAttributes(); + LocaleContextHolder.resetLocaleContext(); + } + } + + public void testDispatcherPortletRefresh() throws PortletException { + MockPortletContext portletContext = new MockPortletContext("org/springframework/web/portlet/context"); + DispatcherPortlet portlet = new DispatcherPortlet(); + + portlet.init(new MockPortletConfig(portletContext, "empty")); + PortletContextAwareBean contextBean = (PortletContextAwareBean) + portlet.getPortletApplicationContext().getBean("portletContextAwareBean"); + PortletConfigAwareBean configBean = (PortletConfigAwareBean) + portlet.getPortletApplicationContext().getBean("portletConfigAwareBean"); + assertSame(portletContext, contextBean.getPortletContext()); + assertSame(portlet.getPortletConfig(), configBean.getPortletConfig()); + PortletMultipartResolver multipartResolver = portlet.getMultipartResolver(); + assertNotNull(multipartResolver); + + portlet.refresh(); + + PortletContextAwareBean contextBean2 = (PortletContextAwareBean) + portlet.getPortletApplicationContext().getBean("portletContextAwareBean"); + PortletConfigAwareBean configBean2 = (PortletConfigAwareBean) + portlet.getPortletApplicationContext().getBean("portletConfigAwareBean"); + assertSame(portletContext, contextBean.getPortletContext()); + assertSame(portlet.getPortletConfig(), configBean.getPortletConfig()); + assertTrue(contextBean != contextBean2); + assertTrue(configBean != configBean2); + PortletMultipartResolver multipartResolver2 = portlet.getMultipartResolver(); + assertTrue(multipartResolver != multipartResolver2); + + portlet.destroy(); + } + + public void testDispatcherPortletContextRefresh() throws PortletException { + MockPortletContext portletContext = new MockPortletContext("org/springframework/web/portlet/context"); + DispatcherPortlet portlet = new DispatcherPortlet(); + + portlet.init(new MockPortletConfig(portletContext, "empty")); + PortletContextAwareBean contextBean = (PortletContextAwareBean) + portlet.getPortletApplicationContext().getBean("portletContextAwareBean"); + PortletConfigAwareBean configBean = (PortletConfigAwareBean) + portlet.getPortletApplicationContext().getBean("portletConfigAwareBean"); + assertSame(portletContext, contextBean.getPortletContext()); + assertSame(portlet.getPortletConfig(), configBean.getPortletConfig()); + PortletMultipartResolver multipartResolver = portlet.getMultipartResolver(); + assertNotNull(multipartResolver); + + ((ConfigurableApplicationContext) portlet.getPortletApplicationContext()).refresh(); + + PortletContextAwareBean contextBean2 = (PortletContextAwareBean) + portlet.getPortletApplicationContext().getBean("portletContextAwareBean"); + PortletConfigAwareBean configBean2 = (PortletConfigAwareBean) + portlet.getPortletApplicationContext().getBean("portletConfigAwareBean"); + assertSame(portletContext, contextBean.getPortletContext()); + assertSame(portlet.getPortletConfig(), configBean.getPortletConfig()); + assertTrue(contextBean != contextBean2); + assertTrue(configBean != configBean2); + PortletMultipartResolver multipartResolver2 = portlet.getMultipartResolver(); + assertTrue(multipartResolver != multipartResolver2); + + portlet.destroy(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/GenericPortletBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/GenericPortletBeanTests.java new file mode 100644 index 00000000000..dd6f8006c01 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/GenericPortletBeanTests.java @@ -0,0 +1,177 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet; + +import javax.portlet.PortletContext; +import javax.portlet.PortletException; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockPortletConfig; +import org.springframework.mock.web.portlet.MockPortletContext; + +/** + * @author Mark Fisher + */ +public class GenericPortletBeanTests extends TestCase { + + public void testInitParameterSet() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + String testValue = "testValue"; + portletConfig.addInitParameter("testParam", testValue); + TestPortletBean portletBean = new TestPortletBean(); + assertNull(portletBean.getTestParam()); + portletBean.init(portletConfig); + assertNotNull(portletBean.getTestParam()); + assertEquals(testValue, portletBean.getTestParam()); + } + + public void testInitParameterNotSet() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + TestPortletBean portletBean = new TestPortletBean(); + assertNull(portletBean.getTestParam()); + portletBean.init(portletConfig); + assertNull(portletBean.getTestParam()); + } + + public void testMultipleInitParametersSet() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + String testValue = "testValue"; + String anotherValue = "anotherValue"; + portletConfig.addInitParameter("testParam", testValue); + portletConfig.addInitParameter("anotherParam", anotherValue); + portletConfig.addInitParameter("unknownParam", "unknownValue"); + TestPortletBean portletBean = new TestPortletBean(); + assertNull(portletBean.getTestParam()); + assertNull(portletBean.getAnotherParam()); + portletBean.init(portletConfig); + assertNotNull(portletBean.getTestParam()); + assertNotNull(portletBean.getAnotherParam()); + assertEquals(testValue, portletBean.getTestParam()); + assertEquals(anotherValue, portletBean.getAnotherParam()); + } + + public void testMultipleInitParametersOnlyOneSet() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + String testValue = "testValue"; + portletConfig.addInitParameter("testParam", testValue); + portletConfig.addInitParameter("unknownParam", "unknownValue"); + TestPortletBean portletBean = new TestPortletBean(); + assertNull(portletBean.getTestParam()); + assertNull(portletBean.getAnotherParam()); + portletBean.init(portletConfig); + assertNotNull(portletBean.getTestParam()); + assertEquals(testValue, portletBean.getTestParam()); + assertNull(portletBean.getAnotherParam()); + } + + public void testRequiredInitParameterSet() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + String testParam = "testParam"; + String testValue = "testValue"; + portletConfig.addInitParameter(testParam, testValue); + TestPortletBean portletBean = new TestPortletBean(); + portletBean.addRequiredProperty(testParam); + assertNull(portletBean.getTestParam()); + portletBean.init(portletConfig); + assertNotNull(portletBean.getTestParam()); + assertEquals(testValue, portletBean.getTestParam()); + } + + public void testRequiredInitParameterNotSet() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + String testParam = "testParam"; + TestPortletBean portletBean = new TestPortletBean(); + portletBean.addRequiredProperty(testParam); + assertNull(portletBean.getTestParam()); + try { + portletBean.init(portletConfig); + fail("should have thrown PortletException"); + } + catch (PortletException ex) { + // expected + } + } + + public void testRequiredInitParameterNotSetOtherParameterNotSet() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + String testParam = "testParam"; + String testValue = "testValue"; + portletConfig.addInitParameter(testParam, testValue); + TestPortletBean portletBean = new TestPortletBean(); + portletBean.addRequiredProperty("anotherParam"); + assertNull(portletBean.getTestParam()); + try { + portletBean.init(portletConfig); + fail("should have thrown PortletException"); + } + catch (PortletException ex) { + // expected + } + assertNull(portletBean.getTestParam()); + } + + public void testUnknownRequiredInitParameter() throws Exception { + PortletContext portletContext = new MockPortletContext(); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + String testParam = "testParam"; + String testValue = "testValue"; + portletConfig.addInitParameter(testParam, testValue); + TestPortletBean portletBean = new TestPortletBean(); + portletBean.addRequiredProperty("unknownParam"); + assertNull(portletBean.getTestParam()); + try { + portletBean.init(portletConfig); + fail("should have thrown PortletException"); + } + catch (PortletException ex) { + // expected + } + assertNull(portletBean.getTestParam()); + } + + + private static class TestPortletBean extends GenericPortletBean { + + private String testParam; + private String anotherParam; + + public void setTestParam(String value) { + this.testParam = value; + } + + public String getTestParam() { + return this.testParam; + } + + public void setAnotherParam(String value) { + this.anotherParam = value; + } + + public String getAnotherParam() { + return this.anotherParam; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java new file mode 100644 index 00000000000..98039953d88 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java @@ -0,0 +1,129 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet; + +import java.io.IOException; +import java.util.Map; + +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.validation.BindException; +import org.springframework.web.portlet.context.StaticPortletApplicationContext; +import org.springframework.web.portlet.handler.ParameterHandlerMapping; +import org.springframework.web.portlet.mvc.SimpleFormController; + +/** + * @author Mark Fisher + */ +public class SimplePortletApplicationContext extends StaticPortletApplicationContext { + + private String renderCommandSessionAttributeName; + private String formSessionAttributeName; + + public void refresh() throws BeansException { + MutablePropertyValues pvs = new MutablePropertyValues(); + registerSingleton("controller1", TestFormController.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("bindOnNewForm", "true"); + registerSingleton("controller2", TestFormController.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("requireSession", "true"); + pvs.addPropertyValue("sessionForm", "true"); + pvs.addPropertyValue("bindOnNewForm", "true"); + registerSingleton("controller3", TestFormController.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("requireSession", "true"); + pvs.addPropertyValue("sessionForm", "true"); + pvs.addPropertyValue("bindOnNewForm", "false"); + registerSingleton("controller4", TestFormController.class, pvs); + + pvs = new MutablePropertyValues(); + Map parameterMap = new ManagedMap(); + parameterMap.put("form", new RuntimeBeanReference("controller1")); + parameterMap.put("form-bind", new RuntimeBeanReference("controller2")); + parameterMap.put("form-session-bind", new RuntimeBeanReference("controller3")); + parameterMap.put("form-session-nobind", new RuntimeBeanReference("controller4")); + pvs.addPropertyValue(new PropertyValue("parameterMap", parameterMap)); + registerSingleton("handlerMapping", ParameterHandlerMapping.class, pvs); + + super.refresh(); + + TestFormController controller1 = (TestFormController) getBean("controller1"); + this.renderCommandSessionAttributeName = controller1.getRenderCommandName(); + this.formSessionAttributeName = controller1.getFormSessionName(); + } + + public String getRenderCommandSessionAttributeName() { + return this.renderCommandSessionAttributeName; + } + + public String getFormSessionAttributeName() { + return this.formSessionAttributeName; + } + + + public static class TestFormController extends SimpleFormController { + + TestFormController() { + super(); + this.setCommandClass(TestBean.class); + this.setCommandName("testBean"); + this.setFormView("form"); + } + + public void doSubmitAction(Object command) { + TestBean testBean = (TestBean) command; + testBean.setAge(testBean.getAge() + 10); + } + + public ModelAndView showForm(RenderRequest request, RenderResponse response, BindException errors) throws Exception { + TestBean testBean = (TestBean) errors.getModel().get(getCommandName()); + this.writeResponse(response, testBean, false); + return null; + } + + public ModelAndView onSubmitRender(RenderRequest request, RenderResponse response, Object command, BindException errors) + throws IOException { + TestBean testBean = (TestBean) command; + this.writeResponse(response, testBean, true); + return null; + } + + private String getRenderCommandName() { + return this.getRenderCommandSessionAttributeName(); + } + + private String getFormSessionName() { + return this.getFormSessionAttributeName(); + } + + private void writeResponse(RenderResponse response, TestBean testBean, boolean finished) throws IOException { + response.getWriter().write((finished ? "finished" : "") + (testBean.getAge() + 5)); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestDataBinderTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestDataBinderTests.java new file mode 100644 index 00000000000..da9b841c1b0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestDataBinderTests.java @@ -0,0 +1,237 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.bind; + +import java.beans.PropertyEditorSupport; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.beans.propertyeditors.StringArrayPropertyEditor; +import org.springframework.core.CollectionFactory; +import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.validation.BindingResult; + +/** + * @author Mark Fisher + */ +public class PortletRequestDataBinderTests extends TestCase { + + public void testSimpleBind() { + TestBean bean = new TestBean(); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("age", "35"); + request.addParameter("name", "test"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.bind(request); + + assertEquals(35, bean.getAge()); + assertEquals("test", bean.getName()); + } + + public void testNestedBind() { + TestBean bean = new TestBean(); + bean.setSpouse(new TestBean()); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("spouse.name", "test"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.bind(request); + + assertNotNull(bean.getSpouse()); + assertEquals("test", bean.getSpouse().getName()); + } + + public void testNestedBindWithPropertyEditor() { + TestBean bean = new TestBean(); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.registerCustomEditor(ITestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean(text)); + } + }); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("spouse", "test"); + request.addParameter("spouse.age", "32"); + binder.bind(request); + + assertNotNull(bean.getSpouse()); + assertEquals("test", bean.getSpouse().getName()); + assertEquals(32, bean.getSpouse().getAge()); + } + + public void testBindingMismatch() { + TestBean bean = new TestBean(); + bean.setAge(30); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("age", "zzz"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.bind(request); + + BindingResult error = binder.getBindingResult(); + assertNotNull(error.getFieldError("age")); + assertEquals("typeMismatch", error.getFieldError("age").getCode()); + assertEquals(30, bean.getAge()); + } + + public void testBindingStringWithCommaSeparatedValue() throws Exception { + TestBean bean = new TestBean(); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("stringArray", "test1,test2"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.bind(request); + + assertNotNull(bean.getStringArray()); + assertEquals(1, bean.getStringArray().length); + assertEquals("test1,test2", bean.getStringArray()[0]); + } + + public void testBindingStringArrayWithSplitting() { + TestBean bean = new TestBean(); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("stringArray", "test1,test2"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor()); + binder.bind(request); + + assertNotNull(bean.getStringArray()); + assertEquals(2, bean.getStringArray().length); + assertEquals("test1", bean.getStringArray()[0]); + assertEquals("test2", bean.getStringArray()[1]); + } + + public void testBindingList() { + TestBean bean = new TestBean(); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("someList[0]", "test1"); + request.addParameter("someList[1]", "test2"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.bind(request); + + assertNotNull(bean.getSomeList()); + assertEquals(2, bean.getSomeList().size()); + assertEquals("test1", bean.getSomeList().get(0)); + assertEquals("test2", bean.getSomeList().get(1)); + } + + public void testBindingMap() { + TestBean bean = new TestBean(); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("someMap['key1']", "val1"); + request.addParameter("someMap['key2']", "val2"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.bind(request); + + assertNotNull(bean.getSomeMap()); + assertEquals(2, bean.getSomeMap().size()); + assertEquals("val1", bean.getSomeMap().get("key1")); + assertEquals("val2", bean.getSomeMap().get("key2")); + } + + public void testBindingSet() { + TestBean bean = new TestBean(); + Set set = CollectionFactory.createLinkedSetIfPossible(2); + set.add(new TestBean("test1")); + set.add(new TestBean("test2")); + bean.setSomeSet(set); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("someSet[0].age", "35"); + request.addParameter("someSet[1].age", "36"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.bind(request); + + assertNotNull(bean.getSomeSet()); + assertEquals(2, bean.getSomeSet().size()); + + Iterator iter = bean.getSomeSet().iterator(); + + TestBean bean1 = (TestBean) iter.next(); + assertEquals("test1", bean1.getName()); + assertEquals(35, bean1.getAge()); + + TestBean bean2 = (TestBean) iter.next(); + assertEquals("test2", bean2.getName()); + assertEquals(36, bean2.getAge()); + } + + public void testBindingDate() throws Exception { + TestBean bean = new TestBean(); + SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); + Date expected = dateFormat.parse("06-03-2006"); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("date", "06-03-2006"); + + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + binder.bind(request); + + assertEquals(expected, bean.getDate()); + } + + public void testBindingFailsWhenMissingRequiredParam() { + TestBean bean = new TestBean(); + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.setRequiredFields(new String[] {"age", "name"}); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("age", "35"); + binder.bind(request); + + BindingResult error = binder.getBindingResult(); + assertNotNull(error.getFieldError("name")); + assertEquals("required", error.getFieldError("name").getCode()); + } + + public void testBindingExcludesDisallowedParam() { + TestBean bean = new TestBean(); + PortletRequestDataBinder binder = new PortletRequestDataBinder(bean); + binder.setAllowedFields(new String[] {"age"}); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("age", "35"); + request.addParameter("name", "test"); + binder.bind(request); + + assertEquals(35, bean.getAge()); + assertNull(bean.getName()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestParameterPropertyValuesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestParameterPropertyValuesTests.java new file mode 100644 index 00000000000..54166c7e91a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestParameterPropertyValuesTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.bind; + +import org.springframework.mock.web.portlet.MockPortletRequest; + +import junit.framework.TestCase; + +/** + * @author Mark Fisher + */ +public class PortletRequestParameterPropertyValuesTests extends TestCase { + + public void testWithNoParams() { + MockPortletRequest request = new MockPortletRequest(); + PortletRequestParameterPropertyValues pvs = new PortletRequestParameterPropertyValues(request); + assertTrue("Should not have any property values", pvs.getPropertyValues().length == 0); + } + + public void testWithNoPrefix() { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param", "value"); + PortletRequestParameterPropertyValues pvs = new PortletRequestParameterPropertyValues(request); + assertEquals("value", pvs.getPropertyValue("param").getValue()); + } + + public void testWithPrefix() { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("test_param", "value"); + PortletRequestParameterPropertyValues pvs = new PortletRequestParameterPropertyValues(request, "test"); + assertTrue(pvs.contains("param")); + assertFalse(pvs.contains("test_param")); + assertEquals("value", pvs.getPropertyValue("param").getValue()); + } + + public void testWithPrefixAndOverridingSeparator() { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("test.param", "value"); + request.addParameter("test_another", "anotherValue"); + request.addParameter("some.other", "someValue"); + PortletRequestParameterPropertyValues pvs = new PortletRequestParameterPropertyValues(request, "test", "."); + assertFalse(pvs.contains("test.param")); + assertFalse(pvs.contains("test_another")); + assertFalse(pvs.contains("some.other")); + assertFalse(pvs.contains("another")); + assertFalse(pvs.contains("other")); + assertTrue(pvs.contains("param")); + assertEquals("value", pvs.getPropertyValue("param").getValue()); + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestUtilsTests.java new file mode 100644 index 00000000000..35be90f849e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/bind/PortletRequestUtilsTests.java @@ -0,0 +1,437 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.bind; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.util.StopWatch; + +/** + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class PortletRequestUtilsTests extends TestCase { + + public void testIntParameter() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param1", "5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertEquals(PortletRequestUtils.getIntParameter(request, "param1"), new Integer(5)); + assertEquals(PortletRequestUtils.getIntParameter(request, "param1", 6), 5); + assertEquals(PortletRequestUtils.getRequiredIntParameter(request, "param1"), 5); + + assertEquals(PortletRequestUtils.getIntParameter(request, "param2", 6), 6); + try { + PortletRequestUtils.getRequiredIntParameter(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + assertEquals(PortletRequestUtils.getIntParameter(request, "param3"), null); + assertEquals(PortletRequestUtils.getIntParameter(request, "param3", 6), 6); + try { + PortletRequestUtils.getRequiredIntParameter(request, "param3"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + try { + PortletRequestUtils.getRequiredIntParameter(request, "paramEmpty"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + } + + public void testIntParameters() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param", new String[] {"1", "2", "3"}); + + request.addParameter("param2", "1"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + int[] array = new int[] { 1, 2, 3 }; + int[] values = PortletRequestUtils.getRequiredIntParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + try { + PortletRequestUtils.getRequiredIntParameters(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + } + + public void testLongParameter() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param1", "5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertEquals(PortletRequestUtils.getLongParameter(request, "param1"), new Long(5L)); + assertEquals(PortletRequestUtils.getLongParameter(request, "param1", 6L), 5L); + assertEquals(PortletRequestUtils.getRequiredIntParameter(request, "param1"), 5L); + assertEquals(PortletRequestUtils.getLongParameter(request, "param2", 6L), 6L); + + try { + PortletRequestUtils.getRequiredLongParameter(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + assertEquals(PortletRequestUtils.getLongParameter(request, "param3"), null); + assertEquals(PortletRequestUtils.getLongParameter(request, "param3", 6L), 6L); + try { + PortletRequestUtils.getRequiredLongParameter(request, "param3"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + try { + PortletRequestUtils.getRequiredLongParameter(request, "paramEmpty"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + } + + public void testLongParameters() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.setParameter("param", new String[] {"1", "2", "3"}); + + request.setParameter("param2", "0"); + request.setParameter("param2", "1"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + long[] array = new long[] { 1L, 2L, 3L }; + long[] values = PortletRequestUtils.getRequiredLongParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + try { + PortletRequestUtils.getRequiredLongParameters(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + request.setParameter("param2", new String[] {"1", "2"}); + values = PortletRequestUtils.getRequiredLongParameters(request, "param2"); + assertEquals(2, values.length); + assertEquals(1, values[0]); + assertEquals(2, values[1]); + } + + public void testFloatParameter() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param1", "5.5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertTrue(PortletRequestUtils.getFloatParameter(request, "param1").equals(new Float(5.5f))); + assertTrue(PortletRequestUtils.getFloatParameter(request, "param1", 6.5f) == 5.5f); + assertTrue(PortletRequestUtils.getRequiredFloatParameter(request, "param1") == 5.5f); + + assertTrue(PortletRequestUtils.getFloatParameter(request, "param2", 6.5f) == 6.5f); + try { + PortletRequestUtils.getRequiredFloatParameter(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + assertTrue(PortletRequestUtils.getFloatParameter(request, "param3") == null); + assertTrue(PortletRequestUtils.getFloatParameter(request, "param3", 6.5f) == 6.5f); + try { + PortletRequestUtils.getRequiredFloatParameter(request, "param3"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + try { + PortletRequestUtils.getRequiredFloatParameter(request, "paramEmpty"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + } + + public void testFloatParameters() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param", new String[] {"1.5", "2.5", "3"}); + + request.addParameter("param2", "1.5"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + float[] array = new float[] { 1.5F, 2.5F, 3 }; + float[] values = PortletRequestUtils.getRequiredFloatParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i], 0); + } + + try { + PortletRequestUtils.getRequiredFloatParameters(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + } + + public void testDoubleParameter() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param1", "5.5"); + request.addParameter("param2", "e"); + request.addParameter("paramEmpty", ""); + + assertTrue(PortletRequestUtils.getDoubleParameter(request, "param1").equals(new Double(5.5))); + assertTrue(PortletRequestUtils.getDoubleParameter(request, "param1", 6.5) == 5.5); + assertTrue(PortletRequestUtils.getRequiredDoubleParameter(request, "param1") == 5.5); + + assertTrue(PortletRequestUtils.getDoubleParameter(request, "param2", 6.5) == 6.5); + try { + PortletRequestUtils.getRequiredDoubleParameter(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + assertTrue(PortletRequestUtils.getDoubleParameter(request, "param3") == null); + assertTrue(PortletRequestUtils.getDoubleParameter(request, "param3", 6.5) == 6.5); + try { + PortletRequestUtils.getRequiredDoubleParameter(request, "param3"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + try { + PortletRequestUtils.getRequiredDoubleParameter(request, "paramEmpty"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + } + + public void testDoubleParameters() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param", new String[] {"1.5", "2.5", "3"}); + + request.addParameter("param2", "1.5"); + request.addParameter("param2", "2"); + request.addParameter("param2", "bogus"); + + double[] array = new double[] { 1.5, 2.5, 3 }; + double[] values = PortletRequestUtils.getRequiredDoubleParameters(request, "param"); + assertEquals(3, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i], 0); + } + + try { + PortletRequestUtils.getRequiredDoubleParameters(request, "param2"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + } + + public void testBooleanParameter() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param1", "true"); + request.addParameter("param2", "e"); + request.addParameter("param4", "yes"); + request.addParameter("param5", "1"); + request.addParameter("paramEmpty", ""); + + assertTrue(PortletRequestUtils.getBooleanParameter(request, "param1").equals(Boolean.TRUE)); + assertTrue(PortletRequestUtils.getBooleanParameter(request, "param1", false)); + assertTrue(PortletRequestUtils.getRequiredBooleanParameter(request, "param1")); + + assertFalse(PortletRequestUtils.getBooleanParameter(request, "param2", true)); + assertFalse(PortletRequestUtils.getRequiredBooleanParameter(request, "param2")); + + assertTrue(PortletRequestUtils.getBooleanParameter(request, "param3") == null); + assertTrue(PortletRequestUtils.getBooleanParameter(request, "param3", true)); + try { + PortletRequestUtils.getRequiredBooleanParameter(request, "param3"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + assertTrue(PortletRequestUtils.getBooleanParameter(request, "param4", false)); + assertTrue(PortletRequestUtils.getRequiredBooleanParameter(request, "param4")); + + assertTrue(PortletRequestUtils.getBooleanParameter(request, "param5", false)); + assertTrue(PortletRequestUtils.getRequiredBooleanParameter(request, "param5")); + assertFalse(PortletRequestUtils.getRequiredBooleanParameter(request, "paramEmpty")); + } + + public void testBooleanParameters() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param", new String[] {"true", "yes", "off", "1", "bogus"}); + + request.addParameter("param2", "false"); + request.addParameter("param2", "true"); + request.addParameter("param2", ""); + + boolean[] array = new boolean[] { true, true, false, true, false }; + boolean[] values = PortletRequestUtils.getRequiredBooleanParameters(request, "param"); + assertEquals(5, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + + array = new boolean[] { false, true, false }; + values = PortletRequestUtils.getRequiredBooleanParameters(request, "param2"); + assertEquals(array.length, values.length); + for (int i = 0; i < array.length; i++) { + assertEquals(array[i], values[i]); + } + } + + public void testStringParameter() throws PortletRequestBindingException { + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("param1", "str"); + request.addParameter("paramEmpty", ""); + + assertEquals("str", PortletRequestUtils.getStringParameter(request, "param1")); + assertEquals("str", PortletRequestUtils.getStringParameter(request, "param1", "string")); + assertEquals("str", PortletRequestUtils.getRequiredStringParameter(request, "param1")); + + assertEquals(null, PortletRequestUtils.getStringParameter(request, "param3")); + assertEquals("string", PortletRequestUtils.getStringParameter(request, "param3", "string")); + try { + PortletRequestUtils.getRequiredStringParameter(request, "param3"); + fail("Should have thrown PortletRequestBindingException"); + } + catch (PortletRequestBindingException ex) { + // expected + } + + assertEquals("", PortletRequestUtils.getStringParameter(request, "paramEmpty")); + assertEquals("", PortletRequestUtils.getRequiredStringParameter(request, "paramEmpty")); + } + + public void testGetIntParameterWithDefaultValueHandlingIsFastEnough() { + MockPortletRequest request = new MockPortletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + PortletRequestUtils.getIntParameter(request, "nonExistingParam", 0); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetLongParameterWithDefaultValueHandlingIsFastEnough() { + MockPortletRequest request = new MockPortletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + PortletRequestUtils.getLongParameter(request, "nonExistingParam", 0); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetFloatParameterWithDefaultValueHandlingIsFastEnough() { + MockPortletRequest request = new MockPortletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + PortletRequestUtils.getFloatParameter(request, "nonExistingParam", 0f); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetDoubleParameterWithDefaultValueHandlingIsFastEnough() { + MockPortletRequest request = new MockPortletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + PortletRequestUtils.getDoubleParameter(request, "nonExistingParam", 0d); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetBooleanParameterWithDefaultValueHandlingIsFastEnough() { + MockPortletRequest request = new MockPortletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + PortletRequestUtils.getBooleanParameter(request, "nonExistingParam", false); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + + public void testGetStringParameterWithDefaultValueHandlingIsFastEnough() { + MockPortletRequest request = new MockPortletRequest(); + StopWatch sw = new StopWatch(); + sw.start(); + for (int i = 0; i < 1000000; i++) { + PortletRequestUtils.getStringParameter(request, "nonExistingParam", "defaultValue"); + } + sw.stop(); + System.out.println(sw.getTotalTimeMillis()); + assertTrue("getStringParameter took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 250); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletConfigAwareBean.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletConfigAwareBean.java new file mode 100644 index 00000000000..2b22f26bd7e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletConfigAwareBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import javax.portlet.PortletConfig; + +/** + * @author Mark Fisher + */ +public class PortletConfigAwareBean implements PortletConfigAware { + + private PortletConfig portletConfig; + + public void setPortletConfig(PortletConfig portletConfig) { + this.portletConfig = portletConfig; + } + + public PortletConfig getPortletConfig() { + return portletConfig; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareBean.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareBean.java new file mode 100644 index 00000000000..87bbe58758e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import javax.portlet.PortletContext; + +/** + * @author Mark Fisher + */ +public class PortletContextAwareBean implements PortletContextAware { + + private PortletContext portletContext; + + public void setPortletContext(PortletContext portletContext) { + this.portletContext = portletContext; + } + + public PortletContext getPortletContext() { + return portletContext; + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareProcessorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareProcessorTests.java new file mode 100644 index 00000000000..d2ad1dd355c --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletContextAwareProcessorTests.java @@ -0,0 +1,154 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import javax.portlet.PortletConfig; +import javax.portlet.PortletContext; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockPortletConfig; +import org.springframework.mock.web.portlet.MockPortletContext; + +/** + * @author Mark Fisher + */ +public class PortletContextAwareProcessorTests extends TestCase { + + public void testPortletContextAwareWithPortletContext() { + PortletContext portletContext = new MockPortletContext(); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext); + PortletContextAwareBean bean = new PortletContextAwareBean(); + assertNull(bean.getPortletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletContext should have been set", bean.getPortletContext()); + assertEquals(portletContext, bean.getPortletContext()); + } + + public void testPortletContextAwareWithPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletConfig portletConfig = new MockPortletConfig(portletContext); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletConfig); + PortletContextAwareBean bean = new PortletContextAwareBean(); + assertNull(bean.getPortletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletContext should have been set", bean.getPortletContext()); + assertEquals(portletContext, bean.getPortletContext()); + } + + public void testPortletContextAwareWithPortletContextAndPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletConfig portletConfig = new MockPortletConfig(portletContext); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext, portletConfig); + PortletContextAwareBean bean = new PortletContextAwareBean(); + assertNull(bean.getPortletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletContext should have been set", bean.getPortletContext()); + assertEquals(portletContext, bean.getPortletContext()); + } + + public void testPortletContextAwareWithNullPortletContextAndNonNullPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletConfig portletConfig = new MockPortletConfig(portletContext); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(null, portletConfig); + PortletContextAwareBean bean = new PortletContextAwareBean(); + assertNull(bean.getPortletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletContext should have been set", bean.getPortletContext()); + assertEquals(portletContext, bean.getPortletContext()); + } + + public void testPortletContextAwareWithNonNullPortletContextAndNullPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext, null); + PortletContextAwareBean bean = new PortletContextAwareBean(); + assertNull(bean.getPortletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletContext should have been set", bean.getPortletContext()); + assertEquals(portletContext, bean.getPortletContext()); + } + + public void testPortletContextAwareWithNullPortletContext() { + PortletContext portletContext = null; + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext); + PortletContextAwareBean bean = new PortletContextAwareBean(); + assertNull(bean.getPortletContext()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getPortletContext()); + } + + public void testPortletConfigAwareWithPortletContextOnly() { + PortletContext portletContext = new MockPortletContext(); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext); + PortletConfigAwareBean bean = new PortletConfigAwareBean(); + assertNull(bean.getPortletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getPortletConfig()); + } + + public void testPortletConfigAwareWithPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletConfig portletConfig = new MockPortletConfig(portletContext); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletConfig); + PortletConfigAwareBean bean = new PortletConfigAwareBean(); + assertNull(bean.getPortletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletConfig should have been set", bean.getPortletConfig()); + assertEquals(portletConfig, bean.getPortletConfig()); + } + + public void testPortletConfigAwareWithPortletContextAndPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletConfig portletConfig = new MockPortletConfig(portletContext); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext, portletConfig); + PortletConfigAwareBean bean = new PortletConfigAwareBean(); + assertNull(bean.getPortletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletConfig should have been set", bean.getPortletConfig()); + assertEquals(portletConfig, bean.getPortletConfig()); + } + + public void testPortletConfigAwareWithNullPortletContextAndNonNullPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletConfig portletConfig = new MockPortletConfig(portletContext); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(null, portletConfig); + PortletConfigAwareBean bean = new PortletConfigAwareBean(); + assertNull(bean.getPortletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNotNull("PortletConfig should have been set", bean.getPortletConfig()); + assertEquals(portletConfig, bean.getPortletConfig()); + } + + public void testPortletConfigAwareWithNonNullPortletContextAndNullPortletConfig() { + PortletContext portletContext = new MockPortletContext(); + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext, null); + PortletConfigAwareBean bean = new PortletConfigAwareBean(); + assertNull(bean.getPortletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getPortletConfig()); + } + + public void testPortletConfigAwareWithNullPortletContext() { + PortletContext portletContext = null; + PortletContextAwareProcessor processor = new PortletContextAwareProcessor(portletContext); + PortletConfigAwareBean bean = new PortletConfigAwareBean(); + assertNull(bean.getPortletConfig()); + processor.postProcessBeforeInitialization(bean, "testBean"); + assertNull(bean.getPortletConfig()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletRequestAttributesTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletRequestAttributesTests.java new file mode 100644 index 00000000000..5454bf007e0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletRequestAttributesTests.java @@ -0,0 +1,170 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import java.io.Serializable; + +import javax.portlet.PortletRequest; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.mock.web.portlet.MockPortletSession; +import org.springframework.test.AssertThrows; +import org.springframework.web.context.request.RequestAttributes; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public class PortletRequestAttributesTests extends TestCase { + + private static final String KEY = "ThatThingThatThing"; + + + private static final Serializable VALUE = new Serializable() { + }; + + + public void testCtorRejectsNullArg() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + new PortletRequestAttributes(null); + } + }.runTest(); + } + + public void testUpdateAccessedAttributes() throws Exception { + MockPortletSession session = new MockPortletSession(); + session.setAttribute(KEY, VALUE); + MockPortletRequest request = new MockPortletRequest(); + request.setSession(session); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + Object value = attrs.getAttribute(KEY, RequestAttributes.SCOPE_SESSION); + assertSame(VALUE, value); + attrs.requestCompleted(); + } + + public void testSetRequestScopedAttribute() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_REQUEST); + Object value = request.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetRequestScopedAttributeAfterCompletion() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + request.close(); + try { + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_REQUEST); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testSetSessionScopedAttribute() throws Exception { + MockPortletSession session = new MockPortletSession(); + session.setAttribute(KEY, VALUE); + MockPortletRequest request = new MockPortletRequest(); + request.setSession(session); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetSessionScopedAttributeAfterCompletion() throws Exception { + MockPortletSession session = new MockPortletSession(); + session.setAttribute(KEY, VALUE); + MockPortletRequest request = new MockPortletRequest(); + request.setSession(session); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + attrs.requestCompleted(); + request.close(); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetGlobalSessionScopedAttribute() throws Exception { + MockPortletSession session = new MockPortletSession(); + session.setAttribute(KEY, VALUE); + MockPortletRequest request = new MockPortletRequest(); + request.setSession(session); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_GLOBAL_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testSetGlobalSessionScopedAttributeAfterCompletion() throws Exception { + MockPortletSession session = new MockPortletSession(); + session.setAttribute(KEY, VALUE); + MockPortletRequest request = new MockPortletRequest(); + request.setSession(session); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + attrs.requestCompleted(); + request.close(); + attrs.setAttribute(KEY, VALUE, RequestAttributes.SCOPE_GLOBAL_SESSION); + Object value = session.getAttribute(KEY); + assertSame(VALUE, value); + } + + public void testGetSessionScopedAttributeDoesNotForceCreationOfSession() throws Exception { + MockControl mockRequest = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mockRequest.getMock(); + request.getPortletSession(false); + mockRequest.setReturnValue(null, 1); + mockRequest.replay(); + + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + Object value = attrs.getAttribute(KEY, RequestAttributes.SCOPE_SESSION); + assertNull(value); + + mockRequest.verify(); + } + + public void testRemoveSessionScopedAttribute() throws Exception { + MockPortletSession session = new MockPortletSession(); + session.setAttribute(KEY, VALUE); + MockPortletRequest request = new MockPortletRequest(); + request.setSession(session); + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + attrs.removeAttribute(KEY, RequestAttributes.SCOPE_SESSION); + Object value = session.getAttribute(KEY); + assertNull(value); + } + + public void testRemoveSessionScopedAttributeDoesNotForceCreationOfSession() throws Exception { + MockControl mockRequest = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mockRequest.getMock(); + request.getPortletSession(false); + mockRequest.setReturnValue(null, 1); + mockRequest.replay(); + + PortletRequestAttributes attrs = new PortletRequestAttributes(request); + attrs.removeAttribute(KEY, RequestAttributes.SCOPE_SESSION); + + mockRequest.verify(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java new file mode 100644 index 00000000000..193dde60be9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import java.util.Locale; +import java.util.Map; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockPortletRequest; + +/** + * @author Juergen Hoeller + * @since 26.07.2006 + */ +public class PortletWebRequestTests extends TestCase { + + public void testParameters() { + MockPortletRequest portletRequest = new MockPortletRequest(); + portletRequest.addParameter("param1", "value1"); + portletRequest.addParameter("param2", "value2"); + portletRequest.addParameter("param2", "value2a"); + + PortletWebRequest request = new PortletWebRequest(portletRequest); + assertEquals("value1", request.getParameter("param1")); + assertEquals(1, request.getParameterValues("param1").length); + assertEquals("value1", request.getParameterValues("param1")[0]); + assertEquals("value2", request.getParameter("param2")); + assertEquals(2, request.getParameterValues("param2").length); + assertEquals("value2", request.getParameterValues("param2")[0]); + assertEquals("value2a", request.getParameterValues("param2")[1]); + + Map paramMap = request.getParameterMap(); + assertEquals(2, paramMap.size()); + assertEquals(1, ((String[]) paramMap.get("param1")).length); + assertEquals("value1", ((String[]) paramMap.get("param1"))[0]); + assertEquals(2, ((String[]) paramMap.get("param2")).length); + assertEquals("value2", ((String[]) paramMap.get("param2"))[0]); + assertEquals("value2a", ((String[]) paramMap.get("param2"))[1]); + } + + public void testLocale() { + MockPortletRequest portletRequest = new MockPortletRequest(); + portletRequest.addPreferredLocale(Locale.UK); + + PortletWebRequest request = new PortletWebRequest(portletRequest); + assertEquals(Locale.UK, request.getLocale()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/empty-portlet.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/empty-portlet.xml new file mode 100644 index 00000000000..0ae01091c42 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/empty-portlet.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/test-portlet.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/test-portlet.xml new file mode 100644 index 00000000000..247ad1986a0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/WEB-INF/test-portlet.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java new file mode 100644 index 00000000000..9014bc59f14 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java @@ -0,0 +1,134 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import java.util.Locale; + +import javax.portlet.PortletConfig; +import javax.portlet.PortletContext; + +import org.springframework.beans.BeansException; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.NoSuchMessageException; +import org.springframework.mock.web.portlet.MockPortletConfig; +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.web.context.XmlWebApplicationContextTests; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class XmlPortletApplicationContextTests extends XmlWebApplicationContextTests { + + private ConfigurablePortletApplicationContext root; + + protected ConfigurableApplicationContext createContext() throws Exception { + root = new XmlPortletApplicationContext(); + PortletContext portletContext = new MockPortletContext(); + PortletConfig portletConfig = new MockPortletConfig(portletContext); + root.setPortletConfig(portletConfig); + root.setConfigLocations(new String[] {"/org/springframework/web/context/WEB-INF/applicationContext.xml"}); + root.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() { + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + beanFactory.addBeanPostProcessor(new BeanPostProcessor() { + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if(bean instanceof TestBean) { + ((TestBean) bean).getFriends().add("myFriend"); + } + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + }); + } + }); + root.refresh(); + XmlPortletApplicationContext pac = new XmlPortletApplicationContext(); + pac.setParent(root); + pac.setPortletConfig(portletConfig); + pac.setNamespace("test-portlet"); + pac.setConfigLocations(new String[] {"/org/springframework/web/portlet/context/WEB-INF/test-portlet.xml"}); + pac.refresh(); + return pac; + } + + /** + * Overridden in order to use MockPortletConfig + * @see org.springframework.web.context.XmlWebApplicationContextTests#testWithoutMessageSource() + */ + public void testWithoutMessageSource() throws Exception { + MockPortletContext portletContext = new MockPortletContext(""); + MockPortletConfig portletConfig = new MockPortletConfig(portletContext); + XmlPortletApplicationContext pac = new XmlPortletApplicationContext(); + pac.setParent(root); + pac.setPortletConfig(portletConfig); + pac.setNamespace("testNamespace"); + pac.setConfigLocations(new String[] {"/org/springframework/web/portlet/context/WEB-INF/test-portlet.xml"}); + pac.refresh(); + try { + pac.getMessage("someMessage", null, Locale.getDefault()); + fail("Should have thrown NoSuchMessageException"); + } + catch (NoSuchMessageException ex) { + // expected; + } + String msg = pac.getMessage("someMessage", null, "default", Locale.getDefault()); + assertTrue("Default message returned", "default".equals(msg)); + } + + /** + * Overridden in order to access the root ApplicationContext + * @see org.springframework.web.context.XmlWebApplicationContextTests#testContextNesting() + */ + public void testContextNesting() { + TestBean father = (TestBean) this.applicationContext.getBean("father"); + assertTrue("Bean from root context", father != null); + assertTrue("Custom BeanPostProcessor applied", father.getFriends().contains("myFriend")); + + TestBean rod = (TestBean) this.applicationContext.getBean("rod"); + assertTrue("Bean from child context", "Rod".equals(rod.getName())); + assertTrue("Bean has external reference", rod.getSpouse() == father); + assertTrue("Custom BeanPostProcessor not applied", !rod.getFriends().contains("myFriend")); + + rod = (TestBean) this.root.getBean("rod"); + assertTrue("Bean from root context", "Roderick".equals(rod.getName())); + assertTrue("Custom BeanPostProcessor applied", rod.getFriends().contains("myFriend")); + } + + public void testCount() { + assertTrue("should have 16 beans, not "+ this.applicationContext.getBeanDefinitionCount(), + this.applicationContext.getBeanDefinitionCount() == 16); + } + + public void testPortletContextAwareBean() { + PortletContextAwareBean bean = (PortletContextAwareBean)this.applicationContext.getBean("portletContextAwareBean"); + assertNotNull(bean.getPortletContext()); + } + + public void testPortletConfigAwareBean() { + PortletConfigAwareBean bean = (PortletConfigAwareBean)this.applicationContext.getBean("portletConfigAwareBean"); + assertNotNull(bean.getPortletConfig()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterHandlerMappingTests.java new file mode 100644 index 00000000000..fbacd30f1f6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterHandlerMappingTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.handler; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.web.portlet.HandlerMapping; +import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext; +import org.springframework.web.portlet.context.XmlPortletApplicationContext; + +/** + * @author Mark Fisher + */ +public class ParameterHandlerMappingTests extends TestCase { + + public static final String CONF = "/org/springframework/web/portlet/handler/parameterMapping.xml"; + + private ConfigurablePortletApplicationContext pac; + + public void setUp() throws Exception { + MockPortletContext portletContext = new MockPortletContext(); + pac = new XmlPortletApplicationContext(); + pac.setPortletContext(portletContext); + pac.setConfigLocations(new String[] {CONF}); + pac.refresh(); + } + + public void testParameterMapping() throws Exception { + HandlerMapping hm = (HandlerMapping)pac.getBean("handlerMapping"); + + MockPortletRequest addRequest = new MockPortletRequest(); + addRequest.addParameter("action", "add"); + + MockPortletRequest removeRequest = new MockPortletRequest(); + removeRequest.addParameter("action", "remove"); + + Object addHandler = hm.getHandler(addRequest).getHandler(); + Object removeHandler = hm.getHandler(removeRequest).getHandler(); + + assertEquals(pac.getBean("addItemHandler"), addHandler); + assertEquals(pac.getBean("removeItemHandler"), removeHandler); + } + + public void testUnregisteredHandlerWithNoDefault() throws Exception { + HandlerMapping hm = (HandlerMapping)pac.getBean("handlerMapping"); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("action", "modify"); + + assertNull(hm.getHandler(request)); + } + + public void testUnregisteredHandlerWithDefault() throws Exception { + ParameterHandlerMapping hm = (ParameterHandlerMapping)pac.getBean("handlerMapping"); + Object defaultHandler = new Object(); + hm.setDefaultHandler(defaultHandler); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("action", "modify"); + + assertNotNull(hm.getHandler(request)); + assertEquals(defaultHandler, hm.getHandler(request).getHandler()); + } + + public void testConfiguredParameterName() throws Exception { + ParameterHandlerMapping hm = (ParameterHandlerMapping)pac.getBean("handlerMapping"); + hm.setParameterName("someParam"); + + MockPortletRequest request = new MockPortletRequest(); + request.addParameter("someParam", "add"); + + Object handler = hm.getHandler(request).getHandler(); + assertEquals(pac.getBean("addItemHandler"), handler); + } + + public void testDuplicateMappingAttempt() { + ParameterHandlerMapping hm = (ParameterHandlerMapping)pac.getBean("handlerMapping"); + try { + hm.registerHandler("add", new Object()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterMappingInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterMappingInterceptorTests.java new file mode 100644 index 00000000000..644786283c7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/ParameterMappingInterceptorTests.java @@ -0,0 +1,131 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.handler; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockActionRequest; +import org.springframework.mock.web.portlet.MockActionResponse; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; + +/** + * @author Mark Fisher + */ +public class ParameterMappingInterceptorTests extends TestCase { + + public void testDefaultParameterMapped() throws Exception { + ParameterMappingInterceptor interceptor = new ParameterMappingInterceptor(); + Object handler = new Object(); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + String param = ParameterHandlerMapping.DEFAULT_PARAMETER_NAME; + String value = "someValue"; + request.setParameter(param, value); + assertNull(response.getRenderParameter(param)); + boolean shouldProceed = interceptor.preHandleAction(request, response, handler); + assertTrue(shouldProceed); + assertNotNull(response.getRenderParameter(param)); + assertEquals(value, response.getRenderParameter(param)); + } + + public void testNonDefaultParameterNotMapped() throws Exception { + ParameterMappingInterceptor interceptor = new ParameterMappingInterceptor(); + Object handler = new Object(); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + String param = "myParam"; + String value = "someValue"; + request.setParameter(param, value); + assertNull(response.getRenderParameter(param)); + boolean shouldProceed = interceptor.preHandle(request, response, handler); + assertTrue(shouldProceed); + assertNull(response.getRenderParameter(param)); + assertNull(response.getRenderParameter(ParameterHandlerMapping.DEFAULT_PARAMETER_NAME)); + } + + public void testNonDefaultParameterMappedWhenHandlerMappingProvided() throws Exception { + String param = "myParam"; + String value = "someValue"; + ParameterHandlerMapping handlerMapping = new ParameterHandlerMapping(); + handlerMapping.setParameterName(param); + ParameterMappingInterceptor interceptor = new ParameterMappingInterceptor(); + interceptor.setParameterName(param); + Object handler = new Object(); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter(param, value); + assertNull(response.getRenderParameter(param)); + boolean shouldProceed = interceptor.preHandleAction(request, response, handler); + assertTrue(shouldProceed); + assertNull(response.getRenderParameter(ParameterHandlerMapping.DEFAULT_PARAMETER_NAME)); + assertNotNull(response.getRenderParameter(param)); + assertEquals(value, response.getRenderParameter(param)); + } + + public void testNoEffectForRenderRequest() throws Exception { + ParameterMappingInterceptor interceptor = new ParameterMappingInterceptor(); + Object handler = new Object(); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String param = ParameterHandlerMapping.DEFAULT_PARAMETER_NAME; + String value = "someValue"; + request.setParameter(param, value); + boolean shouldProceed = interceptor.preHandle(request, response, handler); + assertTrue(shouldProceed); + } + + public void testNoParameterValueSetWithDefaultParameterName() throws Exception { + ParameterMappingInterceptor interceptor = new ParameterMappingInterceptor(); + Object handler = new Object(); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + String param = ParameterHandlerMapping.DEFAULT_PARAMETER_NAME; + assertNull(response.getRenderParameter(param)); + boolean shouldProceed = interceptor.preHandle(request, response, handler); + assertTrue(shouldProceed); + assertNull(response.getRenderParameter(param)); + } + + public void testNoParameterValueSetWithNonDefaultParameterName() throws Exception { + ParameterMappingInterceptor interceptor = new ParameterMappingInterceptor(); + Object handler = new Object(); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + String param = "myParam"; + assertNull(response.getRenderParameter(param)); + boolean shouldProceed = interceptor.preHandle(request, response, handler); + assertTrue(shouldProceed); + assertNull(response.getRenderParameter(param)); + } + + public void testNoParameterValueSetWithNonDefaultParameterNameWhenHandlerMappingProvided() throws Exception { + String param = "myParam"; + ParameterHandlerMapping handlerMapping = new ParameterHandlerMapping(); + handlerMapping.setParameterName(param); + ParameterMappingInterceptor interceptor = new ParameterMappingInterceptor(); + interceptor.setParameterName(param); + Object handler = new Object(); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + assertNull(response.getRenderParameter(param)); + boolean shouldProceed = interceptor.preHandle(request, response, handler); + assertTrue(shouldProceed); + assertNull(response.getRenderParameter(param)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeHandlerMappingTests.java new file mode 100644 index 00000000000..f1bda016299 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeHandlerMappingTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.handler; + +import javax.portlet.PortletMode; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.web.portlet.HandlerMapping; +import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext; +import org.springframework.web.portlet.context.XmlPortletApplicationContext; + +/** + * @author Mark Fisher + */ +public class PortletModeHandlerMappingTests extends TestCase { + + public static final String CONF = "/org/springframework/web/portlet/handler/portletModeMapping.xml"; + + private ConfigurablePortletApplicationContext pac; + + public void setUp() throws Exception { + MockPortletContext portletContext = new MockPortletContext(); + pac = new XmlPortletApplicationContext(); + pac.setPortletContext(portletContext); + pac.setConfigLocations(new String[] {CONF}); + pac.refresh(); + } + + public void testPortletModeView() throws Exception { + HandlerMapping hm = (HandlerMapping)pac.getBean("handlerMapping"); + + MockPortletRequest request = new MockPortletRequest(); + request.setPortletMode(PortletMode.VIEW); + + Object handler = hm.getHandler(request).getHandler(); + assertEquals(pac.getBean("viewHandler"), handler); + } + + public void testPortletModeEdit() throws Exception { + HandlerMapping hm = (HandlerMapping)pac.getBean("handlerMapping"); + + MockPortletRequest request = new MockPortletRequest(); + request.setPortletMode(PortletMode.EDIT); + + Object handler = hm.getHandler(request).getHandler(); + assertEquals(pac.getBean("editHandler"), handler); + } + + public void testPortletModeHelp() throws Exception { + HandlerMapping hm = (HandlerMapping)pac.getBean("handlerMapping"); + + MockPortletRequest request = new MockPortletRequest(); + request.setPortletMode(PortletMode.HELP); + + Object handler = hm.getHandler(request).getHandler(); + assertEquals(pac.getBean("helpHandler"), handler); + } + + public void testDuplicateMappingAttempt() { + PortletModeHandlerMapping hm = (PortletModeHandlerMapping)pac.getBean("handlerMapping"); + try { + hm.registerHandler(PortletMode.VIEW, new Object()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeParameterHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeParameterHandlerMappingTests.java new file mode 100644 index 00000000000..1bf68e45fa4 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/PortletModeParameterHandlerMappingTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.handler; + +import javax.portlet.PortletMode; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.web.portlet.HandlerMapping; +import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext; +import org.springframework.web.portlet.context.XmlPortletApplicationContext; + +/** + * @author Mark Fisher + */ +public class PortletModeParameterHandlerMappingTests extends TestCase { + + public static final String CONF = "/org/springframework/web/portlet/handler/portletModeParameterMapping.xml"; + + private ConfigurablePortletApplicationContext pac; + + public void setUp() throws Exception { + MockPortletContext portletContext = new MockPortletContext(); + pac = new XmlPortletApplicationContext(); + pac.setPortletContext(portletContext); + pac.setConfigLocations(new String[] {CONF}); + pac.refresh(); + } + + public void testPortletModeViewWithParameter() throws Exception { + HandlerMapping hm = (HandlerMapping)pac.getBean("handlerMapping"); + + MockPortletRequest addRequest = new MockPortletRequest(); + addRequest.setPortletMode(PortletMode.VIEW); + addRequest.setParameter("action", "add"); + + MockPortletRequest removeRequest = new MockPortletRequest(); + removeRequest.setPortletMode(PortletMode.VIEW); + removeRequest.setParameter("action", "remove"); + + Object addHandler = hm.getHandler(addRequest).getHandler(); + Object removeHandler = hm.getHandler(removeRequest).getHandler(); + + assertEquals(pac.getBean("addItemHandler"), addHandler); + assertEquals(pac.getBean("removeItemHandler"), removeHandler); + } + + public void testPortletModeEditWithParameter() throws Exception { + HandlerMapping hm = (HandlerMapping)pac.getBean("handlerMapping"); + + MockPortletRequest request = new MockPortletRequest(); + request.setPortletMode(PortletMode.EDIT); + request.setParameter("action", "prefs"); + + Object handler = hm.getHandler(request).getHandler(); + assertEquals(pac.getBean("preferencesHandler"), handler); + } + + public void testDuplicateMappingInSamePortletMode() { + PortletModeParameterHandlerMapping hm = (PortletModeParameterHandlerMapping)pac.getBean("handlerMapping"); + try { + hm.registerHandler(PortletMode.VIEW, "remove", new Object()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testDuplicateMappingInDifferentPortletMode() { + PortletModeParameterHandlerMapping hm = (PortletModeParameterHandlerMapping)pac.getBean("handlerMapping"); + try { + hm.registerHandler(PortletMode.EDIT, "remove", new Object()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + public void testAllowDuplicateMappingInDifferentPortletMode() throws Exception { + PortletModeParameterHandlerMapping hm = (PortletModeParameterHandlerMapping)pac.getBean("handlerMapping"); + hm.setAllowDuplicateParameters(true); + + Object editRemoveHandler = new Object(); + hm.registerHandler(PortletMode.EDIT, "remove", editRemoveHandler); + + MockPortletRequest request = new MockPortletRequest(); + request.setPortletMode(PortletMode.EDIT); + request.setParameter("action", "remove"); + + Object handler = hm.getHandler(request).getHandler(); + assertEquals(editRemoveHandler, handler); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolverTests.java new file mode 100644 index 00000000000..8cc1ec1fe93 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolverTests.java @@ -0,0 +1,277 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.handler; + +import java.util.Collections; +import java.util.Properties; + +import javax.portlet.WindowState; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; +import org.springframework.web.portlet.ModelAndView; + +/** + * @author Seth Ladd + * @author Mark Fisher + * @author Juergen Hoeller + */ +public class SimpleMappingExceptionResolverTests extends TestCase { + + private static final String DEFAULT_VIEW = "default-view"; + + private SimpleMappingExceptionResolver exceptionResolver; + private MockRenderRequest request; + private MockRenderResponse response; + private Object handler1; + private Object handler2; + private Exception genericException; + + protected void setUp() { + exceptionResolver = new SimpleMappingExceptionResolver(); + request = new MockRenderRequest(); + response = new MockRenderResponse(); + handler1 = new String(); + handler2 = new Object(); + genericException = new Exception(); + } + + public void testSetOrder() { + exceptionResolver.setOrder(2); + assertEquals(2, exceptionResolver.getOrder()); + } + + public void testDefaultErrorView() { + exceptionResolver.setDefaultErrorView(DEFAULT_VIEW); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals(DEFAULT_VIEW, mav.getViewName()); + assertEquals(genericException, mav.getModel().get(SimpleMappingExceptionResolver.DEFAULT_EXCEPTION_ATTRIBUTE)); + } + + public void testDefaultErrorViewDifferentHandler() { + exceptionResolver.setDefaultErrorView(DEFAULT_VIEW); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull("Handler not mapped - ModelAndView should be null", mav); + } + + public void testDefaultErrorViewDifferentHandlerClass() { + exceptionResolver.setDefaultErrorView(DEFAULT_VIEW); + exceptionResolver.setMappedHandlerClasses(new Class[] {String.class}); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull("Handler not mapped - ModelAndView should be null", mav); + } + + public void testNullDefaultErrorView() { + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertNull("No default error view set - ModelAndView should be null", mav); + } + + public void testNullExceptionAttribute() { + exceptionResolver.setDefaultErrorView(DEFAULT_VIEW); + exceptionResolver.setExceptionAttribute(null); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals(DEFAULT_VIEW, mav.getViewName()); + assertNull(mav.getModel().get(SimpleMappingExceptionResolver.DEFAULT_EXCEPTION_ATTRIBUTE)); + } + + public void testNullExceptionMappings() { + exceptionResolver.setExceptionMappings(null); + exceptionResolver.setDefaultErrorView(DEFAULT_VIEW); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals(DEFAULT_VIEW, mav.getViewName()); + } + + public void testDefaultNoRenderWhenMinimized() { + exceptionResolver.setDefaultErrorView(DEFAULT_VIEW); + request.setWindowState(WindowState.MINIMIZED); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertNull("Should not render when WindowState is MINIMIZED", mav); + } + + public void testDoRenderWhenMinimized() { + exceptionResolver.setDefaultErrorView(DEFAULT_VIEW); + exceptionResolver.setRenderWhenMinimized(true); + request.setWindowState(WindowState.MINIMIZED); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertNotNull("ModelAndView should not be null", mav); + assertEquals(DEFAULT_VIEW, mav.getViewName()); + } + + public void testSimpleExceptionMapping() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + exceptionResolver.setWarnLogCategory("HANDLER_EXCEPTION"); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testExactExceptionMappingWithHandlerSpecified() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testExactExceptionMappingWithHandlerClassSpecified() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + exceptionResolver.setMappedHandlerClasses(new Class[] {String.class}); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testExactExceptionMappingWithHandlerInterfaceSpecified() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + exceptionResolver.setMappedHandlerClasses(new Class[] {Comparable.class}); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testSimpleExceptionMappingWithHandlerSpecifiedButWrongHandler() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull("Handler not mapped - ModelAndView should be null", mav); + } + + public void testSimpleExceptionMappingWithHandlerSpecifiedButWrongHandlerClass() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + exceptionResolver.setMappedHandlerClasses(new Class[] {String.class}); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull("Handler not mapped - ModelAndView should be null", mav); + } + + public void testMissingExceptionInMapping() { + Properties props = new Properties(); + props.setProperty("SomeFooThrowable", "error"); + exceptionResolver.setWarnLogCategory("HANDLER_EXCEPTION"); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertNull("Exception not mapped - ModelAndView should be null", mav); + } + + public void testTwoMappings() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("AnotherException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testTwoMappingsOneShortOneLong() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + props.setProperty("AnotherException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testTwoMappingsOneShortOneLongThrowOddException() { + Exception oddException = new SomeOddException(); + Properties props = new Properties(); + props.setProperty("Exception", "error"); + props.setProperty("SomeOddException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("error", mav.getViewName()); + } + + public void testTwoMappingsThrowOddExceptionUseLongExceptionMapping() { + Exception oddException = new SomeOddException(); + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("SomeOddException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("another-error", mav.getViewName()); + } + + public void testThreeMappings() { + Exception oddException = new AnotherOddException(); + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("SomeOddException", "another-error"); + props.setProperty("AnotherOddException", "another-some-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("another-some-error", mav.getViewName()); + } + + public void testExceptionWithSubstringMatchingParent() { + Exception oddException = new SomeOddExceptionChild(); + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("SomeOddException", "parent-error"); + props.setProperty("SomeOddExceptionChild", "child-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("child-error", mav.getViewName()); + } + + public void testMostSpecificExceptionInHierarchyWins() { + Exception oddException = new NoSubstringMatchesThisException(); + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("SomeOddException", "parent-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("parent-error", mav.getViewName()); + } + + + private static class SomeOddException extends Exception { + + } + + + private static class SomeOddExceptionChild extends SomeOddException { + + } + + + private static class NoSubstringMatchesThisException extends SomeOddException { + + } + + + private static class AnotherOddException extends Exception { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptorTests.java new file mode 100644 index 00000000000..7185dee9860 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptorTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.handler; + +import javax.portlet.PortletSecurityException; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; + +/** + * @author Mark Fisher + */ +public class UserRoleAuthorizationInterceptorTests extends TestCase { + + public void testAuthorizedUser() throws Exception { + UserRoleAuthorizationInterceptor interceptor = new UserRoleAuthorizationInterceptor(); + String validRole = "allowed"; + interceptor.setAuthorizedRoles(new String[] {validRole}); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + Object handler = new Object(); + request.addUserRole(validRole); + assertTrue(request.isUserInRole(validRole)); + boolean shouldProceed = interceptor.preHandle(request, response, handler); + assertTrue(shouldProceed); + } + + public void testAuthorizedUserWithMultipleRoles() throws Exception { + UserRoleAuthorizationInterceptor interceptor = new UserRoleAuthorizationInterceptor(); + String validRole1 = "allowed1"; + String validRole2 = "allowed2"; + interceptor.setAuthorizedRoles(new String[] {validRole1, validRole2}); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + Object handler = new Object(); + request.addUserRole(validRole2); + request.addUserRole("someOtherRole"); + assertFalse(request.isUserInRole(validRole1)); + assertTrue(request.isUserInRole(validRole2)); + boolean shouldProceed = interceptor.preHandle(request, response, handler); + assertTrue(shouldProceed); + } + + public void testUnauthorizedUser() throws Exception { + UserRoleAuthorizationInterceptor interceptor = new UserRoleAuthorizationInterceptor(); + String validRole = "allowed"; + interceptor.setAuthorizedRoles(new String[] {validRole}); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + Object handler = new Object(); + request.addUserRole("someOtherRole"); + assertFalse(request.isUserInRole(validRole)); + try { + interceptor.preHandle(request, response, handler); + fail("should have thrown PortletSecurityException"); + } + catch (PortletSecurityException ex) { + // expected + } + } + + public void testRequestWithNoUserRoles() throws Exception { + UserRoleAuthorizationInterceptor interceptor = new UserRoleAuthorizationInterceptor(); + String validRole = "allowed"; + interceptor.setAuthorizedRoles(new String[] {validRole}); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + Object handler = new Object(); + assertFalse(request.isUserInRole(validRole)); + try { + interceptor.preHandle(request, response, handler); + fail("should have thrown PortletSecurityException"); + } + catch (PortletSecurityException ex) { + // expected + } + } + + public void testInterceptorWithNoAuthorizedRoles() throws Exception { + UserRoleAuthorizationInterceptor interceptor = new UserRoleAuthorizationInterceptor(); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + Object handler = new Object(); + request.addUserRole("someRole"); + try { + interceptor.preHandle(request, response, handler); + fail("should have thrown PortletSecurityException"); + } + catch (PortletSecurityException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/parameterMapping.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/parameterMapping.xml new file mode 100644 index 00000000000..f3fddf0d76f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/parameterMapping.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeMapping.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeMapping.xml new file mode 100644 index 00000000000..fc62e717e8e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeMapping.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeParameterMapping.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeParameterMapping.xml new file mode 100644 index 00000000000..066d1a88c21 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/handler/portletModeParameterMapping.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java new file mode 100644 index 00000000000..52a566fd398 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java @@ -0,0 +1,461 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.mvc; + +import java.beans.PropertyEditorSupport; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.PortletRequest; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; +import javax.portlet.WindowState; + +import junit.framework.TestCase; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.mock.web.portlet.MockActionRequest; +import org.springframework.mock.web.portlet.MockActionResponse; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; +import org.springframework.web.portlet.ModelAndView; +import org.springframework.web.portlet.bind.PortletRequestDataBinder; +import org.springframework.web.portlet.handler.PortletSessionRequiredException; + +/** + * @author Mark Fisher + */ +public class CommandControllerTests extends TestCase { + + private static final String ERRORS_KEY = "errors"; + + public void testRenderRequestWithNoParams() throws Exception { + TestController tc = new TestController(); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setContextPath("test"); + ModelAndView mav = tc.handleRenderRequest(request, response); + assertEquals("test-view", mav.getViewName()); + assertNotNull(mav.getModel().get(tc.getCommandName())); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertNotNull(errors); + assertEquals("There should be no errors", 0, errors.getErrorCount()); + } + + public void testRenderRequestWithParams() throws Exception { + TestController tc = new TestController(); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String name = "test"; + int age = 30; + request.addParameter("name", name); + request.addParameter("age", "" + age); + request.setContextPath("test"); + ModelAndView mav = tc.handleRenderRequest(request, response); + assertEquals("test-view", mav.getViewName()); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertEquals("Name should be bound", name, command.getName()); + assertEquals("Age should be bound", age, command.getAge()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertNotNull(errors); + assertEquals("There should be no errors", 0, errors.getErrorCount()); + } + + public void testRenderRequestWithMismatch() throws Exception { + TestController tc = new TestController(); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String name = "test"; + request.addParameter("name", name); + request.addParameter("age", "zzz"); + request.setContextPath("test"); + ModelAndView mav = tc.handleRenderRequest(request, response); + assertEquals("test-view", mav.getViewName()); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertNotNull(command); + assertEquals("Name should be bound", name, command.getName()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be 1 error", 1, errors.getErrorCount()); + assertNotNull(errors.getFieldError("age")); + assertEquals("typeMismatch", errors.getFieldError("age").getCode()); + } + + public void testRenderWhenMinimizedReturnsNull() throws Exception { + TestController tc = new TestController(); + assertFalse(tc.isRenderWhenMinimized()); + MockRenderRequest request = new MockRenderRequest(); + request.setWindowState(WindowState.MINIMIZED); + MockRenderResponse response = new MockRenderResponse(); + ModelAndView mav = tc.handleRenderRequest(request, response); + assertNull("ModelAndView should be null", mav); + } + + public void testAllowRenderWhenMinimized() throws Exception { + TestController tc = new TestController(); + tc.setRenderWhenMinimized(true); + MockRenderRequest request = new MockRenderRequest(); + request.setWindowState(WindowState.MINIMIZED); + request.setContextPath("test"); + MockRenderResponse response = new MockRenderResponse(); + ModelAndView mav = tc.handleRenderRequest(request, response); + assertNotNull("ModelAndView should not be null", mav); + assertEquals("test-view", mav.getViewName()); + assertNotNull(mav.getModel().get(tc.getCommandName())); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be no errors", 0, errors.getErrorCount()); + } + + public void testRequiresSessionWithoutSession() throws Exception { + TestController tc = new TestController(); + tc.setRequireSession(true); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + try { + tc.handleRenderRequest(request, response); + fail("Should have thrown PortletSessionRequiredException"); + } + catch (PortletSessionRequiredException ex) { + // expected + } + } + + public void testRequiresSessionWithSession() throws Exception { + TestController tc = new TestController(); + tc.setRequireSession(true); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + + // create the session + request.getPortletSession(true); + try { + tc.handleRenderRequest(request, response); + } + catch (PortletSessionRequiredException ex) { + fail("Should not have thrown PortletSessionRequiredException"); + } + } + + public void testRenderRequestWithoutCacheSetting() throws Exception { + TestController tc = new TestController(); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + tc.handleRenderRequest(request, response); + String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); + assertNull("Expiration-cache should be null", cacheProperty); + } + + public void testRenderRequestWithNegativeCacheSetting() throws Exception { + TestController tc = new TestController(); + tc.setCacheSeconds(-99); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + tc.handleRenderRequest(request, response); + String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); + assertNull("Expiration-cache should be null", cacheProperty); + } + + public void testRenderRequestWithZeroCacheSetting() throws Exception { + TestController tc = new TestController(); + tc.setCacheSeconds(0); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + tc.handleRenderRequest(request, response); + String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); + assertEquals("Expiration-cache should be set to 0 seconds", "0", cacheProperty); + } + + public void testRenderRequestWithPositiveCacheSetting() throws Exception { + TestController tc = new TestController(); + tc.setCacheSeconds(30); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + tc.handleRenderRequest(request, response); + String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); + assertEquals("Expiration-cache should be set to 30 seconds", "30", cacheProperty); + } + + public void testActionRequest() throws Exception { + TestController tc = new TestController(); + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + tc.handleActionRequest(request, response); + TestBean command = (TestBean)request.getPortletSession().getAttribute(tc.getRenderCommandSessionAttributeName()); + assertTrue(command.isJedi()); + } + + public void testSuppressBinding() throws Exception { + TestController tc = new TestController() { + protected boolean suppressBinding(PortletRequest request) { + return true; + } + }; + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String name = "test"; + int age = 30; + request.addParameter("name", name); + request.addParameter("age", "" + age); + request.setContextPath("test"); + ModelAndView mav = tc.handleRenderRequest(request, response); + assertEquals("test-view", mav.getViewName()); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertNotNull(command); + assertTrue("Name should not have been bound", name != command.getName()); + assertTrue("Age should not have been bound", age != command.getAge()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be no errors", 0, errors.getErrorCount()); + } + + public void testWithCustomDateEditor() throws Exception { + final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); + TestController tc = new TestController() { + protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + }; + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String name = "test"; + int age = 30; + request.addParameter("name", name); + request.addParameter("age", "" + age); + String dateString = "07-03-2006"; + Date expectedDate = dateFormat.parse(dateString); + request.addParameter("date", dateString); + ModelAndView mav = tc.handleRenderRequest(request, response); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertEquals(name, command.getName()); + assertEquals(age, command.getAge()); + assertEquals(expectedDate, command.getDate()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be no errors", 0, errors.getErrorCount()); + } + + public void testWithCustomDateEditorEmptyNotAllowed() throws Exception { + final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); + TestController tc = new TestController() { + protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + }; + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String name = "test"; + int age = 30; + request.addParameter("name", name); + request.addParameter("age", "" + age); + String emptyString = ""; + request.addParameter("date", emptyString); + ModelAndView mav = tc.handleRenderRequest(request, response); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertEquals(name, command.getName()); + assertEquals(age, command.getAge()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be 1 error", 1, errors.getErrorCount()); + assertNotNull(errors.getFieldError("date")); + assertEquals("typeMismatch", errors.getFieldError("date").getCode()); + assertEquals(emptyString, errors.getFieldError("date").getRejectedValue()); + } + + public void testWithCustomDateEditorEmptyAllowed() throws Exception { + final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); + TestController tc = new TestController() { + protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); + } + }; + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String name = "test"; + int age = 30; + request.addParameter("name", name); + request.addParameter("age", "" + age); + String dateString = ""; + request.addParameter("date", dateString); + ModelAndView mav = tc.handleRenderRequest(request, response); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertEquals(name, command.getName()); + assertEquals(age, command.getAge()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be 0 errors", 0, errors.getErrorCount()); + assertNull("date should be null", command.getDate()); + } + + public void testNestedBindingWithPropertyEditor() throws Exception { + TestController tc = new TestController() { + protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { + binder.registerCustomEditor(ITestBean.class, new PropertyEditorSupport() { + public void setAsText(String text) throws IllegalArgumentException { + setValue(new TestBean(text)); + } + }); + } + }; + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + String name = "test"; + String spouseName = "testSpouse"; + int age = 30; + int spouseAge = 31; + request.addParameter("name", name); + request.addParameter("age", "" + age); + request.addParameter("spouse", spouseName); + request.addParameter("spouse.age", "" + spouseAge); + ModelAndView mav = tc.handleRenderRequest(request, response); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertEquals(name, command.getName()); + assertEquals(age, command.getAge()); + assertNotNull(command.getSpouse()); + assertEquals(spouseName, command.getSpouse().getName()); + assertEquals(spouseAge, command.getSpouse().getAge()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be no errors", 0, errors.getErrorCount()); + } + + public void testWithValidatorNotSupportingCommandClass() throws Exception { + Validator v = new Validator() { + public boolean supports(Class c) { + return false; + } + public void validate(Object o, Errors e) {} + }; + TestController tc = new TestController(); + tc.setValidator(v); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + try { + tc.handleRenderRequest(request, response); + fail("Should have thrown IllegalArgumentException"); + } + catch(IllegalArgumentException e) { + // expected + } + } + + public void testWithValidatorAddingGlobalError() throws Exception { + final String errorCode = "someCode"; + final String defaultMessage = "validation error!"; + TestController tc = new TestController(); + tc.setValidator(new Validator() { + public boolean supports(Class c) { + return TestBean.class.isAssignableFrom(c); + } + public void validate(Object o, Errors e) { + e.reject(errorCode, defaultMessage); + } + }); + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + ModelAndView mav = tc.handleRenderRequest(request, response); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be 1 error", 1, errors.getErrorCount()); + ObjectError error = errors.getGlobalError(); + assertEquals(error.getCode(), errorCode); + assertEquals(error.getDefaultMessage(), defaultMessage); + } + + public void testWithValidatorAndNullFieldError() throws Exception { + final String errorCode = "someCode"; + final String defaultMessage = "validation error!"; + TestController tc = new TestController(); + tc.setValidator(new Validator() { + public boolean supports(Class c) { + return TestBean.class.isAssignableFrom(c); + } + public void validate(Object o, Errors e) { + ValidationUtils.rejectIfEmpty(e, "name", errorCode, defaultMessage); + } + }); + MockRenderRequest request = new MockRenderRequest(); + int age = 32; + request.setParameter("age", "" + age); + MockRenderResponse response = new MockRenderResponse(); + ModelAndView mav = tc.handleRenderRequest(request, response); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertNull("name should be null", command.getName()); + assertEquals(age, command.getAge()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be 1 error", 1, errors.getErrorCount()); + FieldError error = errors.getFieldError("name"); + assertEquals(error.getCode(), errorCode); + assertEquals(error.getDefaultMessage(), defaultMessage); + } + + public void testWithValidatorAndWhitespaceFieldError() throws Exception { + final String errorCode = "someCode"; + final String defaultMessage = "validation error!"; + TestController tc = new TestController(); + tc.setValidator(new Validator() { + public boolean supports(Class c) { + return TestBean.class.isAssignableFrom(c); + } + public void validate(Object o, Errors e) { + ValidationUtils.rejectIfEmptyOrWhitespace(e, "name", errorCode, defaultMessage); + } + }); + MockRenderRequest request = new MockRenderRequest(); + int age = 32; + String whitespace = " \t "; + request.setParameter("age", "" + age); + request.setParameter("name", whitespace); + MockRenderResponse response = new MockRenderResponse(); + ModelAndView mav = tc.handleRenderRequest(request, response); + TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); + assertTrue(command.getName().equals(whitespace)); + assertEquals(age, command.getAge()); + BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); + assertEquals("There should be 1 error", 1, errors.getErrorCount()); + FieldError error = errors.getFieldError("name"); + assertEquals("rejected value should contain whitespace", whitespace, error.getRejectedValue()); + assertEquals(error.getCode(), errorCode); + assertEquals(error.getDefaultMessage(), defaultMessage); + } + + private static class TestController extends AbstractCommandController { + + private TestController() { + super(TestBean.class, "testBean"); + } + + protected void handleAction(ActionRequest request, ActionResponse response, Object command, BindException errors) { + ((TestBean)command).setJedi(true); + } + + protected ModelAndView handleRender(RenderRequest request, RenderResponse response, Object command, BindException errors) { + assertNotNull(command); + assertNotNull(errors); + Map model = new HashMap(); + model.put(getCommandName(), command); + model.put(ERRORS_KEY, errors); + return new ModelAndView(request.getContextPath() + "-view", model); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/ParameterizableViewControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/ParameterizableViewControllerTests.java new file mode 100644 index 00000000000..cef2df048c5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/ParameterizableViewControllerTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.mvc; + +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.PortletException; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockActionRequest; +import org.springframework.mock.web.portlet.MockActionResponse; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; +import org.springframework.web.portlet.ModelAndView; +import org.springframework.web.portlet.context.StaticPortletApplicationContext; + +/** + * @author Mark Fisher + */ +public class ParameterizableViewControllerTests extends TestCase { + + public void testRenderRequestWithViewNameSet() throws Exception { + ParameterizableViewController controller = new ParameterizableViewController(); + String viewName = "testView"; + controller.setViewName(viewName); + RenderRequest request = new MockRenderRequest(); + RenderResponse response = new MockRenderResponse(); + ModelAndView mav = controller.handleRenderRequest(request, response); + assertEquals(viewName, mav.getViewName()); + } + + public void testInitApplicationContextWithNoViewNameSet() throws Exception { + ParameterizableViewController controller = new ParameterizableViewController(); + try { + controller.setApplicationContext(new StaticPortletApplicationContext()); + fail("should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testActionRequestNotHandled() throws Exception { + ParameterizableViewController controller = new ParameterizableViewController(); + ActionRequest request = new MockActionRequest(); + ActionResponse response = new MockActionResponse(); + try { + controller.handleActionRequest(request, response); + fail("should have thrown PortletException"); + } + catch (PortletException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletModeNameViewControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletModeNameViewControllerTests.java new file mode 100644 index 00000000000..5fa8569bb67 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletModeNameViewControllerTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.mvc; + +import javax.portlet.PortletException; +import javax.portlet.PortletMode; + +import junit.framework.TestCase; + +import org.springframework.mock.web.portlet.MockActionRequest; +import org.springframework.mock.web.portlet.MockActionResponse; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; +import org.springframework.web.portlet.ModelAndView; + +/** + * @author Mark Fisher + */ +public class PortletModeNameViewControllerTests extends TestCase { + + private PortletModeNameViewController controller; + + public void setUp() { + controller = new PortletModeNameViewController(); + } + + public void testEditPortletMode() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.EDIT); + ModelAndView mav = controller.handleRenderRequest(request, response); + assertEquals("edit", mav.getViewName()); + } + + public void testHelpPortletMode() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.HELP); + ModelAndView mav = controller.handleRenderRequest(request, response); + assertEquals("help", mav.getViewName()); + } + + public void testViewPortletMode() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + request.setPortletMode(PortletMode.VIEW); + ModelAndView mav = controller.handleRenderRequest(request, response); + assertEquals("view", mav.getViewName()); + } + + public void testActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + try { + controller.handleActionRequest(request, response); + fail("Should have thrown PortletException"); + } + catch(PortletException ex) { + // expected + } + } +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletWrappingControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletWrappingControllerTests.java new file mode 100644 index 00000000000..10e0ffe1256 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/mvc/PortletWrappingControllerTests.java @@ -0,0 +1,188 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.mvc; + +import junit.framework.TestCase; +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.mock.web.portlet.*; +import org.springframework.test.AssertThrows; +import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext; +import org.springframework.web.portlet.context.StaticPortletApplicationContext; + +import javax.portlet.*; +import java.io.IOException; + +/** + * Unit tests for the {@link PortletWrappingController} class. + * + * @author Mark Fisher + * @author Rick Evans + */ +public final class PortletWrappingControllerTests extends TestCase { + + private static final String RESULT_RENDER_PARAMETER_NAME = "result"; + private static final String PORTLET_WRAPPING_CONTROLLER_BEAN_NAME = "controller"; + private static final String RENDERED_RESPONSE_CONTENT = "myPortlet-view"; + private static final String PORTLET_NAME_ACTION_REQUEST_PARAMETER_NAME = "portletName"; + + + private PortletWrappingController controller; + + + public void setUp() { + ConfigurablePortletApplicationContext applicationContext = new MyApplicationContext(); + MockPortletConfig config = new MockPortletConfig(new MockPortletContext(), "wrappedPortlet"); + applicationContext.setPortletConfig(config); + applicationContext.refresh(); + controller = (PortletWrappingController) applicationContext.getBean(PORTLET_WRAPPING_CONTROLLER_BEAN_NAME); + } + + + public void testActionRequest() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter("test", "test"); + controller.handleActionRequest(request, response); + String result = response.getRenderParameter(RESULT_RENDER_PARAMETER_NAME); + assertEquals("myPortlet-action", result); + } + + public void testRenderRequest() throws Exception { + MockRenderRequest request = new MockRenderRequest(); + MockRenderResponse response = new MockRenderResponse(); + controller.handleRenderRequest(request, response); + String result = response.getContentAsString(); + assertEquals(RENDERED_RESPONSE_CONTENT, result); + } + + public void testActionRequestWithNoParameters() throws Exception { + final MockActionRequest request = new MockActionRequest(); + final MockActionResponse response = new MockActionResponse(); + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + controller.handleActionRequest(request, response); + } + }.runTest(); + } + + public void testRejectsPortletClassThatDoesNotImplementPortletInterface() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletWrappingController controller = new PortletWrappingController(); + controller.setPortletClass(String.class); + controller.afterPropertiesSet(); + } + }.runTest(); + } + + public void testRejectsIfPortletClassIsNotSupplied() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletWrappingController controller = new PortletWrappingController(); + controller.setPortletClass(null); + controller.afterPropertiesSet(); + } + }.runTest(); + } + + public void testDestroyingTheControllerPropagatesDestroyToWrappedPortlet() throws Exception { + final PortletWrappingController controller = new PortletWrappingController(); + controller.setPortletClass(MyPortlet.class); + controller.afterPropertiesSet(); + // test for destroy() call being propagated via exception being thrown :( + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + controller.destroy(); + } + }.runTest(); + } + + public void testPortletName() throws Exception { + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + request.setParameter(PORTLET_NAME_ACTION_REQUEST_PARAMETER_NAME, "test"); + controller.handleActionRequest(request, response); + String result = response.getRenderParameter(RESULT_RENDER_PARAMETER_NAME); + assertEquals("wrappedPortlet", result); + } + + public void testDelegationToMockPortletConfigIfSoConfigured() throws Exception { + + final String BEAN_NAME = "Sixpence None The Richer"; + + MockActionRequest request = new MockActionRequest(); + MockActionResponse response = new MockActionResponse(); + + PortletWrappingController controller = new PortletWrappingController(); + controller.setPortletClass(MyPortlet.class); + controller.setUseSharedPortletConfig(false); + controller.setBeanName(BEAN_NAME); + controller.afterPropertiesSet(); + + request.setParameter(PORTLET_NAME_ACTION_REQUEST_PARAMETER_NAME, "true"); + controller.handleActionRequest(request, response); + + String result = response.getRenderParameter(RESULT_RENDER_PARAMETER_NAME); + assertEquals(BEAN_NAME, result); + } + + + public static final class MyPortlet implements Portlet { + + private PortletConfig portletConfig; + + + public void init(PortletConfig portletConfig) { + this.portletConfig = portletConfig; + } + + public void processAction(ActionRequest request, ActionResponse response) throws PortletException { + if (request.getParameter("test") != null) { + response.setRenderParameter(RESULT_RENDER_PARAMETER_NAME, "myPortlet-action"); + } else if (request.getParameter(PORTLET_NAME_ACTION_REQUEST_PARAMETER_NAME) != null) { + response.setRenderParameter(RESULT_RENDER_PARAMETER_NAME, getPortletConfig().getPortletName()); + } else { + throw new IllegalArgumentException("no request parameters"); + } + } + + public void render(RenderRequest request, RenderResponse response) throws IOException { + response.getWriter().write(RENDERED_RESPONSE_CONTENT); + } + + public PortletConfig getPortletConfig() { + return this.portletConfig; + } + + public void destroy() { + throw new IllegalStateException("Being destroyed..."); + } + + } + + private static final class MyApplicationContext extends StaticPortletApplicationContext { + + public void refresh() throws BeansException { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("portletClass", MyPortlet.class); + registerSingleton(PORTLET_WRAPPING_CONTROLLER_BEAN_NAME, PortletWrappingController.class, pvs); + super.refresh(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java new file mode 100644 index 00000000000..7fcd2f294ee --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java @@ -0,0 +1,605 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.portlet.PortletContext; +import javax.portlet.PortletRequest; +import javax.portlet.PortletSession; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.mock.easymock.AbstractScalarMockTemplate; +import org.springframework.mock.web.portlet.MockActionRequest; +import org.springframework.mock.web.portlet.MockActionResponse; +import org.springframework.mock.web.portlet.MockPortletContext; +import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.mock.web.portlet.MockPortletSession; +import org.springframework.test.AssertThrows; +import org.springframework.web.util.WebUtils; + +/** + * @author Rick Evans + */ +public final class PortletUtilsTests extends TestCase { + + public void testGetTempDirWithNullPortletContext() throws Exception { + new AssertThrows(IllegalArgumentException.class, "null PortletContext passed as argument") { + public void test() throws Exception { + PortletUtils.getTempDir(null); + } + }.runTest(); + } + + public void testGetTempDirSunnyDay() throws Exception { + MockPortletContext ctx = new MockPortletContext(); + Object expectedTempDir = new File("doesn't exist but that's ok in the context of this test"); + ctx.setAttribute(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, expectedTempDir); + assertSame(expectedTempDir, PortletUtils.getTempDir(ctx)); + } + + public void testGetRealPathInterpretsLocationAsRelativeToWebAppRootIfPathDoesNotBeginWithALeadingSlash() throws Exception { + final String originalPath = "web/foo"; + final String expectedRealPath = "/" + originalPath; + new AbstractScalarMockTemplate(PortletContext.class) { + public void setupExpectations(MockControl mockControl, Object mockObject) throws Exception { + PortletContext ctx = (PortletContext) mockObject; + ctx.getRealPath(expectedRealPath); + mockControl.setReturnValue(expectedRealPath); + } + public void doTest(Object mockObject) throws Exception { + PortletContext ctx = (PortletContext) mockObject; + String actualRealPath = PortletUtils.getRealPath(ctx, originalPath); + assertEquals(expectedRealPath, actualRealPath); + } + }.test(); + } + + public void testGetRealPathWithNullPortletContext() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getRealPath(null, "/foo"); + } + }.runTest(); + } + + public void testGetRealPathWithNullPath() throws Exception { + new AssertThrows(NullPointerException.class) { + public void test() throws Exception { + PortletUtils.getRealPath(new MockPortletContext(), null); + } + }.runTest(); + } + + public void testGetRealPathWithPathThatCannotBeResolvedToFile() throws Exception { + new AssertThrows(FileNotFoundException.class) { + public void test() throws Exception { + PortletUtils.getRealPath(new MockPortletContext() { + public String getRealPath(String path) { + return null; + } + }, "/rubbish"); + } + }.runTest(); + } + + public void testPassAllParametersToRenderPhase() throws Exception { + MockActionRequest request = new MockActionRequest(); + request.setParameter("William", "Baskerville"); + request.setParameter("Adso", "Melk"); + MockActionResponse response = new MockActionResponse(); + PortletUtils.passAllParametersToRenderPhase(request, response); + assertEquals("The render parameters map is obviously not being populated with the request parameters.", + request.getParameterMap().size(), response.getRenderParameterMap().size()); + } + + public void testGetParametersStartingWith() throws Exception { + final String targetPrefix = "francisan_"; + final String badKey = "dominican_Bernard"; + MockPortletRequest request = new MockPortletRequest(); + request.setParameter(targetPrefix + "William", "Baskerville"); + request.setParameter(targetPrefix + "Adso", "Melk"); + request.setParameter(badKey, "Gui"); + Map actualParameters = PortletUtils.getParametersStartingWith(request, targetPrefix); + assertNotNull("PortletUtils.getParametersStartingWith(..) must never return a null Map", actualParameters); + assertEquals("Obviously not finding all of the correct parameters", 2, actualParameters.size()); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("William")); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("Adso")); + assertFalse("Obviously not finding all of the correct parameters (is returning a parameter whose name does not start with the desired prefix", + actualParameters.containsKey(badKey)); + } + + public void testGetParametersStartingWithUnpicksScalarParameterValues() throws Exception { + final String targetPrefix = "francisan_"; + final String badKey = "dominican_Bernard"; + MockPortletRequest request = new MockPortletRequest(); + request.setParameter(targetPrefix + "William", "Baskerville"); + request.setParameter(targetPrefix + "Adso", new String[]{"Melk", "Of Melk"}); + request.setParameter(badKey, "Gui"); + Map actualParameters = PortletUtils.getParametersStartingWith(request, targetPrefix); + assertNotNull("PortletUtils.getParametersStartingWith(..) must never return a null Map", actualParameters); + assertEquals("Obviously not finding all of the correct parameters", 2, actualParameters.size()); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("William")); + assertEquals("Not picking scalar parameter value out correctly", + "Baskerville", actualParameters.get("William")); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("Adso")); + assertFalse("Obviously not finding all of the correct parameters (is returning a parameter whose name does not start with the desired prefix", + actualParameters.containsKey(badKey)); + } + + public void testGetParametersStartingWithYieldsEverythingIfTargetPrefixIsNull() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + request.setParameter("William", "Baskerville"); + request.setParameter("Adso", "Melk"); + request.setParameter("dominican_Bernard", "Gui"); + Map actualParameters = PortletUtils.getParametersStartingWith(request, null); + assertNotNull("PortletUtils.getParametersStartingWith(..) must never return a null Map", actualParameters); + assertEquals("Obviously not finding all of the correct parameters", request.getParameterMap().size(), actualParameters.size()); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("William")); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("Adso")); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("dominican_Bernard")); + } + + public void testGetParametersStartingWithYieldsEverythingIfTargetPrefixIsTheEmptyString() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + request.setParameter("William", "Baskerville"); + request.setParameter("Adso", "Melk"); + request.setParameter("dominican_Bernard", "Gui"); + Map actualParameters = PortletUtils.getParametersStartingWith(request, ""); + assertNotNull("PortletUtils.getParametersStartingWith(..) must never return a null Map", actualParameters); + assertEquals("Obviously not finding all of the correct parameters", request.getParameterMap().size(), actualParameters.size()); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("William")); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("Adso")); + assertTrue("Obviously not finding all of the correct parameters", actualParameters.containsKey("dominican_Bernard")); + } + + public void testGetParametersStartingWithYieldsEmptyNonNullMapWhenNoParamaterExistInRequest() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + Map actualParameters = PortletUtils.getParametersStartingWith(request, null); + assertNotNull("PortletUtils.getParametersStartingWith(..) must never return a null Map", actualParameters); + assertEquals("Obviously finding some parameters from somewhere (incorrectly)", + request.getParameterMap().size(), actualParameters.size()); + } + + public void testGetSubmitParameterWithStraightNameMatch() throws Exception { + final String targetSubmitParameter = "William"; + MockPortletRequest request = new MockPortletRequest(); + request.setParameter(targetSubmitParameter, "Baskerville"); + request.setParameter("Adso", "Melk"); + request.setParameter("dominican_Bernard", "Gui"); + String submitParameter = PortletUtils.getSubmitParameter(request, targetSubmitParameter); + assertNotNull(submitParameter); + assertEquals(targetSubmitParameter, submitParameter); + } + + public void testGetSubmitParameterWithPrefixedParameterMatch() throws Exception { + final String bareParameterName = "William"; + final String targetParameterName = bareParameterName + WebUtils.SUBMIT_IMAGE_SUFFIXES[0]; + MockPortletRequest request = new MockPortletRequest(); + request.setParameter(targetParameterName, "Baskerville"); + request.setParameter("Adso", "Melk"); + String submitParameter = PortletUtils.getSubmitParameter(request, bareParameterName); + assertNotNull(submitParameter); + assertEquals(targetParameterName, submitParameter); + } + + public void testGetSubmitParameterWithNoParameterMatchJustReturnsNull() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + request.setParameter("Bill", "Baskerville"); + request.setParameter("Adso", "Melk"); + String submitParameter = PortletUtils.getSubmitParameter(request, "William"); + assertNull(submitParameter); + } + + public void testGetSubmitParameterWithNullRequest() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + final String targetSubmitParameter = "William"; + MockPortletRequest request = new MockPortletRequest(); + request.setParameter(targetSubmitParameter, "Baskerville"); + request.setParameter("Adso", "Melk"); + PortletUtils.getSubmitParameter(null, targetSubmitParameter); + } + }.runTest(); + } + + public void testPassAllParametersToRenderPhaseDoesNotPropagateExceptionIfRedirectAlreadySentAtTimeOfCall() throws Exception { + MockActionRequest request = new MockActionRequest(); + request.setParameter("William", "Baskerville"); + request.setParameter("Adso", "Melk"); + MockActionResponse response = new MockActionResponse() { + public void setRenderParameter(String key, String[] values) { + throw new IllegalStateException(); + } + }; + PortletUtils.passAllParametersToRenderPhase(request, response); + assertEquals("The render parameters map must not be being populated with the request parameters (Action.sendRedirect(..) aleady called).", + 0, response.getRenderParameterMap().size()); + } + + public void testClearAllRenderParameters() throws Exception { + MockActionResponse response = new MockActionResponse(); + response.setRenderParameter("William", "Baskerville"); + response.setRenderParameter("Adso", "Melk"); + PortletUtils.clearAllRenderParameters(response); + assertEquals("The render parameters map is obviously not being cleared out.", + 0, response.getRenderParameterMap().size()); + } + + public void testClearAllRenderParametersDoesNotPropagateExceptionIfRedirectAlreadySentAtTimeOfCall() throws Exception { + MockActionResponse response = new MockActionResponse() { + public void setRenderParameters(Map parameters) { + throw new IllegalStateException(); + } + }; + response.setRenderParameter("William", "Baskerville"); + response.setRenderParameter("Adso", "Melk"); + PortletUtils.clearAllRenderParameters(response); + assertEquals("The render parameters map must not be cleared if ActionResponse.sendRedirect() has been called (already).", + 2, response.getRenderParameterMap().size()); + } + + public void testHasSubmitParameterWithStraightNameMatch() throws Exception { + final String targetSubmitParameter = "William"; + MockPortletRequest request = new MockPortletRequest(); + request.setParameter(targetSubmitParameter, "Baskerville"); + request.setParameter("Adso", "Melk"); + request.setParameter("dominican_Bernard", "Gui"); + assertTrue(PortletUtils.hasSubmitParameter(request, targetSubmitParameter)); + } + + public void testHasSubmitParameterWithPrefixedParameterMatch() throws Exception { + final String bareParameterName = "William"; + final String targetParameterName = bareParameterName + WebUtils.SUBMIT_IMAGE_SUFFIXES[0]; + MockPortletRequest request = new MockPortletRequest(); + request.setParameter(targetParameterName, "Baskerville"); + request.setParameter("Adso", "Melk"); + assertTrue(PortletUtils.hasSubmitParameter(request, bareParameterName)); + } + + public void testHasSubmitParameterWithNoParameterMatch() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + request.setParameter("Bill", "Baskerville"); + request.setParameter("Adso", "Melk"); + assertFalse(PortletUtils.hasSubmitParameter(request, "William")); + } + + public void testHasSubmitParameterWithNullRequest() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.hasSubmitParameter(null, "bingo"); + } + }.runTest(); + } + + public void testExposeRequestAttributesWithNullRequest() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.exposeRequestAttributes(null, Collections.EMPTY_MAP); + } + }.runTest(); + } + + public void testExposeRequestAttributesWithNullAttributesMap() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.exposeRequestAttributes(new MockPortletRequest(), null); + } + }.runTest(); + } + + public void testExposeRequestAttributesWithAttributesMapContainingBadKeyType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + Map attributes = new HashMap(); + attributes.put(new Object(), "bad key type"); + PortletUtils.exposeRequestAttributes(request, attributes); + } + }.runTest(); + } + + public void testExposeRequestAttributesSunnyDay() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + Map attributes = new HashMap(); + attributes.put("ace", "Rick Hunter"); + attributes.put("mentor", "Roy Fokker"); + PortletUtils.exposeRequestAttributes(request, attributes); + assertEquals("Obviously all of the entries in the supplied attributes Map are not being copied over (exposed)", + attributes.size(), countElementsIn(request.getAttributeNames())); + assertEquals("Rick Hunter", request.getAttribute("ace")); + assertEquals("Roy Fokker", request.getAttribute("mentor")); + } + + public void testExposeRequestAttributesWithEmptyAttributesMapIsAnIdempotentOperation() throws Exception { + MockPortletRequest request = new MockPortletRequest(); + Map attributes = new HashMap(); + PortletUtils.exposeRequestAttributes(request, attributes); + assertEquals("Obviously all of the entries in the supplied attributes Map are not being copied over (exposed)", + attributes.size(), countElementsIn(request.getAttributeNames())); + } + + public void testGetOrCreateSessionAttributeWithNullSession() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getOrCreateSessionAttribute(null, "bean", TestBean.class); + } + }.runTest(); + } + + public void testGetOrCreateSessionAttributeJustReturnsAttributeIfItAlreadyExists() throws Exception { + MockPortletSession session = new MockPortletSession(); + final TestBean expectedAttribute = new TestBean("Donna Tartt"); + session.setAttribute("donna", expectedAttribute); + Object actualAttribute = PortletUtils.getOrCreateSessionAttribute(session, "donna", TestBean.class); + assertSame(expectedAttribute, actualAttribute); + } + + public void testGetOrCreateSessionAttributeCreatesAttributeIfItDoesNotAlreadyExist() throws Exception { + MockPortletSession session = new MockPortletSession(); + Object actualAttribute = PortletUtils.getOrCreateSessionAttribute(session, "bean", TestBean.class); + assertNotNull(actualAttribute); + assertEquals("Wrong type of object being instantiated", TestBean.class, actualAttribute.getClass()); + } + + public void testGetOrCreateSessionAttributeWithNoExistingAttributeAndNullClass() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getOrCreateSessionAttribute(new MockPortletSession(), "bean", null); + } + }.runTest(); + } + + public void testGetOrCreateSessionAttributeWithNoExistingAttributeAndClassThatIsAnInterfaceType() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getOrCreateSessionAttribute(new MockPortletSession(), "bean", ITestBean.class); + } + }.runTest(); + } + + public void testGetOrCreateSessionAttributeWithNoExistingAttributeAndClassWithNoPublicCtor() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getOrCreateSessionAttribute(new MockPortletSession(), "bean", NoPublicCtor.class); + } + }.runTest(); + } + + public void testGetSessionMutexWithNullSession() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getSessionMutex(null); + } + }.runTest(); + } + + public void testGetSessionMutexWithNoExistingSessionMutexDefinedJustReturnsTheSessionArgument() throws Exception { + MockPortletSession session = new MockPortletSession(); + Object sessionMutex = PortletUtils.getSessionMutex(session); + assertNotNull("PortletUtils.getSessionMutex(..) must never return a null mutex", sessionMutex); + assertSame("PortletUtils.getSessionMutex(..) must return the exact same PortletSession supplied as an argument if no mutex has been bound as a Session attribute beforehand", + session, sessionMutex); + } + + public void testGetSessionMutexWithExistingSessionMutexReturnsTheExistingSessionMutex() throws Exception { + MockPortletSession session = new MockPortletSession(); + Object expectSessionMutex = new Object(); + session.setAttribute(WebUtils.SESSION_MUTEX_ATTRIBUTE, expectSessionMutex); + Object actualSessionMutex = PortletUtils.getSessionMutex(session); + assertNotNull("PortletUtils.getSessionMutex(..) must never return a null mutex", actualSessionMutex); + assertSame("PortletUtils.getSessionMutex(..) must return the bound mutex attribute if a mutex has been bound as a Session attribute beforehand", + expectSessionMutex, actualSessionMutex); + } + + public void testGetSessionAttributeWithNullPortletRequest() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getSessionAttribute(null, "foo"); + } + }.runTest(); + } + + public void testGetRequiredSessionAttributeWithNullPortletRequest() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.getRequiredSessionAttribute(null, "foo"); + } + }.runTest(); + } + + public void testSetSessionAttributeWithNullPortletRequest() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + PortletUtils.setSessionAttribute(null, "foo", "bar"); + } + }.runTest(); + } + + public void testGetSessionAttributeDoes_Not_CreateANewSession() throws Exception { + MockControl mock = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mock.getMock(); + request.getPortletSession(false); + mock.setReturnValue(null); + mock.replay(); + + Object sessionAttribute = PortletUtils.getSessionAttribute(request, "foo"); + assertNull("Must return null if session attribute does not exist (or if Session does not exist)", sessionAttribute); + mock.verify(); + } + + public void testGetSessionAttributeWithExistingSession() throws Exception { + MockControl mock = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mock.getMock(); + request.getPortletSession(false); + MockPortletSession session = new MockPortletSession(); + session.setAttribute("foo", "foo"); + mock.setReturnValue(session); + mock.replay(); + + Object sessionAttribute = PortletUtils.getSessionAttribute(request, "foo"); + assertNotNull("Must not return null if session attribute exists (and Session exists)", sessionAttribute); + assertEquals("foo", sessionAttribute); + mock.verify(); + } + + public void testGetRequiredSessionAttributeWithExistingSession() throws Exception { + MockControl mock = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mock.getMock(); + request.getPortletSession(false); + MockPortletSession session = new MockPortletSession(); + session.setAttribute("foo", "foo"); + mock.setReturnValue(session); + mock.replay(); + + Object sessionAttribute = PortletUtils.getRequiredSessionAttribute(request, "foo"); + assertNotNull("Must not return null if session attribute exists (and Session exists)", sessionAttribute); + assertEquals("foo", sessionAttribute); + mock.verify(); + } + + public void testGetRequiredSessionAttributeWithExistingSessionAndNoAttribute() throws Exception { + MockControl mock = MockControl.createControl(PortletRequest.class); + final PortletRequest request = (PortletRequest) mock.getMock(); + request.getPortletSession(false); + MockPortletSession session = new MockPortletSession(); + mock.setReturnValue(session); + mock.replay(); + new AssertThrows(IllegalStateException.class) { + public void test() throws Exception { + PortletUtils.getRequiredSessionAttribute(request, "foo"); + } + }.runTest(); + mock.verify(); + } + + public void testSetSessionAttributeWithExistingSessionAndNullValue() throws Exception { + MockControl mockSession = MockControl.createControl(PortletSession.class); + PortletSession session = (PortletSession) mockSession.getMock(); + MockControl mockRequest = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mockRequest.getMock(); + + request.getPortletSession(false); // must not create Session for null value... + mockRequest.setReturnValue(session); + session.removeAttribute("foo", PortletSession.APPLICATION_SCOPE); + mockSession.setVoidCallable(); + mockRequest.replay(); + mockSession.replay(); + + PortletUtils.setSessionAttribute(request, "foo", null, PortletSession.APPLICATION_SCOPE); + mockRequest.verify(); + mockSession.verify(); + } + + public void testSetSessionAttributeWithNoExistingSessionAndNullValue() throws Exception { + MockControl mockRequest = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mockRequest.getMock(); + + request.getPortletSession(false); // must not create Session for null value... + mockRequest.setReturnValue(null); + mockRequest.replay(); + + PortletUtils.setSessionAttribute(request, "foo", null, PortletSession.APPLICATION_SCOPE); + mockRequest.verify(); + } + + public void testSetSessionAttributeWithExistingSessionAndSpecificScope() throws Exception { + MockControl mockSession = MockControl.createControl(PortletSession.class); + PortletSession session = (PortletSession) mockSession.getMock(); + MockControl mockRequest = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mockRequest.getMock(); + + request.getPortletSession(); // must create Session... + mockRequest.setReturnValue(session); + session.setAttribute("foo", "foo", PortletSession.APPLICATION_SCOPE); + mockSession.setVoidCallable(); + mockRequest.replay(); + mockSession.replay(); + + PortletUtils.setSessionAttribute(request, "foo", "foo", PortletSession.APPLICATION_SCOPE); + mockRequest.verify(); + mockSession.verify(); + } + + public void testGetSessionAttributeWithExistingSessionAndSpecificScope() throws Exception { + MockControl mockSession = MockControl.createControl(PortletSession.class); + PortletSession session = (PortletSession) mockSession.getMock(); + MockControl mockRequest = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mockRequest.getMock(); + + request.getPortletSession(false); + mockRequest.setReturnValue(session); + session.getAttribute("foo", PortletSession.APPLICATION_SCOPE); + mockSession.setReturnValue("foo"); + mockRequest.replay(); + mockSession.replay(); + + Object sessionAttribute = PortletUtils.getSessionAttribute(request, "foo", PortletSession.APPLICATION_SCOPE); + assertNotNull("Must not return null if session attribute exists (and Session exists)", sessionAttribute); + assertEquals("foo", sessionAttribute); + mockRequest.verify(); + mockSession.verify(); + } + + public void testGetSessionAttributeWithExistingSessionDefaultsToPortletScope() throws Exception { + MockControl mockSession = MockControl.createControl(PortletSession.class); + PortletSession session = (PortletSession) mockSession.getMock(); + MockControl mockRequest = MockControl.createControl(PortletRequest.class); + PortletRequest request = (PortletRequest) mockRequest.getMock(); + + request.getPortletSession(false); + mockRequest.setReturnValue(session); + session.getAttribute("foo", PortletSession.PORTLET_SCOPE); + mockSession.setReturnValue("foo"); + mockRequest.replay(); + mockSession.replay(); + + Object sessionAttribute = PortletUtils.getSessionAttribute(request, "foo"); + assertNotNull("Must not return null if session attribute exists (and Session exists)", sessionAttribute); + assertEquals("foo", sessionAttribute); + mockRequest.verify(); + mockSession.verify(); + } + + + private static int countElementsIn(Enumeration enumeration) { + int count = 0; + while (enumeration.hasMoreElements()) { + enumeration.nextElement(); + ++count; + } + return count; + } + + + private static final class NoPublicCtor { + + private NoPublicCtor() { + throw new IllegalArgumentException("Just for eclipse..."); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java new file mode 100644 index 00000000000..18019c3a270 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java @@ -0,0 +1,461 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.context.support.ApplicationObjectSupport; +import org.springframework.core.Ordered; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.ServletRequestBindingException; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.context.request.WebRequestInterceptor; +import org.springframework.web.context.support.RequestHandledEvent; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartException; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest; +import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; +import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter; +import org.springframework.web.servlet.handler.SimpleServletPostProcessor; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; +import org.springframework.web.servlet.mvc.Controller; +import org.springframework.web.servlet.mvc.ParameterizableViewController; +import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; +import org.springframework.web.servlet.mvc.SimpleFormController; +import org.springframework.web.servlet.support.RequestContextUtils; +import org.springframework.web.servlet.theme.SessionThemeResolver; +import org.springframework.web.servlet.theme.ThemeChangeInterceptor; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.ResourceBundleViewResolver; + +/** + * @author Juergen Hoeller + * @since 21.05.2003 + */ +public class ComplexWebApplicationContext extends StaticWebApplicationContext { + + public void refresh() throws BeansException { + registerSingleton(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, SessionLocaleResolver.class); + registerSingleton(DispatcherServlet.THEME_RESOLVER_BEAN_NAME, SessionThemeResolver.class); + + LocaleChangeInterceptor interceptor1 = new LocaleChangeInterceptor(); + LocaleChangeInterceptor interceptor2 = new LocaleChangeInterceptor(); + interceptor2.setParamName("locale2"); + ThemeChangeInterceptor interceptor3 = new ThemeChangeInterceptor(); + ThemeChangeInterceptor interceptor4 = new ThemeChangeInterceptor(); + interceptor4.setParamName("theme2"); + UserRoleAuthorizationInterceptor interceptor5 = new UserRoleAuthorizationInterceptor(); + interceptor5.setAuthorizedRoles(new String[] {"role1", "role2"}); + + List interceptors = new ArrayList(); + interceptors.add(interceptor5); + interceptors.add(interceptor1); + interceptors.add(interceptor2); + interceptors.add(interceptor3); + interceptors.add(interceptor4); + interceptors.add(new MyHandlerInterceptor1()); + interceptors.add(new MyHandlerInterceptor2()); + interceptors.add(new MyWebRequestInterceptor()); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue( + "mappings", "/view.do=viewHandler\n/locale.do=localeHandler\nloc.do=anotherLocaleHandler"); + pvs.addPropertyValue("interceptors", interceptors); + registerSingleton("myUrlMapping1", SimpleUrlHandlerMapping.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue( + "mappings", "/form.do=localeHandler\n/unknown.do=unknownHandler\nservlet.do=myServlet"); + pvs.addPropertyValue("order", "2"); + registerSingleton("myUrlMapping2", SimpleUrlHandlerMapping.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue( + "mappings", "/form.do=formHandler\n/head.do=headController\n" + + "body.do=bodyController\n/noview*=noviewController\n/noview/simple*=noviewController"); + pvs.addPropertyValue("order", "1"); + registerSingleton("handlerMapping", SimpleUrlHandlerMapping.class, pvs); + + registerSingleton("myDummyAdapter", MyDummyAdapter.class); + registerSingleton("myHandlerAdapter", MyHandlerAdapter.class); + registerSingleton("standardHandlerAdapter", SimpleControllerHandlerAdapter.class); + registerSingleton("noviewController", NoViewController.class); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", new Integer(0)); + pvs.addPropertyValue("basename", "org.springframework.web.servlet.complexviews"); + registerSingleton("viewResolver", ResourceBundleViewResolver.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("suffix", ".jsp"); + registerSingleton("viewResolver2", InternalResourceViewResolver.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("commandClass", "org.springframework.beans.TestBean"); + pvs.addPropertyValue("formView", "form"); + registerSingleton("formHandler", SimpleFormController.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("viewName", "form"); + registerSingleton("viewHandler", ParameterizableViewController.class, pvs); + + registerSingleton("localeHandler", ComplexLocaleChecker.class); + registerSingleton("anotherLocaleHandler", ComplexLocaleChecker.class); + registerSingleton("unknownHandler", Object.class); + + registerSingleton("headController", HeadController.class); + registerSingleton("bodyController", BodyController.class); + + registerSingleton("servletPostProcessor", SimpleServletPostProcessor.class); + registerSingleton("handlerAdapter", SimpleServletHandlerAdapter.class); + registerSingleton("myServlet", MyServlet.class); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", "1"); + pvs.addPropertyValue("exceptionMappings", + "java.lang.IllegalAccessException=failed2\n" + + "ServletRequestBindingException=failed3"); + pvs.addPropertyValue("defaultErrorView", "failed0"); + registerSingleton("exceptionResolver1", SimpleMappingExceptionResolver.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", "0"); + pvs.addPropertyValue("exceptionMappings", "java.lang.Exception=failed1"); + List mappedHandlers = new ManagedList(); + mappedHandlers.add(new RuntimeBeanReference("anotherLocaleHandler")); + pvs.addPropertyValue("mappedHandlers", mappedHandlers); + pvs.addPropertyValue("defaultStatusCode", "500"); + pvs.addPropertyValue("defaultErrorView", "failed2"); + registerSingleton("handlerExceptionResolver", SimpleMappingExceptionResolver.class, pvs); + + registerSingleton("multipartResolver", MockMultipartResolver.class); + registerSingleton("testListener", TestApplicationListener.class); + + addMessage("test", Locale.ENGLISH, "test message"); + addMessage("test", Locale.CANADA, "Canadian & test message"); + + super.refresh(); + } + + + public static class HeadController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + if ("HEAD".equals(request.getMethod())) { + response.setContentLength(5); + } + return null; + } + } + + + public static class BodyController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + response.getOutputStream().write("body".getBytes()); + return null; + } + } + + + public static class NoViewController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + return new ModelAndView(); + } + } + + + public static class MyServlet implements Servlet { + + private ServletConfig servletConfig; + + public void init(ServletConfig servletConfig) throws ServletException { + this.servletConfig = servletConfig; + } + + public ServletConfig getServletConfig() { + return servletConfig; + } + + public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException { + servletResponse.getOutputStream().write("body".getBytes()); + } + + public String getServletInfo() { + return null; + } + + public void destroy() { + this.servletConfig = null; + } + } + + + public static interface MyHandler { + + public void doSomething(HttpServletRequest request) throws ServletException, IllegalAccessException; + + public long lastModified(); + } + + + public static class MyHandlerAdapter extends ApplicationObjectSupport implements HandlerAdapter, Ordered { + + public int getOrder() { + return 99; + } + + public boolean supports(Object handler) { + return handler != null && MyHandler.class.isAssignableFrom(handler.getClass()); + } + + public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object delegate) + throws ServletException, IllegalAccessException { + ((MyHandler) delegate).doSomething(request); + return null; + } + + public long getLastModified(HttpServletRequest request, Object delegate) { + return ((MyHandler) delegate).lastModified(); + } + } + + + public static class MyDummyAdapter extends ApplicationObjectSupport implements HandlerAdapter { + + public boolean supports(Object handler) { + return handler != null && MyHandler.class.isAssignableFrom(handler.getClass()); + } + + public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object delegate) + throws IOException, ServletException { + throw new ServletException("dummy"); + } + + public long getLastModified(HttpServletRequest request, Object delegate) { + return -1; + } + } + + + public static class MyHandlerInterceptor1 implements HandlerInterceptor { + + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws ServletException { + if (request.getAttribute("test2") != null) { + throw new ServletException("Wrong interceptor order"); + } + request.setAttribute("test1", "test1"); + request.setAttribute("test1x", "test1x"); + request.setAttribute("test1y", "test1y"); + return true; + } + + public void postHandle( + HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) + throws ServletException { + if (request.getAttribute("test2x") != null) { + throw new ServletException("Wrong interceptor order"); + } + if (!"test1x".equals(request.getAttribute("test1x"))) { + throw new ServletException("Incorrect request attribute"); + } + request.removeAttribute("test1x"); + } + + public void afterCompletion( + HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws ServletException { + if (request.getAttribute("test2y") != null) { + throw new ServletException("Wrong interceptor order"); + } + request.removeAttribute("test1y"); + } + } + + + public static class MyHandlerInterceptor2 implements HandlerInterceptor { + + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws ServletException { + if (request.getAttribute("test1x") == null) { + throw new ServletException("Wrong interceptor order"); + } + if (request.getParameter("abort") != null) { + return false; + } + request.setAttribute("test2", "test2"); + request.setAttribute("test2x", "test2x"); + request.setAttribute("test2y", "test2y"); + return true; + } + + public void postHandle( + HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) + throws ServletException { + if (request.getParameter("noView") != null) { + modelAndView.clear(); + } + if (request.getAttribute("test1x") == null) { + throw new ServletException("Wrong interceptor order"); + } + if (!"test2x".equals(request.getAttribute("test2x"))) { + throw new ServletException("Incorrect request attribute"); + } + request.removeAttribute("test2x"); + } + + public void afterCompletion( + HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + if (request.getAttribute("test1y") == null) { + throw new ServletException("Wrong interceptor order"); + } + request.removeAttribute("test2y"); + } + } + + + public static class MyWebRequestInterceptor implements WebRequestInterceptor { + + public void preHandle(WebRequest request) throws Exception { + request.setAttribute("test3", "test3", WebRequest.SCOPE_REQUEST); + } + + public void postHandle(WebRequest request, ModelMap model) throws Exception { + request.setAttribute("test3x", "test3x", WebRequest.SCOPE_REQUEST); + } + + public void afterCompletion(WebRequest request, Exception ex) throws Exception { + request.setAttribute("test3y", "test3y", WebRequest.SCOPE_REQUEST); + } + } + + + public static class ComplexLocaleChecker implements MyHandler { + + public void doSomething(HttpServletRequest request) throws ServletException, IllegalAccessException { + WebApplicationContext wac = RequestContextUtils.getWebApplicationContext(request); + if (!(wac instanceof ComplexWebApplicationContext)) { + throw new ServletException("Incorrect WebApplicationContext"); + } + if (!(request instanceof MultipartHttpServletRequest)) { + throw new ServletException("Not in a MultipartHttpServletRequest"); + } + if (!(RequestContextUtils.getLocaleResolver(request) instanceof SessionLocaleResolver)) { + throw new ServletException("Incorrect LocaleResolver"); + } + if (!Locale.CANADA.equals(RequestContextUtils.getLocale(request))) { + throw new ServletException("Incorrect Locale"); + } + if (!Locale.CANADA.equals(LocaleContextHolder.getLocale())) { + throw new ServletException("Incorrect Locale"); + } + if (!(RequestContextUtils.getThemeResolver(request) instanceof SessionThemeResolver)) { + throw new ServletException("Incorrect ThemeResolver"); + } + if (!"theme".equals(RequestContextUtils.getThemeResolver(request).resolveThemeName(request))) { + throw new ServletException("Incorrect theme name"); + } + if (request.getParameter("fail") != null) { + throw new ModelAndViewDefiningException(new ModelAndView("failed1")); + } + if (request.getParameter("access") != null) { + throw new IllegalAccessException("illegal access"); + } + if (request.getParameter("servlet") != null) { + throw new ServletRequestBindingException("servlet"); + } + if (request.getParameter("exception") != null) { + throw new RuntimeException("servlet"); + } + } + + public long lastModified() { + return 99; + } + } + + + public static class MockMultipartResolver implements MultipartResolver { + + public boolean isMultipart(HttpServletRequest request) { + return true; + } + + public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { + if (request.getAttribute("fail") != null) { + throw new MaxUploadSizeExceededException(1000); + } + if (request instanceof MultipartHttpServletRequest) { + throw new IllegalStateException("Already a multipart request"); + } + if (request.getAttribute("resolved") != null) { + throw new IllegalStateException("Already resolved"); + } + request.setAttribute("resolved", Boolean.TRUE); + return new AbstractMultipartHttpServletRequest(request) { + }; + } + + public void cleanupMultipart(MultipartHttpServletRequest request) { + if (request.getAttribute("cleanedUp") != null) { + throw new IllegalStateException("Already cleaned up"); + } + request.setAttribute("cleanedUp", Boolean.TRUE); + } + } + + + public static class TestApplicationListener implements ApplicationListener { + + public int counter = 0; + + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof RequestHandledEvent) { + this.counter++; + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java new file mode 100644 index 00000000000..86b3d0845a7 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java @@ -0,0 +1,866 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet; + +import java.io.IOException; +import java.util.Locale; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.TestBean; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.validation.BindException; +import org.springframework.web.bind.EscapedErrors; +import org.springframework.web.context.ServletConfigAwareBean; +import org.springframework.web.context.ServletContextAwareBean; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.mvc.BaseCommandController; +import org.springframework.web.servlet.mvc.Controller; +import org.springframework.web.servlet.support.RequestContext; +import org.springframework.web.servlet.support.RequestContextUtils; +import org.springframework.web.servlet.theme.AbstractThemeResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.util.WebUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + */ +public class DispatcherServletTests extends TestCase { + + private static final String URL_KNOWN_ONLY_PARENT = "/knownOnlyToParent.do"; + + private MockServletConfig servletConfig; + + private DispatcherServlet simpleDispatcherServlet; + + private DispatcherServlet complexDispatcherServlet; + + + protected void setUp() throws ServletException { + servletConfig = new MockServletConfig(new MockServletContext(), "simple"); + MockServletConfig complexConfig = new MockServletConfig(servletConfig.getServletContext(), "complex"); + complexConfig.addInitParameter("publishContext", "false"); + complexConfig.addInitParameter("class", "notWritable"); + complexConfig.addInitParameter("unknownParam", "someValue"); + + simpleDispatcherServlet = new DispatcherServlet(); + simpleDispatcherServlet.setContextClass(SimpleWebApplicationContext.class); + simpleDispatcherServlet.init(servletConfig); + + complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.addRequiredProperty("publishContext"); + complexDispatcherServlet.init(complexConfig); + } + + private ServletContext getServletContext() { + return servletConfig.getServletContext(); + } + + + public void testDispatcherServletGetServletNameDoesNotFailWithoutConfig() { + DispatcherServlet ds = new DispatcherServlet(); + assertEquals(null, ds.getServletConfig()); + assertEquals(null, ds.getServletName()); + assertEquals(null, ds.getServletContext()); + } + + public void testConfiguredDispatcherServlets() { + assertTrue("Correct namespace", + ("simple" + FrameworkServlet.DEFAULT_NAMESPACE_SUFFIX).equals(simpleDispatcherServlet.getNamespace())); + assertTrue("Correct attribute", + (FrameworkServlet.SERVLET_CONTEXT_PREFIX + "simple").equals(simpleDispatcherServlet.getServletContextAttributeName())); + assertTrue("Context published", + simpleDispatcherServlet.getWebApplicationContext() == + getServletContext().getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX + "simple")); + + assertTrue("Correct namespace", "test".equals(complexDispatcherServlet.getNamespace())); + assertTrue("Correct attribute", + (FrameworkServlet.SERVLET_CONTEXT_PREFIX + "complex").equals(complexDispatcherServlet.getServletContextAttributeName())); + assertTrue("Context not published", + getServletContext().getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX + "complex") == null); + + simpleDispatcherServlet.destroy(); + complexDispatcherServlet.destroy(); + } + + public void testInvalidRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/invalid.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + simpleDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + assertTrue("correct error code", response.getStatus() == HttpServletResponse.SC_NOT_FOUND); + } + + public void testRequestHandledEvent() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + ComplexWebApplicationContext.TestApplicationListener listener = + (ComplexWebApplicationContext.TestApplicationListener) + complexDispatcherServlet.getWebApplicationContext().getBean("testListener"); + assertEquals(1, listener.counter); + } + + public void testPublishEventsOff() throws Exception { + complexDispatcherServlet.setPublishEvents(false); + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + ComplexWebApplicationContext.TestApplicationListener listener = + (ComplexWebApplicationContext.TestApplicationListener) + complexDispatcherServlet.getWebApplicationContext().getBean("testListener"); + assertEquals(0, listener.counter); + } + + public void testFormRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/form.do"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getForwardedUrl())); + DefaultMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(new String[] {"test"}); + RequestContext rc = new RequestContext(request); + + assertTrue("hasn't RequestContext attribute", request.getAttribute("rc") == null); + assertTrue("Correct WebApplicationContext", + RequestContextUtils.getWebApplicationContext(request) instanceof SimpleWebApplicationContext); + assertTrue("Correct context path", rc.getContextPath().equals(request.getContextPath())); + assertTrue("Correct locale", Locale.CANADA.equals(RequestContextUtils.getLocale(request))); + assertTrue("Correct theme", + AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME.equals(RequestContextUtils.getTheme(request).getName())); + assertTrue("Correct message", "Canadian & test message".equals(rc.getMessage("test"))); + + assertTrue("Correct WebApplicationContext", rc.getWebApplicationContext() == simpleDispatcherServlet.getWebApplicationContext()); + assertTrue("Correct Errors", !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME) instanceof EscapedErrors)); + assertTrue("Correct Errors", !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, false) instanceof EscapedErrors)); + assertTrue("Correct Errors", rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, true) instanceof EscapedErrors); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test")); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", "default")); + assertEquals("Correct message", "default", rc.getMessage("testa", "default")); + assertEquals("Correct message", "default &", rc.getMessage("testa", null, "default &", true)); + } + + public void testParameterizableViewController() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/view.do"); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "myform.jsp".equals(response.getForwardedUrl())); + } + + public void testHandlerInterceptorSuppressesView() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/view.do"); + request.addUserRole("role1"); + request.addParameter("noView", "true"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + + public void testLocaleRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + assertEquals(98, simpleDispatcherServlet.getLastModified(request)); + simpleDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + + public void testUnknownRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testAnotherFormRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/form.do;jsessionid=xxx"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "myform.jsp".equals(response.getForwardedUrl())); + assertTrue("has RequestContext attribute", request.getAttribute("rc") != null); + DefaultMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(new String[] {"test"}); + + RequestContext rc = (RequestContext) request.getAttribute("rc"); + assertTrue("Not in HTML escaping mode", !rc.isDefaultHtmlEscape()); + assertTrue("Correct WebApplicationContext", rc.getWebApplicationContext() == complexDispatcherServlet.getWebApplicationContext()); + assertTrue("Correct context path", rc.getContextPath().equals(request.getContextPath())); + assertTrue("Correct locale", Locale.CANADA.equals(rc.getLocale())); + assertTrue("Correct Errors", !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME) instanceof EscapedErrors)); + assertTrue("Correct Errors", !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, false) instanceof EscapedErrors)); + assertTrue("Correct Errors", rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, true) instanceof EscapedErrors); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test")); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, true)); + + rc.setDefaultHtmlEscape(true); + assertTrue("Is in HTML escaping mode", rc.isDefaultHtmlEscape()); + assertTrue("Correct Errors", rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME) instanceof EscapedErrors); + assertTrue("Correct Errors", !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, false) instanceof EscapedErrors)); + assertTrue("Correct Errors", rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, true) instanceof EscapedErrors); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test")); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, true)); + } + + public void testAnotherLocaleRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do;abc=def"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + assertEquals(99, complexDispatcherServlet.getLastModified(request)); + complexDispatcherServlet.service(request, response); + + assertTrue("Not forwarded", response.getForwardedUrl() == null); + assertTrue(request.getAttribute("test1") != null); + assertTrue(request.getAttribute("test1x") == null); + assertTrue(request.getAttribute("test1y") == null); + assertTrue(request.getAttribute("test2") != null); + assertTrue(request.getAttribute("test2x") == null); + assertTrue(request.getAttribute("test2y") == null); + assertTrue(request.getAttribute("test3") != null); + assertTrue(request.getAttribute("test3x") != null); + assertTrue(request.getAttribute("test3y") != null); + } + + public void testExistingMultipartRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do;abc=def"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ComplexWebApplicationContext.MockMultipartResolver multipartResolver = + (ComplexWebApplicationContext.MockMultipartResolver) + complexDispatcherServlet.getWebApplicationContext().getBean("multipartResolver"); + MultipartHttpServletRequest multipartRequest = multipartResolver.resolveMultipart(request); + complexDispatcherServlet.service(multipartRequest, response); + multipartResolver.cleanupMultipart(multipartRequest); + assertNotNull(request.getAttribute("cleanedUp")); + } + + public void testMultipartResolutionFailed() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do;abc=def"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.setAttribute("fail", Boolean.TRUE); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to failed", "failed0.jsp".equals(response.getForwardedUrl())); + assertEquals(200, response.getStatus()); + assertTrue("correct exception", + request.getAttribute(SimpleMappingExceptionResolver.DEFAULT_EXCEPTION_ATTRIBUTE) instanceof MaxUploadSizeExceededException); + } + + public void testHandlerInterceptorAbort() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addParameter("abort", "true"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + assertTrue(request.getAttribute("test1") != null); + assertTrue(request.getAttribute("test1x") != null); + assertTrue(request.getAttribute("test1y") == null); + assertTrue(request.getAttribute("test2") == null); + assertTrue(request.getAttribute("test2x") == null); + assertTrue(request.getAttribute("test2y") == null); + } + + public void testModelAndViewDefiningException() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("fail", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertTrue("forwarded to failed", "failed1.jsp".equals(response.getForwardedUrl())); + } + catch (ServletException ex) { + fail("Should not have thrown ServletException: " + ex.getMessage()); + } + } + + public void testSimpleMappingExceptionResolverWithSpecificHandler1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("access", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed2.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof IllegalAccessException); + } + + public void testSimpleMappingExceptionResolverWithSpecificHandler2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("servlet", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed3.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof ServletException); + } + + public void testSimpleMappingExceptionResolverWithAllHandlers1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/loc.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("access", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(500, response.getStatus()); + assertEquals("forwarded to failed", "failed1.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof IllegalAccessException); + } + + public void testSimpleMappingExceptionResolverWithAllHandlers2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/loc.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("servlet", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(500, response.getStatus()); + assertEquals("forwarded to failed", "failed1.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof ServletException); + } + + public void testSimpleMappingExceptionResolverWithDefaultErrorView() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("exception", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(RuntimeException.class)); + } + + public void testLocaleChangeInterceptor1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.GERMAN); + request.addUserRole("role2"); + request.addParameter("locale", "en"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testLocaleChangeInterceptor2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.GERMAN); + request.addUserRole("role2"); + request.addParameter("locale", "en"); + request.addParameter("locale2", "en_CA"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + + public void testThemeChangeInterceptor1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("theme", "mytheme"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testThemeChangeInterceptor2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("theme", "mytheme"); + request.addParameter("theme2", "theme"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + catch (ServletException ex) { + fail("Should not have thrown ServletException: " + ex.getMessage()); + } + } + + public void testNotAuthorized() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + assertTrue("Correct response", response.getStatus() == HttpServletResponse.SC_FORBIDDEN); + } + catch (ServletException ex) { + fail("Should not have thrown ServletException: " + ex.getMessage()); + } + } + + public void testHeadMethodWithExplicitHandling() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "HEAD", "/head.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(5, response.getContentLength()); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/head.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("", response.getContentAsString()); + } + + public void testHeadMethodWithNoBodyResponse() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "HEAD", "/body.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(4, response.getContentLength()); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/body.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + } + + public void testNotDetectAllHandlerMappings() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllHandlerMappings(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue(response.getStatus() == HttpServletResponse.SC_NOT_FOUND); + } + + public void testHandlerNotMappedWithAutodetect() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + // no parent + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", + URL_KNOWN_ONLY_PARENT); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus()); + } + + public void testDetectHandlerMappingFromParent() throws ServletException, IOException { + // create a parent context that includes a mapping + StaticWebApplicationContext parent = new StaticWebApplicationContext(); + parent.setServletContext(servletConfig.getServletContext()); + parent.registerSingleton("parentHandler", ControllerFromParent.class, new MutablePropertyValues()); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("mappings", URL_KNOWN_ONLY_PARENT + "=parentHandler")); + + parent.registerSingleton("parentMapping", SimpleUrlHandlerMapping.class, pvs); + parent.refresh(); + + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + // will have parent + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + + ServletConfig config = new MockServletConfig(getServletContext(), "complex"); + config.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, parent); + complexDispatcherServlet.init(config); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", + URL_KNOWN_ONLY_PARENT); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + + assertFalse("Matched through parent controller/handler pair: not response=" + response.getStatus(), + response.getStatus() == HttpServletResponse.SC_NOT_FOUND); + } + + public void testDetectAllHandlerAdapters() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/servlet.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/form.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "myform.jsp".equals(response.getForwardedUrl())); + } + + public void testNotDetectAllHandlerAdapters() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllHandlerAdapters(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + // only ServletHandlerAdapter with bean name "handlerAdapter" detected + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/servlet.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + + // SimpleControllerHandlerAdapter not detected + request = new MockHttpServletRequest(getServletContext(), "GET", "/form.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testNotDetectAllHandlerExceptionResolvers() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllHandlerExceptionResolvers(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + assertTrue(ex.getMessage().indexOf("No adapter for handler") != -1); + } + } + + public void testNotDetectAllViewResolvers() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllViewResolvers(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + assertTrue(ex.getMessage().indexOf("failed0") != -1); + } + } + + public void testCleanupAfterIncludeWithRemove() throws ServletException, IOException { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/main.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setAttribute("test1", "value1"); + request.setAttribute("test2", "value2"); + WebApplicationContext wac = new StaticWebApplicationContext(); + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + + request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/form.do"); + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getIncludedUrl())); + + assertEquals("value1", request.getAttribute("test1")); + assertEquals("value2", request.getAttribute("test2")); + assertEquals(wac, request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)); + assertNull(request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + assertNull(request.getAttribute("command")); + } + + public void testCleanupAfterIncludeWithRestore() throws ServletException, IOException { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/main.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setAttribute("test1", "value1"); + request.setAttribute("test2", "value2"); + WebApplicationContext wac = new StaticWebApplicationContext(); + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + TestBean command = new TestBean(); + request.setAttribute("command", command); + + request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/form.do"); + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getIncludedUrl())); + + assertEquals("value1", request.getAttribute("test1")); + assertEquals("value2", request.getAttribute("test2")); + assertSame(wac, request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)); + assertSame(command, request.getAttribute("command")); + } + + public void testNoCleanupAfterInclude() throws ServletException, IOException { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/main.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setAttribute("test1", "value1"); + request.setAttribute("test2", "value2"); + WebApplicationContext wac = new StaticWebApplicationContext(); + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + TestBean command = new TestBean(); + request.setAttribute("command", command); + + request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/form.do"); + simpleDispatcherServlet.setCleanupAfterInclude(false); + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getIncludedUrl())); + + assertEquals("value1", request.getAttribute("test1")); + assertEquals("value2", request.getAttribute("test2")); + assertSame(wac, request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)); + assertNotSame(command, request.getAttribute("command")); + } + + public void testServletHandlerAdapter() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/servlet.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + + Servlet myServlet = (Servlet) complexDispatcherServlet.getWebApplicationContext().getBean("myServlet"); + assertEquals("complex", myServlet.getServletConfig().getServletName()); + assertEquals(getServletContext(), myServlet.getServletConfig().getServletContext()); + complexDispatcherServlet.destroy(); + assertNull(myServlet.getServletConfig()); + } + + public void testThrowawayController() throws Exception { + SimpleWebApplicationContext.TestThrowawayController.counter = 0; + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/throwaway.do"); + request.addParameter("myInt", "5"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + simpleDispatcherServlet.service(request, response); + assertTrue("Correct response", "view5".equals(response.getForwardedUrl())); + assertEquals(1, SimpleWebApplicationContext.TestThrowawayController.counter); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/throwaway.do"); + request.addParameter("myInt", "5"); + response = new MockHttpServletResponse(); + + simpleDispatcherServlet.service(request, response); + assertTrue("Correct response", "view5".equals(response.getForwardedUrl())); + assertEquals(2, SimpleWebApplicationContext.TestThrowawayController.counter); + } + + public void testThrowawayControllerWithBindingFailure() throws Exception { + SimpleWebApplicationContext.TestThrowawayController.counter = 0; + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/throwaway.do"); + request.addParameter("myInt", "5x"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + try { + simpleDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + assertTrue(ex.getRootCause() instanceof BindException); + assertEquals(1, SimpleWebApplicationContext.TestThrowawayController.counter); + } + } + + public void testWebApplicationContextLookup() { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/invalid.do"); + + try { + RequestContextUtils.getWebApplicationContext(request); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + + try { + RequestContextUtils.getWebApplicationContext(request, servletContext); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, + new StaticWebApplicationContext()); + try { + RequestContextUtils.getWebApplicationContext(request, servletContext); + } + catch (IllegalStateException ex) { + fail("Should not have thrown IllegalStateException: " + ex.getMessage()); + } + } + + public void testWithNoView() throws Exception { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/noview.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + complexDispatcherServlet.service(request, response); + assertEquals("noview.jsp", response.getForwardedUrl()); + } + + public void testWithNoViewNested() throws Exception { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/noview/simple.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + complexDispatcherServlet.service(request, response); + assertEquals("noview/simple.jsp", response.getForwardedUrl()); + } + + public void testWithNoViewAndSamePath() throws Exception { + InternalResourceViewResolver vr = (InternalResourceViewResolver) + complexDispatcherServlet.getWebApplicationContext().getBean("viewResolver2"); + vr.setSuffix(""); + + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/noview"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + try { + complexDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + ex.printStackTrace(); + } + } + + public void testDispatcherServletRefresh() throws ServletException { + MockServletContext servletContext = new MockServletContext("org/springframework/web/context"); + DispatcherServlet servlet = new DispatcherServlet(); + + servlet.init(new MockServletConfig(servletContext, "empty")); + ServletContextAwareBean contextBean = (ServletContextAwareBean) + servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean = (ServletConfigAwareBean) + servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean.getServletContext()); + assertSame(servlet.getServletConfig(), configBean.getServletConfig()); + MultipartResolver multipartResolver = servlet.getMultipartResolver(); + assertNotNull(multipartResolver); + + servlet.refresh(); + + ServletContextAwareBean contextBean2 = (ServletContextAwareBean) + servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean2 = (ServletConfigAwareBean) + servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean2.getServletContext()); + assertSame(servlet.getServletConfig(), configBean2.getServletConfig()); + assertTrue(contextBean != contextBean2); + assertTrue(configBean != configBean2); + MultipartResolver multipartResolver2 = servlet.getMultipartResolver(); + assertTrue(multipartResolver != multipartResolver2); + + servlet.destroy(); + } + + public void testDispatcherServletContextRefresh() throws ServletException { + MockServletContext servletContext = new MockServletContext("org/springframework/web/context"); + DispatcherServlet servlet = new DispatcherServlet(); + + servlet.init(new MockServletConfig(servletContext, "empty")); + ServletContextAwareBean contextBean = (ServletContextAwareBean) + servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean = (ServletConfigAwareBean) + servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean.getServletContext()); + assertSame(servlet.getServletConfig(), configBean.getServletConfig()); + MultipartResolver multipartResolver = servlet.getMultipartResolver(); + assertNotNull(multipartResolver); + + ((ConfigurableApplicationContext) servlet.getWebApplicationContext()).refresh(); + + ServletContextAwareBean contextBean2 = (ServletContextAwareBean) + servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean2 = (ServletConfigAwareBean) + servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean2.getServletContext()); + assertSame(servlet.getServletConfig(), configBean2.getServletConfig()); + assertTrue(contextBean != contextBean2); + assertTrue(configBean != configBean2); + MultipartResolver multipartResolver2 = servlet.getMultipartResolver(); + assertTrue(multipartResolver != multipartResolver2); + + servlet.destroy(); + } + + + public static class ControllerFromParent implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + return new ModelAndView(ControllerFromParent.class.getName()); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java new file mode 100644 index 00000000000..8e36eb9e12e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java @@ -0,0 +1,141 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet; + +import java.io.IOException; +import java.util.Locale; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.context.support.StaticMessageSource; +import org.springframework.ui.context.Theme; +import org.springframework.ui.context.ThemeSource; +import org.springframework.ui.context.support.SimpleTheme; +import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; +import org.springframework.web.servlet.mvc.Controller; +import org.springframework.web.servlet.mvc.LastModified; +import org.springframework.web.servlet.mvc.SimpleFormController; +import org.springframework.web.servlet.mvc.throwaway.ThrowawayController; +import org.springframework.web.servlet.support.RequestContextUtils; +import org.springframework.web.servlet.theme.AbstractThemeResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.XmlViewResolver; +import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; + +/** + * @author Juergen Hoeller + * @since 21.05.2003 + */ +public class SimpleWebApplicationContext extends StaticWebApplicationContext { + + public void refresh() throws BeansException { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("commandClass", "org.springframework.beans.TestBean"); + pvs.addPropertyValue("formView", "form"); + registerSingleton("/form.do", SimpleFormController.class, pvs); + + registerSingleton("/locale.do", LocaleChecker.class); + + registerPrototype("/throwaway.do", TestThrowawayController.class); + + addMessage("test", Locale.ENGLISH, "test message"); + addMessage("test", Locale.CANADA, "Canadian & test message"); + addMessage("testArgs", Locale.ENGLISH, "test {0} message {1}"); + addMessage("testArgsFormat", Locale.ENGLISH, "test {0} message {1,number,#.##} X"); + + registerSingleton(UiApplicationContextUtils.THEME_SOURCE_BEAN_NAME, DummyThemeSource.class); + + registerSingleton("handlerMapping", BeanNameUrlHandlerMapping.class); + registerSingleton("viewResolver", InternalResourceViewResolver.class); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("location", "org/springframework/web/context/WEB-INF/sessionContext.xml"); + registerSingleton("viewResolver2", XmlViewResolver.class, pvs); + + super.refresh(); + } + + + public static class LocaleChecker implements Controller, LastModified { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if (!(RequestContextUtils.getWebApplicationContext(request) instanceof SimpleWebApplicationContext)) { + throw new ServletException("Incorrect WebApplicationContext"); + } + if (!(RequestContextUtils.getLocaleResolver(request) instanceof AcceptHeaderLocaleResolver)) { + throw new ServletException("Incorrect LocaleResolver"); + } + if (!Locale.CANADA.equals(RequestContextUtils.getLocale(request))) { + throw new ServletException("Incorrect Locale"); + } + return null; + } + + public long getLastModified(HttpServletRequest request) { + return 98; + } + } + + + public static class DummyThemeSource implements ThemeSource { + + private StaticMessageSource messageSource; + + public DummyThemeSource() { + this.messageSource = new StaticMessageSource(); + this.messageSource.addMessage("themetest", Locale.ENGLISH, "theme test message"); + this.messageSource.addMessage("themetestArgs", Locale.ENGLISH, "theme test message {0}"); + } + + public Theme getTheme(String themeName) { + if (AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME.equals(themeName)) { + return new SimpleTheme(AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME, this.messageSource); + } + else { + return null; + } + } + } + + + public static class TestThrowawayController implements ThrowawayController { + + public static int counter = 0; + + private int myInt; + + public TestThrowawayController() { + counter++; + } + + public void setMyInt(int myInt) { + this.myInt = myInt; + } + + public ModelAndView execute() throws Exception { + return new ModelAndView("view" + this.myInt); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/complexviews.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/complexviews.properties new file mode 100644 index 00000000000..6917be21627 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/complexviews.properties @@ -0,0 +1,3 @@ +form.(class)=org.springframework.web.servlet.view.InternalResourceView +form.requestContextAttribute=rc +form.url=myform.jsp diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/BeanNameUrlHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/BeanNameUrlHandlerMappingTests.java new file mode 100644 index 00000000000..e6301e7d0df --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/BeanNameUrlHandlerMappingTests.java @@ -0,0 +1,192 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.handler; + +import javax.servlet.ServletException; + +import junit.framework.TestCase; + +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class BeanNameUrlHandlerMappingTests extends TestCase { + + public static final String CONF = "/org/springframework/web/servlet/handler/map1.xml"; + + private ConfigurableWebApplicationContext wac; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + wac = new XmlWebApplicationContext(); + wac.setServletContext(sc); + wac.setConfigLocations(new String[] {CONF}); + wac.refresh(); + } + + public void testRequestsWithoutHandlers() throws Exception { + HandlerMapping hm = (HandlerMapping) wac.getBean("handlerMapping"); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/mypath/nonsense.html"); + req.setContextPath("/myapp"); + Object h = hm.getHandler(req); + assertTrue("Handler is null", h == null); + + req = new MockHttpServletRequest("GET", "/foo/bar/baz.html"); + h = hm.getHandler(req); + assertTrue("Handler is null", h == null); + } + + public void testRequestsWithSubPaths() throws Exception { + HandlerMapping hm = (HandlerMapping) wac.getBean("handlerMapping"); + doTestRequestsWithSubPaths(hm); + } + + public void testRequestsWithSubPathsInParentContext() throws Exception { + BeanNameUrlHandlerMapping hm = new BeanNameUrlHandlerMapping(); + hm.setDetectHandlersInAncestorContexts(true); + hm.setApplicationContext(new StaticApplicationContext(wac)); + doTestRequestsWithSubPaths(hm); + } + + private void doTestRequestsWithSubPaths(HandlerMapping hm) throws Exception { + Object bean = wac.getBean("godCtrl"); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/mypath/welcome.html"); + HandlerExecutionChain hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/myapp/mypath/welcome.html"); + req.setContextPath("/myapp"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/myapp/mypath/welcome.html"); + req.setContextPath("/myapp"); + req.setServletPath("/mypath/welcome.html"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/myapp/myservlet/mypath/welcome.html"); + req.setContextPath("/myapp"); + req.setServletPath("/myservlet"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/myapp/myapp/mypath/welcome.html"); + req.setContextPath("/myapp"); + req.setServletPath("/myapp"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/mypath/show.html"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/mypath/bookseats.html"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + } + + public void testRequestsWithFullPaths() throws Exception { + BeanNameUrlHandlerMapping hm = new BeanNameUrlHandlerMapping(); + hm.setAlwaysUseFullPath(true); + hm.setApplicationContext(wac); + Object bean = wac.getBean("godCtrl"); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/mypath/welcome.html"); + HandlerExecutionChain hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/myapp/mypath/welcome.html"); + req.setContextPath("/myapp"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/mypath/welcome.html"); + req.setContextPath(""); + req.setServletPath("/mypath"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/Myapp/mypath/welcome.html"); + req.setContextPath("/myapp"); + req.setServletPath("/mypath"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + } + + public void testAsteriskMatches() throws Exception { + HandlerMapping hm = (HandlerMapping) wac.getBean("handlerMapping"); + Object bean = wac.getBean("godCtrl"); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/mypath/test.html"); + HandlerExecutionChain hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/mypath/testarossa"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/mypath/tes"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec == null); + } + + public void testOverlappingMappings() throws Exception { + BeanNameUrlHandlerMapping hm = (BeanNameUrlHandlerMapping) wac.getBean("handlerMapping"); + Object anotherHandler = new Object(); + hm.registerHandler("/mypath/testaross*", anotherHandler); + Object bean = wac.getBean("godCtrl"); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/mypath/test.html"); + HandlerExecutionChain hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/mypath/testarossa"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == anotherHandler); + + req = new MockHttpServletRequest("GET", "/mypath/tes"); + hec = hm.getHandler(req); + assertTrue("Handler is correct bean", hec == null); + } + + public void testDoubleMappings() throws ServletException { + BeanNameUrlHandlerMapping hm = (BeanNameUrlHandlerMapping) wac.getBean("handlerMapping"); + try { + hm.registerHandler("/mypath/welcome.html", new Object()); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/PathMatchingUrlHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/PathMatchingUrlHandlerMappingTests.java new file mode 100644 index 00000000000..c0add0066d3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/PathMatchingUrlHandlerMappingTests.java @@ -0,0 +1,251 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.handler; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Alef Arendsen + * @author Juergen Hoeller + */ +public class PathMatchingUrlHandlerMappingTests extends TestCase { + + public static final String CONF = "/org/springframework/web/servlet/handler/map3.xml"; + + private HandlerMapping hm; + + private ConfigurableWebApplicationContext wac; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + wac = new XmlWebApplicationContext(); + wac.setServletContext(sc); + wac.setConfigLocations(new String[] {CONF}); + wac.refresh(); + hm = (HandlerMapping) wac.getBean("urlMapping"); + } + + public void testRequestsWithHandlers() throws Exception { + Object bean = wac.getBean("mainController"); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/welcome.html"); + HandlerExecutionChain hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/show.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/bookseats.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + } + + public void testActualPathMatching() throws Exception { + // there a couple of mappings defined with which we can test the + // path matching, let's do that... + + Object bean = wac.getBean("mainController"); + Object defaultBean = wac.getBean("starController"); + + // testing some normal behavior + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/pathmatchingTest.html"); + HandlerExecutionChain hec = getHandler(req); + assertTrue("Handler is null", hec != null); + assertTrue("Handler is correct bean", hec.getHandler() == bean); + assertEquals("pathmatchingTest.html", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + + // no match, no forward slash included + req = new MockHttpServletRequest("GET", "welcome.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + assertEquals("welcome.html", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + + // testing some ????? behavior + req = new MockHttpServletRequest("GET", "/pathmatchingAA.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + assertEquals("pathmatchingAA.html", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + + // testing some ????? behavior + req = new MockHttpServletRequest("GET", "/pathmatchingA.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + assertEquals("/pathmatchingA.html", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + + // testing some ????? behavior + req = new MockHttpServletRequest("GET", "/administrator/pathmatching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + // testing simple /**/behavior + req = new MockHttpServletRequest("GET", "/administrator/test/pathmatching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + // this should not match because of the administratorT + req = new MockHttpServletRequest("GET", "/administratort/pathmatching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + // this should match because of *.jsp + req = new MockHttpServletRequest("GET", "/bla.jsp"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + // this as well, because there's a **/in there as well + req = new MockHttpServletRequest("GET", "/testing/bla.jsp"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + // should match because because exact pattern is there + req = new MockHttpServletRequest("GET", "/administrator/another/bla.xml"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + // should not match, because there's not .gif extension in there + req = new MockHttpServletRequest("GET", "/administrator/another/bla.gif"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + // should match because there testlast* in there + req = new MockHttpServletRequest("GET", "/administrator/test/testlastbit"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + // but this not, because it's testlast and not testla + req = new MockHttpServletRequest("GET", "/administrator/test/testla"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/administrator/testing/longer/bla"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/administrator/testing/longer/test.jsp"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/administrator/testing/longer2/notmatching/notmatching"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/shortpattern/testing/toolong"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/XXpathXXmatching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/pathXXmatching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/XpathXXmatching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/XXpathmatching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/show12.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/show123.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/show1.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/reallyGood-test-is-this.jpeg"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/reallyGood-tst-is-this.jpeg"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/testing/test.jpeg"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/testing/test.jpg"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/anotherTest"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/stillAnotherTest"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + // there outofpattern*yeah in the pattern, so this should fail + req = new MockHttpServletRequest("GET", "/outofpattern*ye"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/test't est/path'm atching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + + req = new MockHttpServletRequest("GET", "/test%26t%20est/path%26m%20atching.html"); + hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + } + + public void testDefaultMapping() throws Exception { + Object bean = wac.getBean("starController"); + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/goggog.html"); + HandlerExecutionChain hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + } + + public void testMappingExposedInRequest() throws Exception { + Object bean = wac.getBean("mainController"); + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/show.html"); + HandlerExecutionChain hec = getHandler(req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + assertEquals("Mapping not exposed", "show.html", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + } + + private HandlerExecutionChain getHandler(MockHttpServletRequest req) throws Exception { + HandlerExecutionChain hec = hm.getHandler(req); + HandlerInterceptor[] interceptors = hec.getInterceptors(); + if (interceptors != null) { + for (int i = 0; i < interceptors.length; i++) { + interceptors[i].preHandle(req, null, hec.getHandler()); + } + } + return hec; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolverTests.java new file mode 100644 index 00000000000..94c132a13c8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolverTests.java @@ -0,0 +1,243 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.handler; + +import java.util.Collections; +import java.util.Properties; + +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.util.WebUtils; + +/** + * @author Seth Ladd + * @author Juergen Hoeller + */ +public class SimpleMappingExceptionResolverTests extends TestCase { + + private SimpleMappingExceptionResolver exceptionResolver; + private MockHttpServletRequest request; + private MockHttpServletResponse response; + private Object handler1; + private Object handler2; + private Exception genericException; + + protected void setUp() throws Exception { + exceptionResolver = new SimpleMappingExceptionResolver(); + handler1 = new String(); + handler2 = new Object(); + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + request.setMethod("GET"); + genericException = new Exception(); + } + + public void testSetOrder() { + exceptionResolver.setOrder(2); + assertEquals(2, exceptionResolver.getOrder()); + } + + public void testDefaultErrorView() { + exceptionResolver.setDefaultErrorView("default-view"); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("default-view", mav.getViewName()); + assertEquals(genericException, mav.getModel().get(SimpleMappingExceptionResolver.DEFAULT_EXCEPTION_ATTRIBUTE)); + } + + public void testDefaultErrorViewDifferentHandler() { + exceptionResolver.setDefaultErrorView("default-view"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull(mav); + } + + public void testDefaultErrorViewDifferentHandlerClass() { + exceptionResolver.setDefaultErrorView("default-view"); + exceptionResolver.setMappedHandlerClasses(new Class[] {String.class}); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull(mav); + } + + public void testNullExceptionAttribute() { + exceptionResolver.setDefaultErrorView("default-view"); + exceptionResolver.setExceptionAttribute(null); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("default-view", mav.getViewName()); + assertNull(mav.getModel().get(SimpleMappingExceptionResolver.DEFAULT_EXCEPTION_ATTRIBUTE)); + } + + public void testNullExceptionMappings() { + exceptionResolver.setExceptionMappings(null); + exceptionResolver.setDefaultErrorView("default-view"); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("default-view", mav.getViewName()); + } + + public void testNoDefaultStatusCode() { + exceptionResolver.setDefaultErrorView("default-view"); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + } + + public void testSetDefaultStatusCode() { + exceptionResolver.setDefaultErrorView("default-view"); + exceptionResolver.setDefaultStatusCode(HttpServletResponse.SC_BAD_REQUEST); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); + } + + public void testNoDefaultStatusCodeInInclude() { + exceptionResolver.setDefaultErrorView("default-view"); + exceptionResolver.setDefaultStatusCode(HttpServletResponse.SC_BAD_REQUEST); + request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "some path"); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + } + + public void testSimpleExceptionMapping() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + exceptionResolver.setWarnLogCategory("HANDLER_EXCEPTION"); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testExactExceptionMappingWithHandlerSpecified() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testExactExceptionMappingWithHandlerClassSpecified() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + exceptionResolver.setMappedHandlerClasses(new Class[] {String.class}); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testExactExceptionMappingWithHandlerInterfaceSpecified() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + exceptionResolver.setMappedHandlerClasses(new Class[] {Comparable.class}); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testSimpleExceptionMappingWithHandlerSpecifiedButWrongHandler() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull(mav); + } + + public void testSimpleExceptionMappingWithHandlerClassSpecifiedButWrongHandler() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + exceptionResolver.setMappedHandlerClasses(new Class[] {String.class}); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler2, genericException); + assertNull(mav); + } + + public void testMissingExceptionInMapping() { + Properties props = new Properties(); + props.setProperty("SomeFooThrowable", "error"); + exceptionResolver.setWarnLogCategory("HANDLER_EXCEPTION"); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertNull(mav); + } + + public void testTwoMappings() { + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("AnotherException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testTwoMappingsOneShortOneLong() { + Properties props = new Properties(); + props.setProperty("Exception", "error"); + props.setProperty("AnotherException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, genericException); + assertEquals("error", mav.getViewName()); + } + + public void testTwoMappingsOneShortOneLongThrowOddException() { + Exception oddException = new SomeOddException(); + Properties props = new Properties(); + props.setProperty("Exception", "error"); + props.setProperty("SomeOddException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("error", mav.getViewName()); + } + + public void testTwoMappingsThrowOddExceptionUseLongExceptionMapping() { + Exception oddException = new SomeOddException(); + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("SomeOddException", "another-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("another-error", mav.getViewName()); + } + + public void testThreeMappings() { + Exception oddException = new AnotherOddException(); + Properties props = new Properties(); + props.setProperty("java.lang.Exception", "error"); + props.setProperty("SomeOddException", "another-error"); + props.setProperty("AnotherOddException", "another-some-error"); + exceptionResolver.setMappedHandlers(Collections.singleton(handler1)); + exceptionResolver.setExceptionMappings(props); + ModelAndView mav = exceptionResolver.resolveException(request, response, handler1, oddException); + assertEquals("another-some-error", mav.getViewName()); + } + + + private static class SomeOddException extends Exception { + + } + + + private static class AnotherOddException extends Exception { + + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java new file mode 100644 index 00000000000..750da2c1884 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java @@ -0,0 +1,142 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.handler; + +import junit.framework.TestCase; + +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.util.WebUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class SimpleUrlHandlerMappingTests extends TestCase { + + public void testHandlerBeanNotFound() throws Exception { + MockServletContext sc = new MockServletContext(""); + XmlWebApplicationContext root = new XmlWebApplicationContext(); + root.setServletContext(sc); + root.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map1.xml"}); + root.refresh(); + XmlWebApplicationContext wac = new XmlWebApplicationContext(); + wac.setParent(root); + wac.setServletContext(sc); + wac.setNamespace("map2err"); + wac.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map2err.xml"}); + try { + wac.refresh(); + fail("Should have thrown NoSuchBeanDefinitionException"); + } + catch (FatalBeanException ex) { + NoSuchBeanDefinitionException nestedEx = (NoSuchBeanDefinitionException) ex.getCause(); + assertEquals("mainControlle", nestedEx.getBeanName()); + } + } + + public void testUrlMappingWithUrlMap() throws Exception { + checkMappings("urlMapping"); + } + + public void testUrlMappingWithProps() throws Exception { + checkMappings("urlMappingWithProps"); + } + + private void checkMappings(String beanName) throws Exception { + MockServletContext sc = new MockServletContext(""); + XmlWebApplicationContext wac = new XmlWebApplicationContext(); + wac.setServletContext(sc); + wac.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map2.xml"}); + wac.refresh(); + Object bean = wac.getBean("mainController"); + Object otherBean = wac.getBean("otherController"); + Object defaultBean = wac.getBean("starController"); + HandlerMapping hm = (HandlerMapping) wac.getBean(beanName); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/welcome.html"); + HandlerExecutionChain hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + assertEquals("/welcome.html", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + + req = new MockHttpServletRequest("GET", "/welcome.x"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == otherBean); + assertEquals("welcome.x", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + + req = new MockHttpServletRequest("GET", "/"); + req.setServletPath("/welcome.html"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/welcome.html"); + req.setContextPath("/app"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/show.html"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/bookseats.html"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/original-welcome.html"); + req.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/welcome.html"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/original-show.html"); + req.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/show.html"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/original-bookseats.html"); + req.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/bookseats.html"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + + req = new MockHttpServletRequest("GET", "/"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); + assertEquals("/", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + + req = new MockHttpServletRequest("GET", "/somePath"); + hec = getHandler(hm, req); + assertTrue("Handler is correct bean", hec != null && hec.getHandler() == defaultBean); + assertEquals("/somePath", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + } + + private HandlerExecutionChain getHandler(HandlerMapping hm, MockHttpServletRequest req) throws Exception { + HandlerExecutionChain hec = hm.getHandler(req); + HandlerInterceptor[] interceptors = hec.getInterceptors(); + if (interceptors != null) { + for (int i = 0; i < interceptors.length; i++) { + interceptors[i].preHandle(req, null, hec.getHandler()); + } + } + return hec; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map1.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map1.xml new file mode 100644 index 00000000000..f4b473bb158 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.properties b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.properties new file mode 100644 index 00000000000..581757cbe34 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.properties @@ -0,0 +1,7 @@ +/welcome*=otherController +/welcome.html= mainController \n +/show.html=mainController +/bookseats.html=mainController +/reservation.html=mainController +/payment.html=mainController +/confirmation.html=mainController diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.xml new file mode 100644 index 00000000000..9e895318381 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /org/springframework/web/servlet/handler/map2.properties + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2err.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2err.xml new file mode 100644 index 00000000000..08f51cffe85 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map2err.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + /org/springframework/web/servlet/handler/map2.properties + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map3.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map3.xml new file mode 100644 index 00000000000..bc7a9e49a19 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/map3.xml @@ -0,0 +1,45 @@ + + + + + + + true + + + welcome.html=mainController + /**/pathmatchingTest.html=mainController + /**/pathmatching??.html=mainController + /**/path??matching.html=mainController + /**/??path??matching.html=mainController + /**/*.jsp=mainController + /administrator/**/pathmatching.html=mainController + /administrator/**/testlast*=mainController + /administrator/another/bla.xml=mainController + /administrator/testing/longer/**/**/**/**/**=mainController + /administrator/testing/longer2/**/**/bla/**=mainController + /*test*.jpeg=mainController + /*/test.jpeg=mainController + /outofpattern*yeah=mainController + /anotherTest*=mainController + /stillAnotherTestYeah=mainController + /shortpattern/testing=mainController + /show123.html=mainController + /sho*=mainController + /bookseats.html=mainController + /reservation.html=mainController + /payment.html=mainController + /confirmation.html=mainController + /test%26t%20est/path%26m%20atching.html=mainController + *=starController + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/BeanPropertyController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/BeanPropertyController.java new file mode 100644 index 00000000000..d8b248c948e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/BeanPropertyController.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.handler.metadata; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.ITestBean; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +/** + * @author Juergen Hoeller + * + * @@PathMap("/constructor.cgi") + */ +public class BeanPropertyController implements Controller { + + public ITestBean testBean; + + public void setTestBean(ITestBean testBean) { + this.testBean = testBean; + } + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + return new ModelAndView("test"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/ConstructorController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/ConstructorController.java new file mode 100644 index 00000000000..a69fd377c73 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/ConstructorController.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.handler.metadata; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.ITestBean; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +/** + * @author Rod Johnson + * + * @@PathMap("/constructor.cgi") + */ +public class ConstructorController implements Controller { + + public ITestBean testBean; + + public ConstructorController(ITestBean testBean) { + this.testBean = testBean; + } + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + return new ModelAndView("test"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/PathMapHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/PathMapHandlerMappingTests.java new file mode 100644 index 00000000000..d1df6745dda --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/handler/metadata/PathMapHandlerMappingTests.java @@ -0,0 +1,221 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.handler.metadata; + +import java.util.HashMap; + +import junit.framework.TestCase; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; + +/** + * @author Rod Johnson + */ +public class PathMapHandlerMappingTests extends TestCase { + + public void testSatisfiedConstructorDependency() throws Exception { + String path = "/Constructor.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("test", TestBean.class, new MutablePropertyValues()); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.register(ConstructorController.class, new PathMap(path)); + hm.setApplicationContext(wac); + + ConstructorController cc = (ConstructorController) wac.getBean(ConstructorController.class.getName()); + assertSame(wac.getBean("test"), cc.testBean); + HandlerExecutionChain chain = hm.getHandler(new MockHttpServletRequest("GET", path)); + assertNotNull(chain); + assertEquals("Path is mapped correctly based on attribute", cc, chain.getHandler()); + chain = hm.getHandler(new MockHttpServletRequest("GET", "completeRubbish.html")); + assertNull("Don't know anything about this path", chain); + } + + public void testUnsatisfiedConstructorDependency() throws Exception { + String path = "/Constructor.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + // No registration of a TestBean + //wac.registerSingleton("test", TestBean.class, new MutablePropertyValues()); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.register(ConstructorController.class, new PathMap(path)); + try { + hm.setApplicationContext(wac); + fail("DependencyCheck should have failed"); + } + catch (UnsatisfiedDependencyException ex) { + // Ok + } + } + + public void testSatisfiedBeanPropertyDependency() throws Exception { + String path = "/BeanProperty.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("test", TestBean.class, new MutablePropertyValues()); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.register(BeanPropertyController.class, new PathMap(path)); + hm.setApplicationContext(wac); + + BeanPropertyController bpc = (BeanPropertyController) wac.getBean(BeanPropertyController.class.getName()); + assertSame(wac.getBean("test"), bpc.testBean); + HandlerExecutionChain chain = hm.getHandler(new MockHttpServletRequest("GET", path)); + assertNotNull(chain); + assertEquals("Path is mapped correctly based on attribute", bpc, chain.getHandler()); + chain = hm.getHandler(new MockHttpServletRequest("GET", "completeRubbish.html")); + assertNull("Don't know anything about this path", chain); + } + + public void testSatisfiedBeanPropertyDependencyWithAutowireByType() throws Exception { + String path = "/BeanProperty.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("test", TestBean.class, new MutablePropertyValues()); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); + hm.register(BeanPropertyController.class, new PathMap(path)); + hm.setApplicationContext(wac); + + BeanPropertyController bpc = (BeanPropertyController) wac.getBean(BeanPropertyController.class.getName()); + assertSame(wac.getBean("test"), bpc.testBean); + HandlerExecutionChain chain = hm.getHandler(new MockHttpServletRequest("GET", path)); + assertNotNull(chain); + assertEquals("Path is mapped correctly based on attribute", bpc, chain.getHandler()); + chain = hm.getHandler(new MockHttpServletRequest("GET", "completeRubbish.html")); + assertNull("Don't know anything about this path", chain); + } + + public void testUnsatisfiedBeanPropertyDependencyWithAutowireByType() throws Exception { + String path = "/BeanProperty.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.setAutowireModeName("AUTOWIRE_BY_TYPE"); + hm.register(BeanPropertyController.class, new PathMap(path)); + try { + hm.setApplicationContext(wac); + fail("DependencyCheck should have failed"); + } + catch (UnsatisfiedDependencyException ex) { + // Ok + } + } + + public void testSatisfiedBeanPropertyDependencyWithAutowireByName() throws Exception { + String path = "/BeanProperty.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("testBean", TestBean.class, new MutablePropertyValues()); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.setAutowireModeName("AUTOWIRE_BY_NAME"); + hm.register(BeanPropertyController.class, new PathMap(path)); + hm.setApplicationContext(wac); + + BeanPropertyController bpc = (BeanPropertyController) wac.getBean(BeanPropertyController.class.getName()); + assertSame(wac.getBean("testBean"), bpc.testBean); + HandlerExecutionChain chain = hm.getHandler(new MockHttpServletRequest("GET", path)); + assertNotNull(chain); + assertEquals("Path is mapped correctly based on attribute", bpc, chain.getHandler()); + chain = hm.getHandler(new MockHttpServletRequest("GET", "completeRubbish.html")); + assertNull("Don't know anything about this path", chain); + } + + public void testUnsatisfiedBeanPropertyDependencyWithAutowireByName() throws Exception { + String path = "/BeanProperty.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("test", TestBean.class, new MutablePropertyValues()); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME); + hm.register(BeanPropertyController.class, new PathMap(path)); + try { + hm.setApplicationContext(wac); + fail("DependencyCheck should have failed"); + } + catch (UnsatisfiedDependencyException ex) { + // Ok + } + } + + public void testUnsatisfiedBeanPropertyDependencyWithNoDependencyCheck() throws Exception { + String path = "/BeanProperty.htm"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.setAutowireModeName("AUTOWIRE_BY_NAME"); + hm.setDependencyCheck(false); + hm.register(BeanPropertyController.class, new PathMap(path)); + hm.setApplicationContext(wac); + + BeanPropertyController bpc = (BeanPropertyController) wac.getBean(BeanPropertyController.class.getName()); + assertNull("Not autowired but no dependency check", bpc.testBean); + HandlerExecutionChain chain = hm.getHandler(new MockHttpServletRequest("GET", path)); + assertNotNull(chain); + assertEquals("Path is mapped correctly based on attribute", bpc, chain.getHandler()); + chain = hm.getHandler(new MockHttpServletRequest("GET", "completeRubbish.html")); + assertNull("Don't know anything about this path", chain); + } + + public void testMultiplePaths() throws Exception { + String path1 = "/Constructor.htm"; + String path2 = "path2.cgi"; + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + wac.registerSingleton("test", TestBean.class, new MutablePropertyValues()); + + HashUrlMapHandlerMapping hm = new HashUrlMapHandlerMapping(); + hm.register(ConstructorController.class, new PathMap[] { new PathMap(path1), new PathMap(path2) }); + hm.setApplicationContext(wac); + ConstructorController cc = (ConstructorController) wac.getBean(ConstructorController.class.getName()); + assertSame(wac.getBean("test"), cc.testBean); + HandlerExecutionChain chain = hm.getHandler(new MockHttpServletRequest("GET", path1)); + assertNotNull(chain); + assertEquals("Path is mapped correctly based on attribute 1", cc, chain.getHandler()); + chain = hm.getHandler(new MockHttpServletRequest(null, "GET", "/" + path2)); + assertEquals("Path is mapped correctly based on attribute 2", cc, chain.getHandler()); + chain = hm.getHandler(new MockHttpServletRequest(null, "GET", "completeRubbish.html")); + assertNull("Don't know anything about this path", chain); + } + + + private static class HashUrlMapHandlerMapping extends AbstractPathMapHandlerMapping { + + private HashMap classToPathMaps = new HashMap(); + + public void register(Class clazz, PathMap pm) { + classToPathMaps.put(clazz, new PathMap[] { pm }); + } + + public void register(Class clazz, PathMap[] pms) { + classToPathMaps.put(clazz, pms); + } + + protected Class[] getClassesWithPathMapAttributes() { + return (Class[]) classToPathMaps.keySet().toArray(new Class[classToPathMaps.size()]); + } + + protected PathMap[] getPathMapAttributes(Class handlerClass) { + return (PathMap[]) classToPathMaps.get(handlerClass); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java new file mode 100644 index 00000000000..b26d68c4942 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java @@ -0,0 +1,171 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.i18n; + +import java.util.Locale; + +import javax.servlet.http.Cookie; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +/** + * @author Alef Arendsen + * @author Juergen Hoeller + * @author Rick Evans + */ +public class CookieLocaleResolverTests extends TestCase { + + public void testResolveLocale() { + MockHttpServletRequest request = new MockHttpServletRequest(); + Cookie cookie = new Cookie("LanguageKoekje", "nl"); + request.setCookies(new Cookie[]{cookie}); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + // yup, koekje is the Dutch name for Cookie ;-) + resolver.setCookieName("LanguageKoekje"); + Locale loc = resolver.resolveLocale(request); + assertEquals(loc.getLanguage(), "nl"); + } + + public void testSetAndResolveLocale() { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + resolver.setLocale(request, response, new Locale("nl", "")); + + Cookie cookie = response.getCookie(CookieLocaleResolver.DEFAULT_COOKIE_NAME); + assertNotNull(cookie); + assertEquals(CookieLocaleResolver.DEFAULT_COOKIE_NAME, cookie.getName()); + assertEquals(null, cookie.getDomain()); + assertEquals(CookieLocaleResolver.DEFAULT_COOKIE_PATH, cookie.getPath()); + assertEquals(CookieLocaleResolver.DEFAULT_COOKIE_MAX_AGE, cookie.getMaxAge()); + assertFalse(cookie.getSecure()); + + request = new MockHttpServletRequest(); + request.setCookies(new Cookie[]{cookie}); + + resolver = new CookieLocaleResolver(); + Locale loc = resolver.resolveLocale(request); + assertEquals(loc.getLanguage(), "nl"); + } + + public void testCustomCookie() { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + resolver.setCookieName("LanguageKoek"); + resolver.setCookieDomain(".springframework.org"); + resolver.setCookiePath("/mypath"); + resolver.setCookieMaxAge(10000); + resolver.setCookieSecure(true); + resolver.setLocale(request, response, new Locale("nl", "")); + + Cookie cookie = response.getCookie("LanguageKoek"); + assertNotNull(cookie); + assertEquals("LanguageKoek", cookie.getName()); + assertEquals(".springframework.org", cookie.getDomain()); + assertEquals("/mypath", cookie.getPath()); + assertEquals(10000, cookie.getMaxAge()); + assertTrue(cookie.getSecure()); + + request = new MockHttpServletRequest(); + request.setCookies(new Cookie[]{cookie}); + + resolver = new CookieLocaleResolver(); + resolver.setCookieName("LanguageKoek"); + Locale loc = resolver.resolveLocale(request); + assertEquals(loc.getLanguage(), "nl"); + } + + public void testResolveLocaleWithoutCookie() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + + Locale locale = resolver.resolveLocale(request); + assertEquals(request.getLocale(), locale); + } + + public void testResolveLocaleWithoutCookieAndDefaultLocale() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + resolver.setDefaultLocale(Locale.GERMAN); + + Locale locale = resolver.resolveLocale(request); + assertEquals(Locale.GERMAN, locale); + } + + public void testResolveLocaleWithCookieWithoutLocale() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + Cookie cookie = new Cookie(CookieLocaleResolver.LOCALE_REQUEST_ATTRIBUTE_NAME, ""); + request.setCookies(new Cookie[]{cookie}); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + + Locale locale = resolver.resolveLocale(request); + assertEquals(request.getLocale(), locale); + } + + public void testSetLocaleToNullLocale() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + Cookie cookie = new Cookie(CookieLocaleResolver.LOCALE_REQUEST_ATTRIBUTE_NAME, Locale.UK.toString()); + request.setCookies(new Cookie[]{cookie}); + MockHttpServletResponse response = new MockHttpServletResponse(); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + resolver.setLocale(request, response, null); + Locale locale = (Locale) request.getAttribute(CookieLocaleResolver.LOCALE_REQUEST_ATTRIBUTE_NAME); + assertEquals(Locale.TAIWAN, locale); + + Cookie[] cookies = response.getCookies(); + assertEquals(1, cookies.length); + Cookie localeCookie = cookies[0]; + assertEquals(CookieLocaleResolver.LOCALE_REQUEST_ATTRIBUTE_NAME, localeCookie.getName()); + assertEquals("", localeCookie.getValue()); + } + + public void testSetLocaleToNullLocaleWithDefault() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + Cookie cookie = new Cookie(CookieLocaleResolver.LOCALE_REQUEST_ATTRIBUTE_NAME, Locale.UK.toString()); + request.setCookies(new Cookie[]{cookie}); + MockHttpServletResponse response = new MockHttpServletResponse(); + + CookieLocaleResolver resolver = new CookieLocaleResolver(); + resolver.setDefaultLocale(Locale.CANADA_FRENCH); + resolver.setLocale(request, response, null); + Locale locale = (Locale) request.getAttribute(CookieLocaleResolver.LOCALE_REQUEST_ATTRIBUTE_NAME); + assertEquals(Locale.CANADA_FRENCH, locale); + + Cookie[] cookies = response.getCookies(); + assertEquals(1, cookies.length); + Cookie localeCookie = cookies[0]; + assertEquals(CookieLocaleResolver.LOCALE_REQUEST_ATTRIBUTE_NAME, localeCookie.getName()); + assertEquals("", localeCookie.getValue()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/LocaleResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/LocaleResolverTests.java new file mode 100644 index 00000000000..86eb821f9d3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/LocaleResolverTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.i18n; + +import java.util.Locale; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.servlet.LocaleResolver; + +/** + * @author Juergen Hoeller + * @since 20.03.2003 + */ +public class LocaleResolverTests extends TestCase { + + private void internalTest(LocaleResolver localeResolver, boolean shouldSet) { + // create mocks + MockServletContext context = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(context); + request.addPreferredLocale(Locale.UK); + MockHttpServletResponse response = new MockHttpServletResponse(); + // check original locale + Locale locale = localeResolver.resolveLocale(request); + assertEquals(locale, Locale.UK); + // set new locale + try { + localeResolver.setLocale(request, response, Locale.GERMANY); + if (!shouldSet) + fail("should not be able to set Locale"); + // check new locale + locale = localeResolver.resolveLocale(request); + assertEquals(locale, Locale.GERMANY); + } + catch (UnsupportedOperationException ex) { + if (shouldSet) + fail("should be able to set Locale"); + } + } + + public void testAcceptHeaderLocaleResolver() { + internalTest(new AcceptHeaderLocaleResolver(), false); + } + + public void testCookieLocaleResolver() { + internalTest(new CookieLocaleResolver(), true); + } + + public void testSessionLocaleResolver() { + internalTest(new SessionLocaleResolver(), true); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java new file mode 100644 index 00000000000..84f9caa98df --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.i18n; + +import java.util.Locale; + +import javax.servlet.http.HttpSession; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +/** + * @author Juergen Hoeller + */ +public class SessionLocaleResolverTests extends TestCase { + + public void testResolveLocale() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, Locale.GERMAN); + + SessionLocaleResolver resolver = new SessionLocaleResolver(); + assertEquals(Locale.GERMAN, resolver.resolveLocale(request)); + } + + public void testSetAndResolveLocale() { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + SessionLocaleResolver resolver = new SessionLocaleResolver(); + resolver.setLocale(request, response, Locale.GERMAN); + assertEquals(Locale.GERMAN, resolver.resolveLocale(request)); + + HttpSession session = request.getSession(); + request = new MockHttpServletRequest(); + request.setSession(session); + resolver = new SessionLocaleResolver(); + + assertEquals(Locale.GERMAN, resolver.resolveLocale(request)); + } + + public void testResolveLocaleWithoutSession() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + + SessionLocaleResolver resolver = new SessionLocaleResolver(); + + assertEquals(request.getLocale(), resolver.resolveLocale(request)); + } + + public void testResolveLocaleWithoutSessionAndDefaultLocale() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + + SessionLocaleResolver resolver = new SessionLocaleResolver(); + resolver.setDefaultLocale(Locale.GERMAN); + + assertEquals(Locale.GERMAN, resolver.resolveLocale(request)); + } + + public void testSetLocaleToNullLocale() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, Locale.GERMAN); + MockHttpServletResponse response = new MockHttpServletResponse(); + + SessionLocaleResolver resolver = new SessionLocaleResolver(); + resolver.setLocale(request, response, null); + Locale locale = (Locale) request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME); + assertNull(locale); + + HttpSession session = request.getSession(); + request = new MockHttpServletRequest(); + request.addPreferredLocale(Locale.TAIWAN); + request.setSession(session); + resolver = new SessionLocaleResolver(); + assertEquals(Locale.TAIWAN, resolver.resolveLocale(request)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java new file mode 100644 index 00000000000..804d13489e5 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java @@ -0,0 +1,236 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class CancellableFormControllerTests extends TestCase { + + public void testFormViewRequest() throws Exception { + String formView = "theFormView"; + + TestController ctl = new TestController(); + ctl.setFormView(formView); + ctl.setBindOnNewForm(true); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + String name = "Rob Harrop"; + int age = 23; + + request.setMethod("GET"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + + ModelAndView mv = ctl.handleRequest(request, response); + + assertEquals("Incorrect view name", formView, mv.getViewName()); + + TestBean command = (TestBean) mv.getModel().get(ctl.getCommandName()); + + testCommandIsBound(command, name, age); + } + + public void testFormSubmissionRequestWithoutCancel() throws Exception { + String successView = "successView"; + + TestController ctl = new TestController(); + ctl.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + String name = "Rob Harrop"; + int age = 23; + + request.setMethod("POST"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + + ModelAndView mv = ctl.handleRequest(request, response); + + assertEquals("Incorrect view name", successView, mv.getViewName()); + + TestBean command = (TestBean) mv.getModel().get(ctl.getCommandName()); + + testCommandIsBound(command, name, age); + } + + public void testFormSubmissionWithErrors() throws Exception { + String successView = "successView"; + String formView = "formView"; + + TestController ctl = new TestController(); + ctl.setSuccessView(successView); + ctl.setFormView(formView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("name", "Rob Harrop"); + request.addParameter("age", "xxx23"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", formView, mv.getViewName()); + + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + ctl.getCommandName()); + assertNotNull("No errors", errors); + assertEquals(1, errors.getErrorCount()); + } + + public void testFormSubmissionWithValidationError() throws Exception { + String successView = "successView"; + String formView = "formView"; + + TestController ctl = new TestController(); + ctl.setSuccessView(successView); + ctl.setFormView(formView); + TestValidator val = new TestValidator(); + ctl.setValidator(val); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("name", "Rob Harrop"); + request.addParameter("age", "23"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", formView, mv.getViewName()); + + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + ctl.getCommandName()); + assertNotNull("No errors", errors); + assertEquals(1, errors.getErrorCount()); + assertTrue(val.invoked); + } + + public void testCancelSubmission() throws Exception { + String cancelView = "cancelView"; + String cancelParameterKey = "cancelRequest"; + + TestController ctl = new TestController(); + ctl.setCancelParamKey(cancelParameterKey); + ctl.setCancelView(cancelView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("cancelRequest", "true"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", cancelView, mv.getViewName()); + } + + public void testCancelSubmissionWithValidationError() throws Exception { + String cancelView = "cancelView"; + String cancelParameterKey = "cancelRequest"; + + TestController ctl = new TestController(); + ctl.setCancelParamKey(cancelParameterKey); + ctl.setCancelView(cancelView); + TestValidator val = new TestValidator(); + ctl.setValidator(val); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("name", "Rob Harrop"); + request.addParameter("age", "23"); + request.addParameter("cancelRequest", "true"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", cancelView, mv.getViewName()); + + assertFalse(val.invoked); + } + + public void testCancelSubmissionWithCustomModelParams() throws Exception { + String cancelView = "cancelView"; + String cancelParameterKey = "cancelRequest"; + final String reason = "Because I wanted to"; + + TestController ctl = new TestController() { + protected ModelAndView onCancel(HttpServletRequest request, HttpServletResponse response, Object command) { + return new ModelAndView(getCancelView(), "reason", reason); + } + }; + + ctl.setCancelParamKey(cancelParameterKey); + ctl.setCancelView(cancelView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("cancelRequest", "true"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", cancelView, mv.getViewName()); + assertEquals("Model parameter reason not correct", reason, mv.getModel().get("reason")); + } + + private void testCommandIsBound(TestBean command, String name, int age) { + assertNotNull("Command bean should not be null", command); + assertEquals("Name not bound", name, command.getName()); + assertEquals("Age not bound", age, command.getAge()); + } + + + private static class TestController extends CancellableFormController { + + public TestController() { + setCommandClass(TestBean.class); + } + } + + + private static class TestValidator implements Validator { + + private boolean invoked = false; + + public boolean supports(Class clazz) { + return TestBean.class.isAssignableFrom(clazz); + } + public void validate(Object target, Errors errors) { + this.invoked = true; + TestBean tb = (TestBean) target; + if (tb.getAge() < 25) { + errors.rejectValue("age", "TOO_YOUNG"); + } + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java new file mode 100644 index 00000000000..1b757c9314d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java @@ -0,0 +1,510 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.ServletRequestDataBinder; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rod Johnson + */ +public class CommandControllerTests extends TestCase { + + public void testNoArgsNoErrors() throws Exception { + TestController mc = new TestController(); + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(request.getServletPath())); + TestBean person = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("command and errors non null", person != null && errors != null); + assertTrue("no errors", !errors.hasErrors()); + assertTrue("Correct caching", response.getHeader("Cache-Control") == null); + assertTrue("Correct expires header", response.getHeader("Expires") == null); + } + + public void test2ArgsNoErrors() throws Exception { + TestController mc = new TestController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + String name = "Rod"; + int age = 32; + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(request.getServletPath())); + TestBean person = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("command and errors non null", person != null && errors != null); + assertTrue("no errors", !errors.hasErrors()); + assertTrue("command name bound ok", person.getName().equals(name)); + assertTrue("command age bound ok", person.getAge() == age); + } + + public void test2Args1Mismatch() throws Exception { + TestController mc = new TestController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + String name = "Rod"; + String age = "32x"; + request.addParameter("name", name); + request.addParameter("age", age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(request.getServletPath())); + TestBean person = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("command and errors non null", person != null && errors != null); + assertTrue("has 1 errors", errors.getErrorCount() == 1); + assertTrue("command name bound ok", person.getName().equals(name)); + assertTrue("command age default", person.getAge() == new TestBean().getAge()); + assertTrue("has error on field age", errors.hasFieldErrors("age")); + FieldError fe = errors.getFieldError("age"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(age)); + assertTrue("Correct field", fe.getField().equals("age")); + } + + public void testSupportedMethods() throws Exception { + TestController mc = new TestController(); + mc.setSupportedMethods(new String[] {"POST"}); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + } + } + + public void testRequireSessionWithoutSession() throws Exception { + TestController mc = new TestController(); + mc.setRequireSession(true); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + } + } + + public void testRequireSessionWithSession() throws Exception { + TestController mc = new TestController(); + mc.setRequireSession(true); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + request.setSession(new MockHttpSession(null)); + HttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + } + + public void testNoCaching() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(0); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires").equals(new Long(1))); + List cacheControl = response.getHeaders("Cache-Control"); + assertTrue("Correct cache control", cacheControl.contains("no-cache")); + assertTrue("Correct cache control", cacheControl.contains("no-store")); + } + + public void testNoCachingWithoutExpires() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(0); + mc.setUseExpiresHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("No expires header", response.getHeader("Expires") == null); + List cacheControl = response.getHeaders("Cache-Control"); + assertTrue("Correct cache control", cacheControl.contains("no-cache")); + assertTrue("Correct cache control", cacheControl.contains("no-store")); + } + + public void testNoCachingWithoutCacheControl() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(0); + mc.setUseCacheControlHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires").equals(new Long(1))); + assertTrue("No cache control", response.getHeader("Cache-Control") == null); + } + + public void testCaching() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(10); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=10")); + } + + public void testCachingWithoutExpires() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(10); + mc.setUseExpiresHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("No expires header", response.getHeader("Expires") == null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=10")); + } + + public void testCachingWithoutCacheControl() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(10); + mc.setUseCacheControlHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("No cache control", response.getHeader("Cache-Control") == null); + } + + public void testCachingWithLastModified() throws Exception { + class LastModifiedTestController extends TestController implements LastModified { + public long getLastModified(HttpServletRequest request) { + return 0; + } + } + LastModifiedTestController mc = new LastModifiedTestController(); + mc.setCacheSeconds(10); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=10, must-revalidate")); + } + + public void testCachingWithCustomCacheForSecondsCall() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + cacheForSeconds(response, 5); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=5")); + } + + public void testCachingWithCustomApplyCacheSecondsCall1() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + applyCacheSeconds(response, 5); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=5")); + } + + public void testCachingWithCustomApplyCacheSecondsCall2() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + applyCacheSeconds(response, 0); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires").equals(new Long(1))); + List cacheControl = response.getHeaders("Cache-Control"); + assertTrue("Correct cache control", cacheControl.contains("no-cache")); + assertTrue("Correct cache control", cacheControl.contains("no-store")); + } + + public void testCachingWithCustomApplyCacheSecondsCall3() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + applyCacheSeconds(response, -1); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("No expires header", response.getHeader("Expires") == null); + assertTrue("No cache control", response.getHeader("Cache-Control") == null); + } + + public void testCustomDateEditorWithAllowEmpty() throws Exception { + final DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN); + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", "1.5.2003"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("date")); + assertTrue("Correct date property", df.parse("1.5.2003").equals(tb.getDate())); + assertTrue("Correct date value", "01.05.2003".equals(errors.getFieldValue("date"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("date")); + assertTrue("Correct date property", tb.getDate() == null); + assertTrue("Correct date value", "".equals(errors.getFieldValue("date"))); + } + + public void testCustomDateEditorWithoutAllowEmpty() throws Exception { + final DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN); + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", "1.5.2003"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("date")); + assertTrue("Correct date property", df.parse("1.5.2003").equals(tb.getDate())); + assertTrue("Correct date value", "01.05.2003".equals(errors.getFieldValue("date"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Has field error", errors.hasFieldErrors("date")); + assertTrue("Correct date property", tb.getDate() != null); + assertTrue("Correct date value", errors.getFieldValue("date") != null); + } + + public void testCustomNumberEditorWithAllowEmpty() throws Exception { + final NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN); + + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, nf, true)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", "5,1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", (new Float(5.1)).equals(tb.getMyFloat())); + assertTrue("Correct float value", "5,1".equals(errors.getFieldValue("myFloat"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", tb.getMyFloat() == null); + assertTrue("Correct float value", "".equals(errors.getFieldValue("myFloat"))); + } + + public void testCustomNumberEditorWithoutAllowEmpty() throws Exception { + final NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN); + + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, nf, false)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", "5,1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", (new Float(5.1)).equals(tb.getMyFloat())); + assertTrue("Correct float value", "5,1".equals(errors.getFieldValue("myFloat"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Has field error", errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", tb.getMyFloat() != null); + assertTrue("Correct float value", errors.getFieldValue("myFloat") != null); + } + + public void testResetEmptyStringField() throws Exception { + TestController mc = new TestController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "visible"); + request.addParameter("name", "test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", "test".equals(tb.getName())); + assertTrue("Correct name value", "test".equals(errors.getFieldValue("name"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "visible"); + request.addParameter("_someNonExistingField", "visible"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", tb.getName() == null); + assertTrue("Correct name value", errors.getFieldValue("name") == null); + } + + public void testResetEmptyBooleanField() throws Exception { + TestController mc = new TestController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_postProcessed", "visible"); + request.addParameter("postProcessed", "true"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct postProcessed property", tb.isPostProcessed()); + assertTrue("Correct postProcessed value", Boolean.TRUE.equals(errors.getFieldValue("postProcessed"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_postProcessed", "visible"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct postProcessed property", !tb.isPostProcessed()); + assertTrue("Correct postProcessed value", Boolean.FALSE.equals(errors.getFieldValue("postProcessed"))); + } + + public void testResetEmptyStringArrayField() throws Exception { + TestController mc = new TestController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_stringArray", "visible"); + request.addParameter("stringArray", "value1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + assertTrue("Correct stringArray property", + tb.getStringArray() != null && "value1".equals(tb.getStringArray()[0])); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_stringArray", "visible"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + assertTrue("Correct stringArray property", tb.getStringArray() != null && tb.getStringArray().length == 0); + } + + public void testResetEmptyFieldsTurnedOff() throws Exception { + TestController mc = new TestController() { + protected Object getCommand(HttpServletRequest request) throws Exception { + return new TestBean("original", 99); + } + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.setFieldMarkerPrefix(null); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "visible"); + request.addParameter("name", "test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", "test".equals(tb.getName())); + assertTrue("Correct name value", "test".equals(errors.getFieldValue("name"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "true"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", "original".equals(tb.getName())); + assertTrue("Correct name value", "original".equals(errors.getFieldValue("name"))); + } + + + private static class TestController extends AbstractCommandController { + + private TestController() { + super(TestBean.class, "person"); + } + + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + Map m = new HashMap(); + assertTrue("Command not null", command != null); + assertTrue("errors not null", errors != null); + m.put("errors", errors); + m.put("command", command); + return new ModelAndView(request.getServletPath(), m); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/ControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/ControllerTests.java new file mode 100644 index 00000000000..d54fc6ab3e1 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/ControllerTests.java @@ -0,0 +1,216 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.util.Properties; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.util.WebUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class ControllerTests extends TestCase { + + public void testParameterizableViewController() throws Exception { + String viewName = "viewName"; + ParameterizableViewController pvc = new ParameterizableViewController(); + pvc.setViewName(viewName); + pvc.initApplicationContext(); + // We don't care about the params. + ModelAndView mv = pvc.handleRequest(new MockHttpServletRequest("GET", "foo.html"), null); + assertTrue("model has no data", mv.getModel().size() == 0); + assertTrue("model has correct viewname", mv.getViewName().equals(viewName)); + assertTrue("getViewName matches", pvc.getViewName().equals(viewName)); + } + + public void testParameterizableViewControllerWithPropertyNotSet() { + ParameterizableViewController pvc = new ParameterizableViewController(); + try { + pvc.initApplicationContext(); + fail("should require viewName property to be set"); + } + catch (IllegalArgumentException ex){ + // expected + assertTrue("meaningful exception message", ex.getMessage().indexOf("viewName") != -1); + } + } + + public void testServletForwardingController() throws Exception { + ServletForwardingController sfc = new ServletForwardingController(); + sfc.setServletName("action"); + doTestServletForwardingController(sfc, false); + } + + public void testServletForwardingControllerWithInclude() throws Exception { + ServletForwardingController sfc = new ServletForwardingController(); + sfc.setServletName("action"); + doTestServletForwardingController(sfc, true); + } + + public void testServletForwardingControllerWithBeanName() throws Exception { + ServletForwardingController sfc = new ServletForwardingController(); + sfc.setBeanName("action"); + doTestServletForwardingController(sfc, false); + } + + private void doTestServletForwardingController(ServletForwardingController sfc, boolean include) + throws Exception { + + MockControl requestControl = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) requestControl.getMock(); + MockControl responseControl = MockControl.createControl(HttpServletResponse.class); + HttpServletResponse response = (HttpServletResponse) responseControl.getMock(); + MockControl contextControl = MockControl.createControl(ServletContext.class); + ServletContext context = (ServletContext) contextControl.getMock(); + MockControl dispatcherControl = MockControl.createControl(RequestDispatcher.class); + RequestDispatcher dispatcher = (RequestDispatcher) dispatcherControl.getMock(); + + request.getMethod(); + requestControl.setReturnValue("GET", 1); + context.getNamedDispatcher("action"); + contextControl.setReturnValue(dispatcher, 1); + if (include) { + request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); + requestControl.setReturnValue("somePath", 1); + dispatcher.include(request, response); + dispatcherControl.setVoidCallable(1); + } + else { + request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); + requestControl.setReturnValue(null, 1); + dispatcher.forward(request, response); + dispatcherControl.setVoidCallable(1); + } + requestControl.replay(); + contextControl.replay(); + dispatcherControl.replay(); + + StaticWebApplicationContext sac = new StaticWebApplicationContext(); + sac.setServletContext(context); + sfc.setApplicationContext(sac); + assertNull(sfc.handleRequest(request, response)); + + requestControl.verify(); + contextControl.verify(); + dispatcherControl.verify(); + } + + public void testServletWrappingController() throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/somePath"); + HttpServletResponse response = new MockHttpServletResponse(); + + ServletWrappingController swc = new ServletWrappingController(); + swc.setServletClass(TestServlet.class); + swc.setServletName("action"); + Properties props = new Properties(); + props.setProperty("config", "myValue"); + swc.setInitParameters(props); + + swc.afterPropertiesSet(); + assertNotNull(TestServlet.config); + assertEquals("action", TestServlet.config.getServletName()); + assertEquals("myValue", TestServlet.config.getInitParameter("config")); + assertNull(TestServlet.request); + assertFalse(TestServlet.destroyed); + + assertNull(swc.handleRequest(request, response)); + assertEquals(request, TestServlet.request); + assertEquals(response, TestServlet.response); + assertFalse(TestServlet.destroyed); + + swc.destroy(); + assertTrue(TestServlet.destroyed); + } + + public void testServletWrappingControllerWithBeanName() throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/somePath"); + HttpServletResponse response = new MockHttpServletResponse(); + + ServletWrappingController swc = new ServletWrappingController(); + swc.setServletClass(TestServlet.class); + swc.setBeanName("action"); + + swc.afterPropertiesSet(); + assertNotNull(TestServlet.config); + assertEquals("action", TestServlet.config.getServletName()); + assertNull(TestServlet.request); + assertFalse(TestServlet.destroyed); + + assertNull(swc.handleRequest(request, response)); + assertEquals(request, TestServlet.request); + assertEquals(response, TestServlet.response); + assertFalse(TestServlet.destroyed); + + swc.destroy(); + assertTrue(TestServlet.destroyed); + } + + + public static class TestServlet implements Servlet { + + private static ServletConfig config; + private static ServletRequest request; + private static ServletResponse response; + private static boolean destroyed; + + public TestServlet() { + config = null; + request = null; + response = null; + destroyed = false; + } + + public void init(ServletConfig servletConfig) { + config = servletConfig; + } + + public ServletConfig getServletConfig() { + return config; + } + + public void service(ServletRequest servletRequest, ServletResponse servletResponse) { + request = servletRequest; + response = servletResponse; + } + + public String getServletInfo() { + return "TestServlet"; + } + + public void destroy() { + destroyed = true; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java new file mode 100644 index 00000000000..dd735910802 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java @@ -0,0 +1,646 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.Validator; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class FormControllerTests extends TestCase { + + public void testReferenceDataOnForm() throws Exception { + String formView = "f"; + String successView = "s"; + + RefController mc = new RefController(); + mc.setFormView(formView); + mc.setCommandName("tb"); + mc.setSuccessView(successView); + mc.refDataCount = 0; + + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(formView)); + + assertTrue("refDataCount == 1", mc.refDataCount == 1); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + int[] numbers = (int[]) mv.getModel().get(mc.NUMBERS_ATT); + assertTrue("model is non null", person != null); + assertTrue("numbers is non null", numbers != null); + } + + public void testReferenceDataOnResubmit() throws Exception { + String formView = "f"; + String successView = "s"; + + RefController mc = new RefController(); + mc.setFormView(formView); + mc.setCommandName("tb"); + mc.setSuccessView(successView); + mc.refDataCount = 0; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("age", "23x"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(formView)); + assertTrue("has errors", mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()) != null); + + assertTrue("refDataCount == 1", mc.refDataCount == 1); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + int[] numbers = (int[]) mv.getModel().get(mc.NUMBERS_ATT); + assertTrue("model is non null", person != null); + assertTrue("numbers is non null", numbers != null); + } + + public void testForm() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("name", "rod"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("bean age default ok", person.getAge() == TestController.DEFAULT_AGE); + assertTrue("name not set", person.getName() == null); + } + + public void testBindOnNewForm() throws Exception { + String formView = "f"; + String successView = "s"; + final Integer someNumber = new Integer(12); + + TestController mc = new TestController() { + protected void onBindOnNewForm(HttpServletRequest request, Object command) throws Exception { + TestBean testBean = (TestBean)command; + testBean.setSomeNumber(new Integer(12)); + } + }; + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setBindOnNewForm(true); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("name", "rod"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertEquals("returned correct view name", formView, mv.getViewName()); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertNotNull("model is non null", person); + assertEquals("bean age default ok", person.getAge(), TestController.DEFAULT_AGE); + assertEquals("name set", "rod", person.getName()); + assertEquals("Property [someNumber] not set in onBindOnNewForm callback", someNumber, person.getSomeNumber()); + } + + public void testSubmitWithoutErrors() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + String name = "Rod"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + + assertEquals("returned correct view name", successView, mv.getViewName()); + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("errors is non null", errors != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age bound ok", person.getAge() == age); + } + + public void testSubmitWithoutValidation() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + String name = "Rod"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + request.addParameter("formChange", "true"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + + assertEquals("returned correct view name", formView, mv.getViewName()); + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("errors is non null", errors != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age bound ok", person.getAge() == age); + } + + public void testSubmitWithCustomOnSubmit() throws Exception { + String formView = "f"; + + TestControllerWithCustomOnSubmit mc = new TestControllerWithCustomOnSubmit(); + mc.setFormView(formView); + + String name = "Rod"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertEquals("returned correct view name", "mySuccess", mv.getViewName()); + assertTrue("no model", mv.getModel().isEmpty()); + } + + public void testSubmitPassedByValidator() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setValidator(new TestValidator()); + + String name = "Roderick Johnson"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + successView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(successView)); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age bound ok", person.getAge() == age); + } + + public void testSubmit1Mismatch() throws Exception { + String formView = "fred"; + String successView = "tony"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + String name = "Rod"; + String age = "xxx"; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + assertTrue("model is non null", person != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age is default", person.getAge() == TestController.DEFAULT_AGE); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("One error", errors.getErrorCount() == 1); + FieldError fe = errors.getFieldError("age"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(age)); + assertTrue("Correct field", fe.getField().equals("age")); + } + + public void testSubmit1Mismatch1Invalidated() throws Exception { + String formView = "fred"; + String successView = "tony"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setValidators(new Validator[] {new TestValidator(), new TestValidator2()}); + + String name = "Rod"; + // will be rejected + String age = "xxx"; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + + // yes, but it was rejected after binding by the validator + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age is default", person.getAge() == TestController.DEFAULT_AGE); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("3 errors", errors.getErrorCount() == 3); + FieldError fe = errors.getFieldError("age"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(age)); + assertTrue("Correct field", fe.getField().equals("age")); + + // raised by first validator + fe = errors.getFieldError("name"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(name)); + assertTrue("Correct field", fe.getField().equals("name")); + assertTrue("Correct validation code: expected '" +TestValidator.TOOSHORT + "', not '" + + fe.getCode() + "'", fe.getCode().equals(TestValidator.TOOSHORT)); + + // raised by second validator + ObjectError oe = errors.getGlobalError(); + assertEquals("test", oe.getCode()); + assertEquals("testmessage", oe.getDefaultMessage()); + } + + public void testSessionController() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setSessionForm(true); + + // first request: GET form + HttpServletRequest request1 = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response1 = new MockHttpServletResponse(); + ModelAndView mv1 = mc.handleRequest(request1, response1); + assertTrue("returned correct view name", mv1.getViewName().equals(formView)); + TestBean person = (TestBean) mv1.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("Bean age default ok", person.getAge() == TestController.DEFAULT_AGE); + + // second request, using same session: POST submit + MockHttpServletRequest request2 = new MockHttpServletRequest("POST", "/welcome.html"); + request2.setSession(request1.getSession(false)); + HttpServletResponse response2 = new MockHttpServletResponse(); + ModelAndView mv2 = mc.handleRequest(request2, response2); + assertTrue("returned correct view name", mv2.getViewName().equals(successView)); + TestBean person2 = (TestBean) mv2.getModel().get(TestController.BEAN_NAME); + assertTrue("model is same object", person == person2); + } + + public void testDefaultInvalidSubmit() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setSessionForm(true); + + // invalid request: POST submit + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(successView)); + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + } + + public void testSpecialInvalidSubmit() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController() { + protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + throw new ServletException("invalid submit"); + } + }; + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setSessionForm(true); + + // invalid request: POST submit + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + } + } + + public void testSubmitWithIndexedProperties() throws Exception { + String formView = "fred"; + String successView = "tony"; + + SimpleFormController mc = new SimpleFormController(); + mc.setCommandClass(IndexedTestBean.class); + mc.setFormView(formView); + mc.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("array[0].name", "name3"); + request.addParameter("array[1].age", "name2"); + request.addParameter("list[0].name", "name1"); + request.addParameter("list[1].age", "name0"); + request.addParameter("list[2]", "listobj"); + request.addParameter("map[key1]", "mapobj1"); + request.addParameter("map[key3]", "mapobj2"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + IndexedTestBean bean = (IndexedTestBean) mv.getModel().get(mc.getCommandName()); + assertTrue("model is non null", bean != null); + assertEquals("name3", bean.getArray()[0].getName()); + assertEquals("name1", ((TestBean) bean.getList().get(0)).getName()); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("2 errors", errors.getErrorCount() == 2); + FieldError fe1 = errors.getFieldError("array[1].age"); + assertTrue("Saved invalid value", fe1.getRejectedValue().equals("name2")); + assertTrue("Correct field", fe1.getField().equals("array[1].age")); + FieldError fe2 = errors.getFieldError("list[1].age"); + assertTrue("Saved invalid value", fe2.getRejectedValue().equals("name0")); + assertTrue("Correct field", fe2.getField().equals("list[1].age")); + + assertEquals("listobj", bean.getList().get(2)); + assertEquals("mapobj1", bean.getMap().get("key1")); + assertEquals("mapobj2", bean.getMap().get("key3")); + } + + public void testFormChangeRequest() throws Exception { + String formView = "fred"; + String successView = "tony"; + final Float myFloat = new Float("123.45"); + + TestController mc = new TestController() { + protected boolean isFormChangeRequest(HttpServletRequest request) { + return (request.getParameter("formChange") != null); + } + + protected void onFormChange(HttpServletRequest request, HttpServletResponse response, Object command) { + assertNotNull("Command should not be null", command); + assertEquals("Incorrect command class", TestBean.class, command.getClass()); + ((TestBean)command).setMyFloat(myFloat); + } + }; + mc.setFormView(formView); + mc.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("name", "Rod"); + request.addParameter("age", "99"); + request.addParameter("formChange", "true"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + assertTrue("model is non null", person != null); + assertTrue("bean name bound ok", person.getName().equals("Rod")); + assertTrue("bean age is 99", person.getAge() == 99); + assertEquals("Command property myFloat not updated in onFormChange", myFloat, person.getMyFloat()); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("No errors", errors.getErrorCount() == 0); + } + + public void testFormBindingOfNestedBooleans() throws Exception { + BooleanBindingFormController controller = new BooleanBindingFormController(); + controller.setCommandClass(ListForm.class); + MockHttpServletRequest req = new MockHttpServletRequest("POST", "/myurl"); + MockHttpServletResponse res = new MockHttpServletResponse(); + req.addParameter("oks[0].ok", "true"); + ModelAndView mav = controller.handleRequest(req, res); + ListForm form = (ListForm) mav.getModelMap().get("command"); + Boolean ok = ((Ok) form.getOks().get(0)).getOk(); + assertNotNull(ok); + } + + public void testFormControllerInWebApplicationContext() { + StaticWebApplicationContext ctx = new StaticWebApplicationContext(); + ctx.setServletContext(new MockServletContext()); + RefController mc = new RefController(); + mc.setApplicationContext(ctx); + try { + mc.invokeWebSpecificStuff(); + } + catch (IllegalStateException ex) { + fail("Shouldn't have thrown exception: " + ex.getMessage()); + } + } + + public void testFormControllerInNonWebApplicationContext() { + StaticApplicationContext ctx = new StaticApplicationContext(); + RefController mc = new RefController(); + mc.setApplicationContext(ctx); + try { + mc.invokeWebSpecificStuff(); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + + private static class TestValidator implements Validator { + + public static String TOOSHORT = "tooshort"; + + public boolean supports(Class clazz) { return true; } + + public void validate(Object obj, Errors errors) { + TestBean tb = (TestBean) obj; + if (tb.getName() == null || "".equals(tb.getName())) + errors.rejectValue("name", "needname", null, "need name"); + else if (tb.getName().length() < 5) + errors.rejectValue("name", TOOSHORT, null, "need full name"); + } + } + + + private static class TestValidator2 implements Validator { + + public static String TOOSHORT = "tooshort"; + + public boolean supports(Class clazz) { return true; } + + public void validate(Object obj, Errors errors) { + errors.reject("test", "testmessage"); + } + } + + + private static class TestController extends SimpleFormController { + + public static String BEAN_NAME = "person"; + + public static int DEFAULT_AGE = 52; + + public TestController() { + setCommandClass(TestBean.class); + setCommandName(BEAN_NAME); + } + + protected Object formBackingObject(HttpServletRequest request) throws ServletException { + TestBean person = new TestBean(); + person.setAge(DEFAULT_AGE); + return person; + } + + protected boolean isFormChangeRequest(HttpServletRequest request) { + return (request.getParameter("formChange") != null); + } + } + + + private static class TestControllerWithCustomOnSubmit extends TestController { + + protected ModelAndView onSubmit(Object command) throws Exception { + return new ModelAndView("mySuccess"); + } + } + + + private static class RefController extends SimpleFormController { + + final String NUMBERS_ATT = "NUMBERS"; + + static final int[] NUMBERS = { 1, 2, 3, 4 }; + + int refDataCount; + + public RefController() { + setCommandClass(TestBean.class); + } + + protected Map referenceData(HttpServletRequest request) { + ++refDataCount; + Map m = new HashMap(); + m.put(NUMBERS_ATT, NUMBERS); + return m; + } + + public void invokeWebSpecificStuff() { + getTempDir(); + } + } + + + public static class BooleanBindingFormController extends AbstractFormController { + + protected ModelAndView processFormSubmission + (HttpServletRequest req, HttpServletResponse resp, Object command, BindException errors) throws Exception { + ModelAndView mav = new ModelAndView(); + mav.addObject("command", command); + return mav; + } + + protected ModelAndView showForm( + HttpServletRequest req, HttpServletResponse resp, BindException err) throws Exception { + return null; + } + } + + + public static class Ok { + + private Boolean ok; + + public Boolean getOk () { + return ok; + } + + public void setOk(Boolean ok) { + this.ok = ok; + } + } + + + public static class ListForm { + + private List oks = new ArrayList(); + + public ListForm () { + for (int index = 0; index < 5; index++) { + Ok ok = new Ok(); + oks.add(ok); + } + } + + public List getOks() { + return oks; + } + + public void setOks(List oks) { + this.oks = oks; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/UrlFilenameViewControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/UrlFilenameViewControllerTests.java new file mode 100644 index 00000000000..ed45d97f820 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/UrlFilenameViewControllerTests.java @@ -0,0 +1,158 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + * @author Rick Evans + * @since 14.09.2005 + */ +public class UrlFilenameViewControllerTests extends TestCase { + + private PathMatcher pathMatcher = new AntPathMatcher(); + + + public void testWithPlainFilename() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("index", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithFilenamePlusExtension() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("index", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithPrefixAndSuffix() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setPrefix("mypre_"); + ctrl.setSuffix("_mysuf"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("mypre_index_mysuf", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithPrefix() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setPrefix("mypre_"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("mypre_index", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithSuffix() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setSuffix("_mysuf"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("index_mysuf", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testMultiLevel() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/docs/cvs/commit.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("docs/cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testMultiLevelWithMapping() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/docs/cvs/commit.html"); + exposePathInMapping(request, "/docs/**"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testMultiLevelMappingWithFallback() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/docs/cvs/commit.html"); + exposePathInMapping(request, "/docs/cvs/commit.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("docs/cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithContextMapping() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/docs/cvs/commit.html"); + request.setContextPath("/myapp"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("docs/cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testSettingPrefixToNullCausesEmptyStringToBeUsed() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setPrefix(null); + assertNotNull("When setPrefix(..) is called with a null argument, the empty string value must be used instead.", ctrl.getPrefix()); + assertEquals("When setPrefix(..) is called with a null argument, the empty string value must be used instead.", "", ctrl.getPrefix()); + } + + public void testSettingSuffixToNullCausesEmptyStringToBeUsed() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setSuffix(null); + assertNotNull("When setSuffix(..) is called with a null argument, the empty string value must be used instead.", ctrl.getSuffix()); + assertEquals("When setSuffix(..) is called with a null argument, the empty string value must be used instead.", "", ctrl.getSuffix()); + } + + /** + * This is the expected behavior, and it now has a test to prove it. + * http://opensource.atlassian.com/projects/spring/browse/SPR-2789 + */ + public void testNestedPathisUsedAsViewName_InBreakingChangeFromSpring12Line() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/products/view.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("products/view", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + private void exposePathInMapping(MockHttpServletRequest request, String mapping) { + String pathInMapping = this.pathMatcher.extractPathWithinPattern(mapping, request.getRequestURI()); + request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathInMapping); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java new file mode 100644 index 00000000000..e23a379f2be --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java @@ -0,0 +1,122 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.util.List; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.AssertThrows; +import org.springframework.web.servlet.support.WebContentGenerator; + +/** + * @author Rick Evans + */ +public class WebContentInterceptorTests extends TestCase { + + private MockHttpServletRequest request; + + private MockHttpServletResponse response; + + + protected void setUp() throws Exception { + request = new MockHttpServletRequest(); + request.setMethod(WebContentGenerator.METHOD_GET); + response = new MockHttpServletResponse(); + } + + + public void testPreHandleSetsCacheSecondsOnMatchingRequest() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(10); + + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertNotNull("'Expires' header not set (must be) : null", expiresHeaders); + assertTrue("'Expires' header not set (must be) : empty", expiresHeaders.size() > 0); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertNotNull("'Cache-Control' header not set (must be) : null", cacheControlHeaders); + assertTrue("'Cache-Control' header not set (must be) : empty", cacheControlHeaders.size() > 0); + } + + public void testPreHandleSetsCacheSecondsOnMatchingRequestWithCustomCacheMapping() throws Exception { + Properties mappings = new Properties(); + mappings.setProperty("**/*handle.vm", "-1"); + + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(10); + interceptor.setCacheMappings(mappings); + + request.setRequestURI("http://localhost:7070/example/adminhandle.vm"); + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertTrue("'Expires' header set (must not be) : empty", expiresHeaders.size() == 0); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertTrue("'Cache-Control' header set (must not be) : empty", cacheControlHeaders.size() == 0); + + request.setRequestURI("http://localhost:7070/example/bingo.html"); + interceptor.preHandle(request, response, null); + + expiresHeaders = response.getHeaders("Expires"); + assertNotNull("'Expires' header not set (must be) : null", expiresHeaders); + assertTrue("'Expires' header not set (must be) : empty", expiresHeaders.size() > 0); + cacheControlHeaders = response.getHeaders("Cache-Control"); + assertNotNull("'Cache-Control' header not set (must be) : null", cacheControlHeaders); + assertTrue("'Cache-Control' header not set (must be) : empty", cacheControlHeaders.size() > 0); + } + + public void testPreHandleSetsCacheSecondsOnMatchingRequestWithNoCaching() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(0); + + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertNotNull("'Expires' header not set (must be) : null", expiresHeaders); + assertTrue("'Expires' header not set (must be) : empty", expiresHeaders.size() > 0); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertNotNull("'Cache-Control' header not set (must be) : null", cacheControlHeaders); + assertTrue("'Cache-Control' header not set (must be) : empty", cacheControlHeaders.size() > 0); + } + + public void testPreHandleSetsCacheSecondsOnMatchingRequestWithCachingDisabled() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(-1); + + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertTrue("'Expires' header set (must not be) : empty", expiresHeaders.size() == 0); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertTrue("'Cache-Control' header set (must not be) : empty", cacheControlHeaders.size() == 0); + } + + public void testSetPathMatcherToNull() throws Exception { + new AssertThrows(IllegalArgumentException.class) { + public void test() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setPathMatcher(null); + } + }.runTest(); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java new file mode 100644 index 00000000000..b8e35f02671 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java @@ -0,0 +1,428 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + * @since 29.04.2003 + */ +public class WizardFormControllerTests extends TestCase { + + public void testNoDirtyPageChange() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + + assertTrue(wizard.getFormSessionAttributeName() != wizard.getPageSessionAttributeName()); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, null, 0, null, 0, "currentPage"); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "0"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1.x", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1.y", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("date", "not a date"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1.y", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // not allowed to go to 0 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "1"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, "myname", 32, "currentPage"); + // age set -> now allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + } + + public void testCustomSessionAttributes() throws Exception { + AbstractWizardFormController wizard = new TestWizardController() { + protected String getFormSessionAttributeName() { + return "myFormAttr"; + } + protected String getPageSessionAttributeName() { + return "myPageAttr"; + } + }; + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + assertTrue(session.getAttribute("myFormAttr") instanceof TestBean); + assertEquals(new Integer(0), session.getAttribute("myPageAttr")); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, null, 0, null, 0, "currentPage"); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "0"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, "currentPage"); + } + + public void testCustomRequestDependentSessionAttributes() throws Exception { + AbstractWizardFormController wizard = new TestWizardController() { + protected String getFormSessionAttributeName(HttpServletRequest request) { + return "myFormAttr" + request.getParameter("formAttr"); + } + protected String getPageSessionAttributeName(HttpServletRequest request) { + return "myPageAttr" + request.getParameter("pageAttr"); + } + }; + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + assertTrue(session.getAttribute("myFormAttr1") instanceof TestBean); + assertEquals(new Integer(0), session.getAttribute("myPageAttr2")); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, null, 0, null, 0, "currentPage"); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "0"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, "currentPage"); + } + + public void testDirtyBack() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(true); + wizard.setAllowDirtyForward(false); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 0, null, 0, null); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, null); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, "myname", 0, null); + // dirty back -> allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 1, "myname", 0, null); + // finish while dirty -> show dirty page (1) + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + // age set -> now allowed to finish + } + + public void testDirtyForward() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(true); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // dirty forward -> allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // not allowed to go to 0 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // age set -> now allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // finish while dirty -> show dirty page (0) + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH + ".x", "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + // name set -> now allowed to finish + } + + public void testSubmitWithoutValidation() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + + Properties params = new Properties(); + params.setProperty("formChange", "true"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // no validation -> allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // not allowed to go to 0 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // age set -> now allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // finish while dirty -> show dirty page (0) + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH + ".x", "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + // name set -> now allowed to finish + } + + public void testCancel() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_CANCEL, "value"); + performRequest(wizard, session, params, -2, null, 0, null); + + assertTrue(session.getAttribute(wizard.getFormSessionAttributeName()) == null); + assertTrue(session.getAttribute(wizard.getPageSessionAttributeName()) == null); + + session = performRequest(wizard, null, null, 0, null, 0, null); + params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_CANCEL + ".y", "value"); + performRequest(wizard, session, params, -2, null, 0, null); + } + + public void testInvalidSubmit() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + + Properties params = new Properties(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, "myname", 32, "currentPage"); + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 0, null, 0, "currentPage"); + // returned to initial page of new wizard form + } + + private HttpSession performRequest( + AbstractWizardFormController wizard, HttpSession session, Properties params, + int target, String name, int age, String pageAttr) throws Exception { + + MockHttpServletRequest request = new MockHttpServletRequest((params != null ? "POST" : "GET"), "/wizard"); + request.addParameter("formAttr", "1"); + request.addParameter("pageAttr", "2"); + if (params != null) { + for (Iterator it = params.keySet().iterator(); it.hasNext();) { + String param = (String) it.next(); + request.addParameter(param, params.getProperty(param)); + } + } + request.setSession(session); + request.setAttribute("target", new Integer(target)); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = wizard.handleRequest(request, response); + if (target >= 0) { + assertTrue("Page " + target + " returned", ("page" + target).equals(mv.getViewName())); + if (pageAttr != null) { + assertTrue("Page attribute set", (new Integer(target)).equals(mv.getModel().get(pageAttr))); + assertTrue("Correct model size", mv.getModel().size() == 3); + } + else { + assertTrue("Correct model size", mv.getModel().size() == 2); + } + assertTrue( + request.getSession().getAttribute(wizard.getFormSessionAttributeName(request)) instanceof TestBean); + assertEquals(new Integer(target), + request.getSession().getAttribute(wizard.getPageSessionAttributeName(request))); + } + else if (target == -1) { + assertTrue("Success target returned", "success".equals(mv.getViewName())); + assertTrue("Correct model size", mv.getModel().size() == 1); + assertTrue(request.getSession().getAttribute(wizard.getFormSessionAttributeName(request)) == null); + assertTrue(request.getSession().getAttribute(wizard.getPageSessionAttributeName(request)) == null); + } + else if (target == -2) { + assertTrue("Cancel view returned", "cancel".equals(mv.getViewName())); + assertTrue("Correct model size", mv.getModel().size() == 1); + assertTrue(request.getSession().getAttribute(wizard.getFormSessionAttributeName(request)) == null); + assertTrue(request.getSession().getAttribute(wizard.getPageSessionAttributeName(request)) == null); + } + TestBean tb = (TestBean) mv.getModel().get("tb"); + assertTrue("Has model", tb != null); + assertTrue("Name is " + name, ObjectUtils.nullSafeEquals(name, tb.getName())); + assertTrue("Age is " + age, tb.getAge() == age); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + "tb"); + if (params != null && params.containsKey("formChange")) { + assertNotNull(errors); + assertFalse(errors.hasErrors()); + } + return request.getSession(false); + } + + + private static class TestWizardController extends AbstractWizardFormController { + + public TestWizardController() { + setCommandClass(TestBean.class); + setCommandName("tb"); + setPages(new String[] {"page0", "page1"}); + } + + protected Map referenceData(HttpServletRequest request, int page) throws Exception { + assertEquals(new Integer(page), request.getAttribute("target")); + return super.referenceData(request, page); + } + + protected boolean suppressValidation(HttpServletRequest request, Object command) { + return (request.getParameter("formChange") != null); + } + + protected void validatePage(Object command, Errors errors, int page) { + TestBean tb = (TestBean) command; + switch (page) { + case 0: + if (tb.getName() == null) { + errors.rejectValue("name", "NAME_REQUIRED", null, "Name is required"); + } + break; + case 1: + if (tb.getAge() == 0) { + errors.rejectValue("age", "AGE_REQUIRED", null, "Age is required"); + } + break; + default: + throw new IllegalArgumentException("Invalid page number"); + } + } + + protected ModelAndView processFinish( + HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) + throws ServletException, IOException { + assertTrue(getCurrentPage(request) == 0 || getCurrentPage(request) == 1); + return new ModelAndView("success", getCommandName(), command); + } + + protected ModelAndView processCancel( + HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) + throws ServletException, IOException { + assertTrue(getCurrentPage(request) == 0 || getCurrentPage(request) == 1); + return new ModelAndView("cancel", getCommandName(), command); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/AdminController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/AdminController.java new file mode 100644 index 00000000000..650e201d0fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/AdminController.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import org.springframework.web.servlet.mvc.multiaction.MultiActionController; + +/** + * @author Rob Harrop + */ +public class AdminController extends MultiActionController { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java new file mode 100644 index 00000000000..3f42bdd83af --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import org.springframework.web.servlet.mvc.SimpleFormController; + +/** + * @author Rob Harrop + */ +public class BuyForm extends SimpleFormController { + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/Controller.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/Controller.java new file mode 100644 index 00000000000..307b6ab80d8 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/Controller.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + */ +public class Controller implements org.springframework.web.servlet.mvc.Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("indexView"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerBeanNameHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerBeanNameHandlerMappingTests.java new file mode 100644 index 00000000000..5351f35b581 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerBeanNameHandlerMappingTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Juergen Hoeller + */ +public class ControllerBeanNameHandlerMappingTests extends TestCase { + + public static final String LOCATION = "/org/springframework/web/servlet/mvc/mapping/name-mapping.xml"; + + private XmlWebApplicationContext wac; + + private HandlerMapping hm; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + this.wac = new XmlWebApplicationContext(); + this.wac.setServletContext(sc); + this.wac.setConfigLocations(new String[] {LOCATION}); + this.wac.refresh(); + this.hm = (HandlerMapping) this.wac.getBean("mapping"); + } + + public void testIndexUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + } + + public void testMapSimpleUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithContextPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + request.setContextPath("/myapp"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithMultiActionControllerMapping() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/admin"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("admin"), chain.getHandler()); + } + + public void testWithoutControllerSuffix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/buy"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerClassNameHandlerMappingTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerClassNameHandlerMappingTests.java new file mode 100644 index 00000000000..e822f40f043 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerClassNameHandlerMappingTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class ControllerClassNameHandlerMappingTests extends TestCase { + + public static final String LOCATION = "/org/springframework/web/servlet/mvc/mapping/class-mapping.xml"; + + private XmlWebApplicationContext wac; + + private HandlerMapping hm; + + private HandlerMapping hm2; + + private HandlerMapping hm3; + + private HandlerMapping hm4; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + this.wac = new XmlWebApplicationContext(); + this.wac.setServletContext(sc); + this.wac.setConfigLocations(new String[] {LOCATION}); + this.wac.refresh(); + this.hm = (HandlerMapping) this.wac.getBean("mapping"); + this.hm2 = (HandlerMapping) this.wac.getBean("mapping2"); + this.hm3 = (HandlerMapping) this.wac.getBean("mapping3"); + this.hm4 = (HandlerMapping) this.wac.getBean("mapping4"); + } + + public void testIndexUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + } + + public void testMapSimpleUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithContextPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + request.setContextPath("/myapp"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithMultiActionControllerMapping() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/admin/user"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("admin"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/admin/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("admin"), chain.getHandler()); + } + + public void testWithoutControllerSuffix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/buyform"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/mapping/welcome"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithBasePackageAndCaseSensitive() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/mapping/buyForm"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithFullBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + HandlerExecutionChain chain = this.hm3.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithRootAsBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/org/springframework/web/servlet/mvc/mapping/welcome"); + HandlerExecutionChain chain = this.hm4.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/WelcomeController.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/WelcomeController.java new file mode 100644 index 00000000000..5c36b0989d3 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/WelcomeController.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +/** + * @author Rob Harrop + */ +public class WelcomeController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("welcomeView"); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/class-mapping.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/class-mapping.xml new file mode 100644 index 00000000000..214b8498b31 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/class-mapping.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/name-mapping.xml b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/name-mapping.xml new file mode 100644 index 00000000000..67ec8eda816 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/mapping/name-mapping.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/multiaction/MultiActionControllerTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/multiaction/MultiActionControllerTests.java new file mode 100644 index 00000000000..ddf7bd44517 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/mvc/multiaction/MultiActionControllerTests.java @@ -0,0 +1,720 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.multiaction; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import junit.framework.TestCase; + +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.TestBean; +import org.springframework.context.ApplicationContextException; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.web.HttpSessionRequiredException; +import org.springframework.web.bind.ServletRequestBindingException; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Colin Sampaleanu + * @author Rob Harrop + * @author Sam Brannen + */ +public class MultiActionControllerTests extends TestCase { + + public void testDefaultInternalPathMethodNameResolver() throws Exception { + doDefaultTestInternalPathMethodNameResolver("/foo.html", "foo"); + doDefaultTestInternalPathMethodNameResolver("/foo/bar.html", "bar"); + doDefaultTestInternalPathMethodNameResolver("/bugal.xyz", "bugal"); + doDefaultTestInternalPathMethodNameResolver("/x/y/z/q/foo.html", "foo"); + doDefaultTestInternalPathMethodNameResolver("qqq.q", "qqq"); + } + + private void doDefaultTestInternalPathMethodNameResolver(String in, String expected) throws Exception { + MultiActionController rc = new MultiActionController(); + HttpServletRequest request = new MockHttpServletRequest("GET", in); + String actual = rc.getMethodNameResolver().getHandlerMethodName(request); + assertEquals("Wrong method name resolved", expected, actual); + } + + public void testCustomizedInternalPathMethodNameResolver() throws Exception { + doTestCustomizedInternalPathMethodNameResolver("/foo.html", "my", null, "myfoo"); + doTestCustomizedInternalPathMethodNameResolver("/foo/bar.html", null, "Handler", "barHandler"); + doTestCustomizedInternalPathMethodNameResolver("/Bugal.xyz", "your", "Method", "yourBugalMethod"); + } + + private void doTestCustomizedInternalPathMethodNameResolver(String in, String prefix, String suffix, String expected) + throws Exception { + + MultiActionController rc = new MultiActionController(); + InternalPathMethodNameResolver resolver = new InternalPathMethodNameResolver(); + if (prefix != null) { + resolver.setPrefix(prefix); + } + if (suffix != null) { + resolver.setSuffix(suffix); + } + rc.setMethodNameResolver(resolver); + HttpServletRequest request = new MockHttpServletRequest("GET", in); + String actual = rc.getMethodNameResolver().getHandlerMethodName(request); + assertEquals("Wrong method name resolved", expected, actual); + } + + public void testParameterMethodNameResolver() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver mnr = new ParameterMethodNameResolver(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", "bar"); + assertEquals("bar", mnr.getHandlerMethodName(request)); + + request = new MockHttpServletRequest("GET", "/foo.html"); + try { + mnr.getHandlerMethodName(request); + fail("Should have thrown NoSuchRequestHandlingMethodException"); + } + catch (NoSuchRequestHandlingMethodException expected) { + } + + request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", ""); + try { + mnr.getHandlerMethodName(request); + fail("Should have thrown NoSuchRequestHandlingMethodException"); + } + catch (NoSuchRequestHandlingMethodException expected) { + } + + request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", " "); + try { + mnr.getHandlerMethodName(request); + fail("Should have thrown NoSuchRequestHandlingMethodException"); + } + catch (NoSuchRequestHandlingMethodException expected) { + } + } + + public void testParameterMethodNameResolverWithCustomParamName() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver mnr = new ParameterMethodNameResolver(); + mnr.setParamName("myparam"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("myparam", "bar"); + assertEquals("bar", mnr.getHandlerMethodName(request)); + } + + public void testParameterMethodNameResolverWithParamNames() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver resolver = new ParameterMethodNameResolver(); + resolver.setDefaultMethodName("default"); + resolver.setMethodParamNames(new String[] { "hello", "spring", "colin" }); + Properties logicalMappings = new Properties(); + logicalMappings.setProperty("hello", "goodbye"); + logicalMappings.setProperty("nina", "colin"); + resolver.setLogicalMappings(logicalMappings); + + // verify default handler + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("this will not match anything", "whatever"); + assertEquals("default", resolver.getHandlerMethodName(request)); + + // verify first resolution strategy (action=method) + request = new MockHttpServletRequest(); + request.addParameter("action", "reset"); + assertEquals("reset", resolver.getHandlerMethodName(request)); + // this one also tests logical mapping + request = new MockHttpServletRequest(); + request.addParameter("action", "nina"); + assertEquals("colin", resolver.getHandlerMethodName(request)); + + // now validate second resolution strategy (parameter existence) + // this also tests logical mapping + request = new MockHttpServletRequest(); + request.addParameter("hello", "whatever"); + assertEquals("goodbye", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("spring", "whatever"); + assertEquals("spring", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("hello", "whatever"); + request.addParameter("spring", "whatever"); + assertEquals("goodbye", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("colin", "whatever"); + request.addParameter("spring", "whatever"); + assertEquals("spring", resolver.getHandlerMethodName(request)); + + // validate image button handling + request = new MockHttpServletRequest(); + request.addParameter("spring.x", "whatever"); + assertEquals("spring", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("hello.x", "whatever"); + request.addParameter("spring", "whatever"); + assertEquals("goodbye", resolver.getHandlerMethodName(request)); + } + + public void testParameterMethodNameResolverWithDefaultMethodName() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver mnr = new ParameterMethodNameResolver(); + mnr.setDefaultMethodName("foo"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", "bar"); + assertEquals("bar", mnr.getHandlerMethodName(request)); + request = new MockHttpServletRequest("GET", "/foo.html"); + assertEquals("foo", mnr.getHandlerMethodName(request)); + } + + public void testInvokesCorrectMethod() throws Exception { + TestMaController mc = new TestMaController(); + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + Properties p = new Properties(); + p.put("/welcome.html", "welcome"); + PropertiesMethodNameResolver mnr = new PropertiesMethodNameResolver(); + mnr.setMappings(p); + mc.setMethodNameResolver(mnr); + + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked welcome method", mc.wasInvoked("welcome")); + assertTrue("view name is welcome", mv.getViewName().equals("welcome")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + mc = new TestMaController(); + request = new MockHttpServletRequest("GET", "/subdir/test.html"); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + assertTrue("Invoked test method", mc.wasInvoked("test")); + assertTrue("view name is subdir_test", mv.getViewName().equals("test")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + } + + public void testPathMatching() throws Exception { + TestMaController mc = new TestMaController(); + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + Properties p = new Properties(); + p.put("/welc*.html", "welcome"); + PropertiesMethodNameResolver mn = new PropertiesMethodNameResolver(); + mn.setMappings(p); + mc.setMethodNameResolver(mn); + + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked welcome method", mc.wasInvoked("welcome")); + assertTrue("view name is welcome", mv.getViewName().equals("welcome")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + mc = new TestMaController(); + mc.setMethodNameResolver(mn); + request = new MockHttpServletRequest("GET", "/nomatch"); + response = new MockHttpServletResponse(); + try { + mv = mc.handleRequest(request, response); + } + catch (Exception expected) { + } + assertFalse("Not invoking welcome method", mc.wasInvoked("welcome")); + assertTrue("No method invoked", mc.getInvokedMethods() == 0); + } + + public void testInvokesCorrectMethodOnDelegate() throws Exception { + MultiActionController mac = new MultiActionController(); + TestDelegate d = new TestDelegate(); + mac.setDelegate(d); + HttpServletRequest request = new MockHttpServletRequest("GET", "/test.html"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mac.handleRequest(request, response); + assertTrue("view name is test", mv.getViewName().equals("test")); + assertTrue("Delegate was invoked", d.invoked); + } + + public void testInvokesCorrectMethodWithSession() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/inSession.html"); + request.setSession(new MockHttpSession(null)); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked inSession method", mc.wasInvoked("inSession")); + assertTrue("view name is welcome", mv.getViewName().equals("inSession")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + request = new MockHttpServletRequest("GET", "/inSession.html"); + response = new MockHttpServletResponse(); + try { + + mc.handleRequest(request, response); + fail("Must have rejected request without session"); + } + catch (ServletException expected) { + } + } + + public void testInvokesCommandMethodNoSession() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/commandNoSession.html"); + request.addParameter("name", "rod"); + request.addParameter("age", "32"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked commandNoSession method", mc.wasInvoked("commandNoSession")); + assertTrue("view name is commandNoSession", mv.getViewName().equals("commandNoSession")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + } + + public void testInvokesCommandMethodWithSession() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/commandInSession.html"); + request.addParameter("name", "rod"); + request.addParameter("age", "32"); + + request.setSession(new MockHttpSession(null)); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked commandInSession method", mc.wasInvoked("commandInSession")); + assertTrue("view name is commandInSession", mv.getViewName().equals("commandInSession")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + request = new MockHttpServletRequest("GET", "/commandInSession.html"); + response = new MockHttpServletResponse(); + try { + + mc.handleRequest(request, response); + fail("Must have rejected request without session"); + } + catch (ServletException expected) { + } + } + + public void testSessionRequiredCatchable() throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/testSession.html"); + HttpServletResponse response = new MockHttpServletResponse(); + TestMaController contr = new TestSessionRequiredController(); + try { + contr.handleRequest(request, response); + fail("Should have thrown exception"); + } + catch (HttpSessionRequiredException ex) { + // assertTrue("session required", ex.equals(t)); + } + request = new MockHttpServletRequest("GET", "/testSession.html"); + response = new MockHttpServletResponse(); + contr = new TestSessionRequiredExceptionHandler(); + ModelAndView mv = contr.handleRequest(request, response); + assertTrue("Name is ok", mv.getViewName().equals("handle(SRE)")); + } + + private void testExceptionNoHandler(TestMaController mc, Throwable t) throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/testException.html"); + request.setAttribute(TestMaController.THROWABLE_ATT, t); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown exception"); + } + catch (Throwable ex) { + assertTrue(ex.equals(t)); + } + } + + private void testExceptionNoHandler(Throwable t) throws Exception { + testExceptionNoHandler(new TestMaController(), t); + } + + public void testExceptionNoHandler() throws Exception { + testExceptionNoHandler(new Exception()); + + // must go straight through + testExceptionNoHandler(new ServletException()); + + // subclass of servlet exception + testExceptionNoHandler(new ServletRequestBindingException("foo")); + testExceptionNoHandler(new RuntimeException()); + testExceptionNoHandler(new Error()); + } + + public void testLastModifiedDefault() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + long lastMod = mc.getLastModified(request); + assertTrue("default last modified is -1", lastMod == -1L); + } + + public void testLastModifiedWithMethod() throws Exception { + LastModController mc = new LastModController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + long lastMod = mc.getLastModified(request); + assertTrue("last modified with method is > -1", lastMod == mc.getLastModified(request)); + } + + private ModelAndView testHandlerCaughtException(TestMaController mc, Throwable t) throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/testException.html"); + request.setAttribute(TestMaController.THROWABLE_ATT, t); + HttpServletResponse response = new MockHttpServletResponse(); + return mc.handleRequest(request, response); + } + + public void testHandlerCaughtException() throws Exception { + TestMaController mc = new TestExceptionHandler(); + ModelAndView mv = testHandlerCaughtException(mc, new Exception()); + assertNotNull("ModelAndView must not be null", mv); + assertTrue("mv name is handle(Exception)", "handle(Exception)".equals(mv.getViewName())); + assertTrue("Invoked correct method", mc.wasInvoked("handle(Exception)")); + + // WILL GET RUNTIME EXCEPTIONS TOO + testExceptionNoHandler(mc, new Error()); + + mc = new TestServletExceptionHandler(); + mv = testHandlerCaughtException(mc, new ServletException()); + assertTrue(mv.getViewName().equals("handle(ServletException)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(ServletException)")); + + mv = testHandlerCaughtException(mc, new ServletRequestBindingException("foo")); + assertTrue(mv.getViewName().equals("handle(ServletException)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(ServletException)")); + + // Check it doesn't affect unknown exceptions + testExceptionNoHandler(mc, new RuntimeException()); + testExceptionNoHandler(mc, new Error()); + testExceptionNoHandler(mc, new SQLException()); + testExceptionNoHandler(mc, new Exception()); + + mc = new TestRuntimeExceptionHandler(); + mv = testHandlerCaughtException(mc, new RuntimeException()); + assertTrue(mv.getViewName().equals("handle(RTE)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(RTE)")); + mv = testHandlerCaughtException(mc, new FatalBeanException(null, null)); + assertTrue(mv.getViewName().equals("handle(RTE)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(RTE)")); + + testExceptionNoHandler(mc, new SQLException()); + testExceptionNoHandler(mc, new Exception()); + } + + public void testHandlerReturnsMap() throws Exception { + Map model = new HashMap(); + model.put("message", "Hello World!"); + + MultiActionController mac = new ModelOnlyMultiActionController(model); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertFalse("ModelAndView should not have a view", mav.hasView()); + assertEquals(model, mav.getModel()); + } + + public void testExceptionHandlerReturnsMap() throws Exception { + Map model = new HashMap(); + + MultiActionController mac = new ModelOnlyMultiActionController(model); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertFalse("ModelAndView should not have a view", mav.hasView()); + assertTrue(model.containsKey("exception")); + } + + public void testCannotCallExceptionHandlerDirectly() throws Exception { + Map model = new HashMap(); + + MultiActionController mac = new ModelOnlyMultiActionController(model); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handleIllegalStateException.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus()); + } + + public void testHandlerReturnsVoid() throws Exception { + MultiActionController mac = new VoidMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNull("ModelAndView must be null", mav); + } + + public void testExceptionHandlerReturnsVoid() throws Exception { + MultiActionController mac = new VoidMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNull("ModelAndView must be null", mav); + assertEquals("exception", response.getContentAsString()); + } + + public void testHandlerReturnsString() throws Exception { + MultiActionController mac = new StringMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertTrue("ModelAndView must have a view", mav.hasView()); + assertEquals("Verifying view name", "welcomeString", mav.getViewName()); + } + + public void testExceptionHandlerReturnsString() throws Exception { + MultiActionController mac = new StringMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertTrue("ModelAndView must have a view", mav.hasView()); + assertEquals("Verifying view name", "handleIllegalStateExceptionString", mav.getViewName()); + } + + + /** No error handlers */ + public static class TestMaController extends MultiActionController { + + public static final String THROWABLE_ATT = "throwable"; + + /** Method name -> object */ + protected Map invoked = new HashMap(); + + public void clear() { + this.invoked.clear(); + } + + public ModelAndView welcome(HttpServletRequest request, HttpServletResponse response) { + this.invoked.put("welcome", Boolean.TRUE); + return new ModelAndView("welcome"); + } + + public ModelAndView commandNoSession(HttpServletRequest request, HttpServletResponse response, TestBean command) { + this.invoked.put("commandNoSession", Boolean.TRUE); + + String pname = request.getParameter("name"); + String page = request.getParameter("age"); + // ALLOW FOR NULL + if (pname == null) { + assertTrue("name null", command.getName() == null); + } + else { + assertTrue("name param set", pname.equals(command.getName())); + } + // if (page == null) + // assertTrue("age default", command.getAge() == 0); + // else + // assertTrue("age set", command.getName().equals(pname)); + // assertTrue("a", + // command.getAge().equals(request.getParameter("name"))); + return new ModelAndView("commandNoSession"); + } + + public ModelAndView inSession(HttpServletRequest request, HttpServletResponse response, HttpSession session) { + this.invoked.put("inSession", Boolean.TRUE); + assertTrue("session non null", session != null); + return new ModelAndView("inSession"); + } + + public ModelAndView commandInSession(HttpServletRequest request, HttpServletResponse response, + HttpSession session, TestBean command) { + this.invoked.put("commandInSession", Boolean.TRUE); + assertTrue("session non null", session != null); + return new ModelAndView("commandInSession"); + } + + public ModelAndView test(HttpServletRequest request, HttpServletResponse response) { + this.invoked.put("test", Boolean.TRUE); + return new ModelAndView("test"); + } + + public ModelAndView testException(HttpServletRequest request, HttpServletResponse response) throws Throwable { + this.invoked.put("testException", Boolean.TRUE); + Throwable t = (Throwable) request.getAttribute(THROWABLE_ATT); + if (t != null) { + throw t; + } + else { + return new ModelAndView("no throwable"); + } + } + + public boolean wasInvoked(String method) { + return this.invoked.get(method) != null; + } + + public int getInvokedMethods() { + return this.invoked.size(); + } + } + + + public static class TestDelegate { + + boolean invoked; + + public ModelAndView test(HttpServletRequest request, HttpServletResponse response) { + this.invoked = true; + return new ModelAndView("test"); + } + } + + + public static class TestExceptionHandler extends TestMaController { + + public ModelAndView handleAnyException(HttpServletRequest request, HttpServletResponse response, Exception ex) { + this.invoked.put("handle(Exception)", Boolean.TRUE); + return new ModelAndView("handle(Exception)"); + } + } + + + public static class TestRuntimeExceptionHandler extends TestMaController { + + public ModelAndView handleRuntimeProblem(HttpServletRequest request, HttpServletResponse response, + RuntimeException ex) { + this.invoked.put("handle(RTE)", Boolean.TRUE); + return new ModelAndView("handle(RTE)"); + } + } + + + public static class TestSessionRequiredController extends TestMaController { + + public ModelAndView testSession(HttpServletRequest request, HttpServletResponse response, HttpSession sess) { + return null; + } + } + + + /** Extends previous to handle exception */ + public static class TestSessionRequiredExceptionHandler extends TestSessionRequiredController { + + public ModelAndView handleServletException(HttpServletRequest request, HttpServletResponse response, + HttpSessionRequiredException ex) { + this.invoked.put("handle(SRE)", Boolean.TRUE); + return new ModelAndView("handle(SRE)"); + } + } + + public static class TestServletExceptionHandler extends TestMaController { + + public ModelAndView handleServletException(HttpServletRequest request, HttpServletResponse response, + ServletException ex) { + this.invoked.put("handle(ServletException)", Boolean.TRUE); + return new ModelAndView("handle(ServletException)"); + } + } + + + public static class LastModController extends MultiActionController { + + public static final String THROWABLE_ATT = "throwable"; + + /** Method name -> object */ + protected HashMap invoked = new HashMap(); + + public void clear() { + this.invoked.clear(); + } + + public ModelAndView welcome(HttpServletRequest request, HttpServletResponse response) { + this.invoked.put("welcome", Boolean.TRUE); + return new ModelAndView("welcome"); + } + + /** Always says content is up to date */ + public long welcomeLastModified(HttpServletRequest request) { + return 1111L; + } + } + + + public static class ModelOnlyMultiActionController extends MultiActionController { + + private final Map model; + + public ModelOnlyMultiActionController(Map model) throws ApplicationContextException { + this.model = model; + } + + public Map welcome(HttpServletRequest request, HttpServletResponse response) { + return this.model; + } + + public Map index(HttpServletRequest request, HttpServletResponse response) { + throw new IllegalStateException(); + } + + public Map handleIllegalStateException(HttpServletRequest request, HttpServletResponse response, + IllegalStateException ex) { + this.model.put("exception", ex); + return this.model; + } + } + + + public static class VoidMultiActionController extends MultiActionController { + + public void welcome(HttpServletRequest request, HttpServletResponse response) { + } + + public void index(HttpServletRequest request, HttpServletResponse response) { + throw new IllegalStateException(); + } + + public void handleIllegalStateException(HttpServletRequest request, HttpServletResponse response, + IllegalStateException ex) throws IOException { + response.getWriter().write("exception"); + } + } + + + public static class StringMultiActionController extends MultiActionController { + + public String welcome(HttpServletRequest request, HttpServletResponse response) { + return "welcomeString"; + } + + public String index(HttpServletRequest request, HttpServletResponse response) { + throw new IllegalStateException(); + } + + public String handleIllegalStateException(HttpServletRequest request, HttpServletResponse response, + IllegalStateException ex) throws IOException { + return "handleIllegalStateExceptionString"; + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java new file mode 100644 index 00000000000..59d76364aac --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags; + +import java.io.StringWriter; + +import javax.servlet.jsp.JspWriter; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockBodyContent; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockPageContext; +import org.springframework.mock.web.MockServletContext; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.SimpleWebApplicationContext; +import org.springframework.web.servlet.ThemeResolver; +import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; +import org.springframework.web.servlet.theme.FixedThemeResolver; + +/** + * Abstract base class for testing tags: provides createPageContext. + * + * @author Alef Arendsen + * @author Juergen Hoeller + */ +public abstract class AbstractTagTests extends TestCase { + + protected MockPageContext createPageContext() { + MockServletContext sc = new MockServletContext(); + SimpleWebApplicationContext wac = new SimpleWebApplicationContext(); + wac.setServletContext(sc); + wac.setNamespace("test"); + wac.refresh(); + + MockHttpServletRequest request = new MockHttpServletRequest(sc); + MockHttpServletResponse response = new MockHttpServletResponse(); + if (inDispatcherServlet()) { + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + LocaleResolver lr = new AcceptHeaderLocaleResolver(); + request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, lr); + ThemeResolver tr = new FixedThemeResolver(); + request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, tr); + request.setAttribute(DispatcherServlet.THEME_SOURCE_ATTRIBUTE, wac); + } + else { + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + } + + return new MockPageContext(sc, request, response); + } + + protected boolean inDispatcherServlet() { + return true; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagOutsideDispatcherServletTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagOutsideDispatcherServletTests.java new file mode 100644 index 00000000000..e4fce1213fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagOutsideDispatcherServletTests.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags; + +/** + * @author Juergen Hoeller + * @since 14.01.2005 + */ +public class BindTagOutsideDispatcherServletTests extends BindTagTests { + + protected boolean inDispatcherServlet() { + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagTests.java new file mode 100644 index 00000000000..747ee0e9a1e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/BindTagTests.java @@ -0,0 +1,1040 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags; + +import java.beans.PropertyEditorSupport; +import java.io.StringWriter; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Set; + +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.tagext.Tag; + +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.NestedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.DataBinder; +import org.springframework.validation.Errors; +import org.springframework.web.bind.ServletRequestDataBinder; +import org.springframework.web.servlet.support.BindStatus; +import org.springframework.web.servlet.tags.form.FormTag; +import org.springframework.web.servlet.tags.form.TagWriter; + +/** + * @author Juergen Hoeller + * @author Alef Arendsen + * @author Mark Fisher + */ +public class BindTagTests extends AbstractTagTests { + + public void testBindTagWithoutErrors() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", status.getExpression() == null); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", !status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 0); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 0); + assertTrue("Correct errorCode", "".equals(status.getErrorCode())); + assertTrue("Correct errorMessage", "".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "".equals(status.getErrorMessagesAsString(","))); + } + + public void testBindTagWithGlobalErrors() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + errors.reject("code1", "message1"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", status.getExpression() == null); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 1); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 1); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "message1".equals(status.getErrorMessagesAsString(","))); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.*"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "*".equals(status.getExpression())); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 1); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 1); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "message1".equals(status.getErrorMessagesAsString(","))); + } + + public void testBindTagWithGlobalErrorsAndNoDefaultMessage() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + errors.reject("code1"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", status.getExpression() == null); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 1); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.*"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "*".equals(status.getExpression())); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 1); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + } + + public void testBindTagWithGlobalErrorsAndDefaultMessageOnly() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + errors.reject(null, "message1"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", status.getExpression() == null); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 1); + assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "message1".equals(status.getErrorMessagesAsString(","))); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.*"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "*".equals(status.getExpression())); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 1); + assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "message1".equals(status.getErrorMessagesAsString(","))); + } + + public void testBindStatusGetErrorMessagesAsString() throws JspException { + // one error (should not include delimiter) + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + errors.reject("code1", null, "message1"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + tag.doStartTag(); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertEquals("Error messages String should be 'message1'", + status.getErrorMessagesAsString(","), "message1"); + + // two errors + pc = createPageContext(); + errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + errors.reject("code1", null, "message1"); + errors.reject("code1", null, "message2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + tag.doStartTag(); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertEquals("Error messages String should be 'message1,message2'", + status.getErrorMessagesAsString(","), "message1,message2"); + + // no errors + pc = createPageContext(); + errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + tag.doStartTag(); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertEquals("Error messages String should be ''", status.getErrorMessagesAsString(","), ""); + } + + public void testBindTagWithFieldErrors() throws JspException { + PageContext pc = createPageContext(); + TestBean tb = new TestBean(); + tb.setName("name1"); + Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); + errors.rejectValue("name", "code1", "message & 1"); + errors.rejectValue("name", "code2", "message2"); + errors.rejectValue("age", "code2", "message2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.name"); + tag.setHtmlEscape("true"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "name".equals(status.getExpression())); + assertTrue("Correct value", "name1".equals(status.getValue())); + assertTrue("Correct displayValue", "name1".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 2); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 2); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessages()[0])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); + assertTrue("Correct errorMessagesAsString", + "message & 1 - message2".equals(status.getErrorMessagesAsString(" - "))); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.age"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "age".equals(status.getExpression())); + assertTrue("Correct value", new Integer(0).equals(status.getValue())); + assertTrue("Correct displayValue", "0".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 1); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 1); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCode())); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "message2".equals(status.getErrorMessagesAsString(" - "))); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.*"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "*".equals(status.getExpression())); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 3); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 3); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[2])); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessages()[0])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[2])); + } + + public void testBindTagWithFieldErrorsAndNoDefaultMessage() throws JspException { + PageContext pc = createPageContext(); + TestBean tb = new TestBean(); + tb.setName("name1"); + Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); + errors.rejectValue("name", "code1"); + errors.rejectValue("name", "code2"); + errors.rejectValue("age", "code2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.name"); + tag.setHtmlEscape("true"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "name".equals(status.getExpression())); + assertTrue("Correct value", "name1".equals(status.getValue())); + assertTrue("Correct displayValue", "name1".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 2); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.age"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "age".equals(status.getExpression())); + assertTrue("Correct value", new Integer(0).equals(status.getValue())); + assertTrue("Correct displayValue", "0".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 1); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCode())); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.*"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "*".equals(status.getExpression())); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 3); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[2])); + } + + public void testBindTagWithFieldErrorsAndDefaultMessageOnly() throws JspException { + PageContext pc = createPageContext(); + TestBean tb = new TestBean(); + tb.setName("name1"); + Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); + errors.rejectValue("name", null, "message & 1"); + errors.rejectValue("name", null, "message2"); + errors.rejectValue("age", null, "message2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.name"); + tag.setHtmlEscape("true"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "name".equals(status.getExpression())); + assertTrue("Correct value", "name1".equals(status.getValue())); + assertTrue("Correct displayValue", "name1".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 2); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessages()[0])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); + assertTrue("Correct errorMessagesAsString", + "message & 1 - message2".equals(status.getErrorMessagesAsString(" - "))); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.age"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "age".equals(status.getExpression())); + assertTrue("Correct value", new Integer(0).equals(status.getValue())); + assertTrue("Correct displayValue", "0".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 1); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "message2".equals(status.getErrorMessagesAsString(" - "))); + + tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.*"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "*".equals(status.getExpression())); + assertTrue("Correct value", status.getValue() == null); + assertTrue("Correct displayValue", "".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 3); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessage", "message & 1".equals(status.getErrorMessages()[0])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[2])); + } + + public void testBindTagWithNestedFieldErrors() throws JspException { + PageContext pc = createPageContext(); + TestBean tb = new TestBean(); + tb.setName("name1"); + TestBean spouse = new TestBean(); + spouse.setName("name2"); + tb.setSpouse(spouse); + Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); + errors.rejectValue("spouse.name", "code1", "message1"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + pc.setAttribute("myattr", "tb.spouse.name"); + tag.setPath("${myattr}"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "spouse.name".equals(status.getExpression())); + assertTrue("Correct value", "name2".equals(status.getValue())); + assertTrue("Correct displayValue", "name2".equals(status.getDisplayValue())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 1); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 1); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCode())); + assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessage())); + assertTrue("Correct errorMessagesAsString", "message1".equals(status.getErrorMessagesAsString(" - "))); + } + + public void testPropertyExposing() throws JspException { + PageContext pc = createPageContext(); + TestBean tb = new TestBean(); + tb.setName("name1"); + Errors errors = new BindException(tb, "tb"); + errors.rejectValue("name", "code1", null, "message & 1"); + errors.rejectValue("name", "code2", null, "message2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + // test global property (should be null) + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + assertNull(tag.getProperty()); + + // test property set (tb.name) + tag.release(); + tag.setPageContext(pc); + tag.setPath("tb.name"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + assertEquals("name", tag.getProperty()); + } + + public void testBindTagWithIndexedProperties() throws JspException { + PageContext pc = createPageContext(); + IndexedTestBean tb = new IndexedTestBean(); + Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); + errors.rejectValue("array[0]", "code1", "message1"); + errors.rejectValue("array[0]", "code2", "message2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.array[0]"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "array[0]".equals(status.getExpression())); + assertTrue("Value is TestBean", status.getValue() instanceof TestBean); + assertTrue("Correct value", "name0".equals(((TestBean) status.getValue()).getName())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 2); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 2); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); + assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessages()[0])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); + } + + public void testBindTagWithMappedProperties() throws JspException { + PageContext pc = createPageContext(); + IndexedTestBean tb = new IndexedTestBean(); + Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); + errors.rejectValue("map[key1]", "code1", "message1"); + errors.rejectValue("map[key1]", "code2", "message2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.map[key1]"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "map[key1]".equals(status.getExpression())); + assertTrue("Value is TestBean", status.getValue() instanceof TestBean); + assertTrue("Correct value", "name4".equals(((TestBean) status.getValue()).getName())); + assertTrue("Correct isError", status.isError()); + assertTrue("Correct errorCodes", status.getErrorCodes().length == 2); + assertTrue("Correct errorMessages", status.getErrorMessages().length == 2); + assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); + assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); + assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessages()[0])); + assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); + } + + public void testBindTagWithIndexedPropertiesAndCustomEditor() throws JspException { + PageContext pc = createPageContext(); + IndexedTestBean tb = new IndexedTestBean(); + DataBinder binder = new ServletRequestDataBinder(tb, "tb"); + binder.registerCustomEditor(TestBean.class, null, new PropertyEditorSupport() { + public String getAsText() { + return "something"; + } + }); + Errors errors = binder.getBindingResult(); + errors.rejectValue("array[0]", "code1", "message1"); + errors.rejectValue("array[0]", "code2", "message2"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.array[0]"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertTrue("Correct expression", "array[0]".equals(status.getExpression())); + // because of the custom editor getValue() should return a String + assertTrue("Value is TestBean", status.getValue() instanceof String); + assertTrue("Correct value", "something".equals(status.getValue())); + } + + public void testBindTagWithToStringAndHtmlEscaping() throws JspException { + PageContext pc = createPageContext(); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.doctor"); + tag.setHtmlEscape("true"); + TestBean tb = new TestBean("somebody", 99); + NestedTestBean ntb = new NestedTestBean("juergen&eva"); + tb.setDoctor(ntb); + pc.getRequest().setAttribute("tb", tb); + tag.doStartTag(); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertEquals("doctor", status.getExpression()); + assertTrue(status.getValue() instanceof NestedTestBean); + assertTrue(status.getDisplayValue().indexOf("juergen&eva") != -1); + } + + public void testBindTagWithSetValueAndHtmlEscaping() throws JspException { + PageContext pc = createPageContext(); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.someSet"); + tag.setHtmlEscape("true"); + pc.getRequest().setAttribute("tb", new TestBean("juergen&eva", 99)); + tag.doStartTag(); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertEquals("someSet", status.getExpression()); + assertTrue(status.getValue() instanceof Set); + } + + public void testBindTagWithFieldButWithoutErrorsInstance() throws JspException { + PageContext pc = createPageContext(); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.name"); + pc.getRequest().setAttribute("tb", new TestBean("juergen&eva", 99)); + tag.doStartTag(); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertEquals("name", status.getExpression()); + assertEquals("juergen&eva", status.getValue()); + } + + public void testBindTagWithFieldButWithoutErrorsInstanceAndHtmlEscaping() throws JspException { + PageContext pc = createPageContext(); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb.name"); + tag.setHtmlEscape("true"); + pc.getRequest().setAttribute("tb", new TestBean("juergen&eva", 99)); + tag.doStartTag(); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertEquals("name", status.getExpression()); + assertEquals("juergen&eva", status.getValue()); + } + + public void testBindTagWithBeanButWithoutErrorsInstance() throws JspException { + PageContext pc = createPageContext(); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + pc.getRequest().setAttribute("tb", new TestBean("juergen", 99)); + tag.doStartTag(); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertNull(status.getExpression()); + assertNull(status.getValue()); + } + + public void testBindTagWithoutBean() throws JspException { + PageContext pc = createPageContext(); + BindTag tag = new BindTag(); + tag.setPageContext(pc); + tag.setPath("tb"); + try { + tag.doStartTag(); + fail("Should have thrown JspException"); + } + catch (JspException ex) { + // expected + } + } + + + public void testBindErrorsTagWithoutErrors() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + BindErrorsTag tag = new BindErrorsTag(); + tag.setPageContext(pc); + tag.setName("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.SKIP_BODY); + assertTrue("Doesn't have errors variable", pc.getAttribute(BindErrorsTag.ERRORS_VARIABLE_NAME) == null); + } + + public void testBindErrorsTagWithErrors() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + errors.reject("test", null, "test"); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + BindErrorsTag tag = new BindErrorsTag(); + tag.setPageContext(pc); + tag.setName("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + assertTrue("Has errors variable", pc.getAttribute(BindErrorsTag.ERRORS_VARIABLE_NAME, PageContext.REQUEST_SCOPE) == errors); + } + + public void testBindErrorsTagWithoutBean() throws JspException { + PageContext pc = createPageContext(); + BindErrorsTag tag = new BindErrorsTag(); + tag.setPageContext(pc); + tag.setName("tb"); + assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.SKIP_BODY); + } + + + public void testNestedPathDoEndTag() throws JspException { + PageContext pc = createPageContext(); + NestedPathTag tag = new NestedPathTag(); + tag.setPath("foo"); + tag.setPageContext(pc); + tag.doStartTag(); + int returnValue = tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, returnValue); + assertNull(pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + } + + public void testNestedPathDoEndTagWithNesting() throws JspException { + PageContext pc = createPageContext(); + NestedPathTag tag = new NestedPathTag(); + tag.setPath("foo"); + tag.setPageContext(pc); + tag.doStartTag(); + + NestedPathTag anotherTag = new NestedPathTag(); + anotherTag.setPageContext(pc); + anotherTag.setPath("bar"); + anotherTag.doStartTag(); + anotherTag.doEndTag(); + + assertEquals("foo.", pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + + tag.doEndTag(); + assertNull(pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + } + + public void testNestedPathDoStartTagInternal() throws JspException { + PageContext pc = createPageContext(); + NestedPathTag tag = new NestedPathTag(); + tag.setPath("foo"); + tag.setPageContext(pc); + int returnValue = tag.doStartTag(); + + assertEquals(Tag.EVAL_BODY_INCLUDE, returnValue); + assertEquals("foo.", pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + } + + public void testNestedPathDoStartTagInternalWithNesting() throws JspException { + PageContext pc = createPageContext(); + NestedPathTag tag = new NestedPathTag(); + tag.setPath("foo"); + tag.setPageContext(pc); + tag.doStartTag(); + assertEquals("foo.", pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + + NestedPathTag anotherTag = new NestedPathTag(); + anotherTag.setPageContext(pc); + anotherTag.setPath("bar"); + anotherTag.doStartTag(); + + assertEquals("foo.bar.", pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + + NestedPathTag yetAnotherTag = new NestedPathTag(); + yetAnotherTag.setPageContext(pc); + yetAnotherTag.setPath("boo"); + yetAnotherTag.doStartTag(); + + assertEquals("foo.bar.boo.", pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + + yetAnotherTag.doEndTag(); + + NestedPathTag andAnotherTag = new NestedPathTag(); + andAnotherTag.setPageContext(pc); + andAnotherTag.setPath("boo2"); + andAnotherTag.doStartTag(); + + assertEquals("foo.bar.boo2.", pc.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + } + + public void testNestedPathWithBindTag() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb").getBindingResult(); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); + + NestedPathTag nestedPathTag = new NestedPathTag(); + nestedPathTag.setPath("tb"); + nestedPathTag.setPageContext(pc); + nestedPathTag.doStartTag(); + + BindTag bindTag = new BindTag(); + bindTag.setPageContext(pc); + bindTag.setPath("name"); + + assertTrue("Correct doStartTag return value", bindTag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertEquals("tb.name", status.getPath()); + assertEquals("Correct field value", "", status.getDisplayValue()); + + BindTag bindTag2 = new BindTag(); + bindTag2.setPageContext(pc); + bindTag2.setPath("age"); + + assertTrue("Correct doStartTag return value", bindTag2.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status2 = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status2 != null); + assertEquals("tb.age", status2.getPath()); + assertEquals("Correct field value", "0", status2.getDisplayValue()); + + bindTag2.doEndTag(); + + BindStatus status3 = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertSame("Status matches previous status", status, status3); + assertEquals("tb.name", status.getPath()); + assertEquals("Correct field value", "", status.getDisplayValue()); + + bindTag.doEndTag(); + nestedPathTag.doEndTag(); + } + + public void testNestedPathWithBindTagWithIgnoreNestedPath() throws JspException { + PageContext pc = createPageContext(); + Errors errors = new ServletRequestDataBinder(new TestBean(), "tb2").getBindingResult(); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb2", errors); + + NestedPathTag tag = new NestedPathTag(); + tag.setPath("tb"); + tag.setPageContext(pc); + tag.doStartTag(); + + BindTag bindTag = new BindTag(); + bindTag.setPageContext(pc); + bindTag.setIgnoreNestedPath(true); + bindTag.setPath("tb2.name"); + + assertTrue("Correct doStartTag return value", bindTag.doStartTag() == Tag.EVAL_BODY_INCLUDE); + BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); + assertTrue("Has status variable", status != null); + assertEquals("tb2.name", status.getPath()); + } + + public void testTransformTagCorrectBehavior() throws JspException { + // first set up the pagecontext and the bean + PageContext pc = createPageContext(); + TestBean tb = new TestBean(); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + ServletRequestDataBinder binder = new ServletRequestDataBinder(tb, "tb"); + CustomDateEditor l = new CustomDateEditor(df, true); + binder.registerCustomEditor(Date.class, l); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", binder.getBindingResult()); + + // execute the bind tag using the date property + BindTag bind = new BindTag(); + bind.setPageContext(pc); + bind.setPath("tb.date"); + bind.doStartTag(); + + // transform stuff + TransformTag transform = new TransformTag(); + transform.setPageContext(pc); + pc.setAttribute("date", tb.getDate()); + transform.setParent(bind); + transform.setValue("${date}"); + transform.setVar("theDate"); + transform.doStartTag(); + + assertNotNull(pc.getAttribute("theDate")); + assertEquals(pc.getAttribute("theDate"), df.format(tb.getDate())); + + // try another time, this time using Strings + bind = new BindTag(); + bind.setPageContext(pc); + bind.setPath("tb.name"); + bind.doStartTag(); + + transform = new TransformTag(); + transform.setPageContext(pc); + pc.setAttribute("string", "name"); + transform.setValue("${string}"); + transform.setParent(bind); + transform.setVar("theString"); + transform.doStartTag(); + + assertNotNull(pc.getAttribute("theString")); + assertEquals(pc.getAttribute("theString"), "name"); + } + + public void testTransformTagWithHtmlEscape() throws JspException { + // first set up the PageContext and the bean + PageContext pc = createPageContext(); + TestBean tb = new TestBean(); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + ServletRequestDataBinder binder = new ServletRequestDataBinder(tb, "tb"); + CustomDateEditor l = new CustomDateEditor(df, true); + binder.registerCustomEditor(Date.class, l); + pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", binder.getBindingResult()); + + // try another time, this time using Strings + BindTag bind = new BindTag(); + bind.setPageContext(pc); + bind.setPath("tb.name"); + bind.doStartTag(); + + TransformTag transform = new TransformTag(); + transform.setPageContext(pc); + pc.setAttribute("string", "na -1); + } + + protected final void assertAttributeNotPresent(String output, String attributeName) { + assertTrue("Unexpected attribute '" + attributeName + "' in output '" + output + "'.", + output.indexOf(attributeName + "=\"") < 0); + } + + protected final void assertBlockTagContains(String output, String desiredContents) { + String contents = output.substring(output.indexOf(">") + 1, output.lastIndexOf("<")); + assertTrue("Expected to find '" + desiredContents + "' in the contents of block tag '" + output + "'", + contents.indexOf(desiredContents) > -1); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxTagTests.java new file mode 100644 index 00000000000..0d81c67f52a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxTagTests.java @@ -0,0 +1,624 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags.form; + +import java.beans.PropertyEditorSupport; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import javax.servlet.jsp.tagext.Tag; + +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +import org.springframework.beans.Colour; +import org.springframework.beans.Pet; +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.BindingResult; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class CheckboxTagTests extends AbstractFormTagTests { + + private CheckboxTag tag; + + private TestBean bean; + + protected void onSetUp() { + this.tag = new CheckboxTag() { + protected TagWriter createTagWriter() { + return new TagWriter(getWriter()); + } + }; + this.tag.setPageContext(getPageContext()); + } + + public void testWithSingleValueBooleanObjectChecked() throws Exception { + this.tag.setPath("someBoolean"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element rootElement = document.getRootElement(); + assertEquals("Both tag and hidden element not rendered", 2, rootElement.elements().size()); + Element checkboxElement = (Element) rootElement.elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("someBoolean", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals("true", checkboxElement.attribute("value").getValue()); + } + + public void testWithSingleValueBooleanChecked() throws Exception { + this.tag.setPath("jedi"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("jedi", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals("true", checkboxElement.attribute("value").getValue()); + } + + public void testWithSingleValueBooleanObjectUnchecked() throws Exception { + this.bean.setSomeBoolean(new Boolean(false)); + this.tag.setPath("someBoolean"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("someBoolean", checkboxElement.attribute("name").getValue()); + assertNull(checkboxElement.attribute("checked")); + assertEquals("true", checkboxElement.attribute("value").getValue()); + } + + public void testWithSingleValueBooleanUnchecked() throws Exception { + this.bean.setJedi(false); + this.tag.setPath("jedi"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("jedi", checkboxElement.attribute("name").getValue()); + assertNull(checkboxElement.attribute("checked")); + assertEquals("true", checkboxElement.attribute("value").getValue()); + } + + public void testWithSingleValueNull() throws Exception { + this.bean.setName(null); + this.tag.setPath("name"); + this.tag.setValue("Rob Harrop"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("name", checkboxElement.attribute("name").getValue()); + assertNull(checkboxElement.attribute("checked")); + assertEquals("Rob Harrop", checkboxElement.attribute("value").getValue()); + } + + public void testWithSingleValueNotNull() throws Exception { + this.bean.setName("Rob Harrop"); + this.tag.setPath("name"); + this.tag.setValue("Rob Harrop"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("name", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals("Rob Harrop", checkboxElement.attribute("value").getValue()); + } + + public void testWithSingleValueAndEditor() throws Exception { + this.bean.setName("Rob Harrop"); + this.tag.setPath("name"); + this.tag.setValue(" Rob Harrop"); + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + bindingResult.getPropertyEditorRegistry().registerCustomEditor(String.class, new StringTrimmerEditor(false)); + getPageContext().getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, bindingResult); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("name", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals(" Rob Harrop", checkboxElement.attribute("value").getValue()); + } + + public void testWithMultiValueChecked() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setValue("foo"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals("foo", checkboxElement.attribute("value").getValue()); + } + + public void testWithMultiValueUnchecked() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setValue("abc"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement.attribute("name").getValue()); + assertNull(checkboxElement.attribute("checked")); + assertEquals("abc", checkboxElement.attribute("value").getValue()); + } + + public void testWithMultiValueWithEditor() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setValue(" foo"); + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + MyStringTrimmerEditor editor = new MyStringTrimmerEditor(); + bindingResult.getPropertyEditorRegistry().registerCustomEditor(String.class, editor); + getPageContext().getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, bindingResult); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + assertEquals(1, editor.count); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals(" foo", checkboxElement.attribute("value").getValue()); + } + + public void testWithMultiValueIntegerWithEditor() throws Exception { + this.tag.setPath("someIntegerArray"); + this.tag.setValue(" 1"); + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + MyIntegerEditor editor = new MyIntegerEditor(); + bindingResult.getPropertyEditorRegistry().registerCustomEditor(Integer.class, editor); + getPageContext().getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, bindingResult); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + assertEquals(1, editor.count); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("someIntegerArray", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals(" 1", checkboxElement.attribute("value").getValue()); + } + + public void testWithCollection() throws Exception { + this.tag.setPath("someList"); + this.tag.setValue("foo"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("someList", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals("foo", checkboxElement.attribute("value").getValue()); + } + + public void testWithObjectChecked() throws Exception { + this.tag.setPath("date"); + this.tag.setValue(getDate()); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("date", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals(getDate().toString(), checkboxElement.attribute("value").getValue()); + } + + public void testWithObjectUnchecked() throws Exception { + this.tag.setPath("date"); + Date date = new Date(); + this.tag.setValue(date); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("date", checkboxElement.attribute("name").getValue()); + assertNull(checkboxElement.attribute("checked")); + assertEquals(date.toString(), checkboxElement.attribute("value").getValue()); + } + + public void testCollectionOfColoursSelected() throws Exception { + this.tag.setPath("otherColours"); + this.tag.setValue("RED"); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("otherColours", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + } + + public void testCollectionOfColoursNotSelected() throws Exception { + this.tag.setPath("otherColours"); + this.tag.setValue("PURPLE"); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("otherColours", checkboxElement.attribute("name").getValue()); + assertNull(checkboxElement.attribute("checked")); + } + + public void testCollectionOfPetsAsString() throws Exception { + this.tag.setPath("pets"); + this.tag.setValue("Spot"); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("pets", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + } + + public void testCollectionOfPetsAsStringNotSelected() throws Exception { + this.tag.setPath("pets"); + this.tag.setValue("Santa's Little Helper"); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("pets", checkboxElement.attribute("name").getValue()); + assertNull(checkboxElement.attribute("checked")); + } + + public void testCollectionOfPets() throws Exception { + this.tag.setPath("pets"); + this.tag.setValue(new Pet("Rudiger")); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("pets", checkboxElement.attribute("name").getValue()); + assertEquals("Rudiger", checkboxElement.attribute("value").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + } + + public void testCollectionOfPetsNotSelected() throws Exception { + this.tag.setPath("pets"); + this.tag.setValue(new Pet("Santa's Little Helper")); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("pets", checkboxElement.attribute("name").getValue()); + assertEquals("Santa's Little Helper", checkboxElement.attribute("value").getValue()); + assertNull(checkboxElement.attribute("checked")); + } + + public void testCollectionOfPetsWithEditor() throws Exception { + this.tag.setPath("pets"); + this.tag.setValue(new ItemPet("Rudiger")); + + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + PropertyEditorSupport editor = new ItemPet.CustomEditor(); + bindingResult.getPropertyEditorRegistry().registerCustomEditor(ItemPet.class, editor); + getPageContext().getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, bindingResult); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element checkboxElement = (Element) document.getRootElement().elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("pets", checkboxElement.attribute("name").getValue()); + assertEquals("Rudiger", checkboxElement.attribute("value").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + } + + public void testWithNullValue() throws Exception { + try { + this.tag.setPath("name"); + this.tag.doStartTag(); + fail("Should not be able to render with a null value when binding to a non-boolean."); + } + catch (IllegalArgumentException e) { + // success + } + } + + public void testHiddenElementOmittedOnDisabled() throws Exception { + this.tag.setPath("someBoolean"); + this.tag.setDisabled("true"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element rootElement = document.getRootElement(); + assertEquals("Both tag and hidden element rendered incorrectly", 1, rootElement.elements().size()); + Element checkboxElement = (Element) rootElement.elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("someBoolean", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals("true", checkboxElement.attribute("value").getValue()); + } + private Date getDate() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, 10); + cal.set(Calendar.MONTH, 10); + cal.set(Calendar.DATE, 10); + cal.set(Calendar.HOUR, 10); + cal.set(Calendar.MINUTE, 10); + cal.set(Calendar.SECOND, 10); + return cal.getTime(); + } + + protected TestBean createTestBean() { + List colours = new ArrayList(); + colours.add(Colour.BLUE); + colours.add(Colour.RED); + colours.add(Colour.GREEN); + + List pets = new ArrayList(); + pets.add(new Pet("Rudiger")); + pets.add(new Pet("Spot")); + pets.add(new Pet("Fluffy")); + pets.add(new Pet("Mufty")); + + this.bean = new TestBean(); + this.bean.setDate(getDate()); + this.bean.setName("Rob Harrop"); + this.bean.setJedi(true); + this.bean.setSomeBoolean(new Boolean(true)); + this.bean.setStringArray(new String[] {"bar", "foo"}); + this.bean.setSomeIntegerArray(new Integer[] {new Integer(2), new Integer(1)}); + this.bean.setOtherColours(colours); + this.bean.setPets(pets); + List list = new ArrayList(); + list.add("foo"); + list.add("bar"); + this.bean.setSomeList(list); + return this.bean; + } + + + private class MyStringTrimmerEditor extends StringTrimmerEditor { + + public int count = 0; + + public MyStringTrimmerEditor() { + super(false); + } + + public void setAsText(String text) { + this.count++; + super.setAsText(text); + } + } + + + private class MyIntegerEditor extends PropertyEditorSupport { + + public int count = 0; + + public void setAsText(String text) { + this.count++; + setValue(new Integer(text.trim())); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxesTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxesTagTests.java new file mode 100644 index 00000000000..3bf0bcfce86 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/CheckboxesTagTests.java @@ -0,0 +1,671 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags.form; + +import java.beans.PropertyEditorSupport; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.jsp.tagext.Tag; + +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +import org.springframework.beans.Colour; +import org.springframework.beans.Pet; +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.BindingResult; + +/** + * @author Thomas Risberg + * @author Mark Fisher + * @author Juergen Hoeller + * @author Benjamin Hoffmann + */ +public class CheckboxesTagTests extends AbstractFormTagTests { + + private CheckboxesTag tag; + + private TestBean bean; + + protected void onSetUp() { + this.tag = new CheckboxesTag() { + protected TagWriter createTagWriter() { + return new TagWriter(getWriter()); + } + }; + this.tag.setPageContext(getPageContext()); + } + + public void testWithMultiValueArray() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setItems(new Object[] {"foo", "bar", "baz"}); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("foo", checkboxElement1.attribute("value").getValue()); + assertEquals("foo", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("bar", checkboxElement2.attribute("value").getValue()); + assertEquals("bar", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("baz", checkboxElement3.attribute("value").getValue()); + assertEquals("baz", spanElement3.getStringValue()); + } + + public void testWithMultiValueArrayWithDelimiter() throws Exception { + this.tag.setDelimiter("
"); + this.tag.setPath("stringArray"); + this.tag.setItems(new Object[] {"foo", "bar", "baz"}); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element delimiterElement1 = spanElement1.element("br"); + assertNull(delimiterElement1); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("foo", checkboxElement1.attribute("value").getValue()); + assertEquals("foo", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element delimiterElement2 = (Element) spanElement2.elements().get(0); + assertEquals("br", delimiterElement2.getName()); + Element checkboxElement2 = (Element) spanElement2.elements().get(1); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("bar", checkboxElement2.attribute("value").getValue()); + assertEquals("bar", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element delimiterElement3 = (Element) spanElement3.elements().get(0); + assertEquals("br", delimiterElement3.getName()); + Element checkboxElement3 = (Element) spanElement3.elements().get(1); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("baz", checkboxElement3.attribute("value").getValue()); + assertEquals("baz", spanElement3.getStringValue()); + } + + public void testWithMultiValueMap() throws Exception { + this.tag.setPath("stringArray"); + Map m = new LinkedHashMap(); + m.put("foo", "FOO"); + m.put("bar", "BAR"); + m.put("baz", "BAZ"); + this.tag.setItems(m); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("foo", checkboxElement1.attribute("value").getValue()); + assertEquals("FOO", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("bar", checkboxElement2.attribute("value").getValue()); + assertEquals("BAR", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("baz", checkboxElement3.attribute("value").getValue()); + assertEquals("BAZ", spanElement3.getStringValue()); + } + + public void testWithPetItemsMap() throws Exception { + this.tag.setPath("someSet"); + Map m = new LinkedHashMap(); + m.put(new ItemPet("PET1"), "PET1Label"); + m.put(new ItemPet("PET2"), "PET2Label"); + m.put(new ItemPet("PET3"), "PET3Label"); + this.tag.setItems(m); + tag.setItemValue("name"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("someSet", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("PET1", checkboxElement1.attribute("value").getValue()); + assertEquals("PET1Label", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("someSet", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("PET2", checkboxElement2.attribute("value").getValue()); + assertEquals("PET2Label", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("someSet", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("PET3", checkboxElement3.attribute("value").getValue()); + assertEquals("PET3Label", spanElement3.getStringValue()); + } + + public void testWithMultiValueMapWithDelimiter() throws Exception { + String delimiter = " | "; + this.tag.setDelimiter(delimiter); + this.tag.setPath("stringArray"); + Map m = new LinkedHashMap(); + m.put("foo", "FOO"); + m.put("bar", "BAR"); + m.put("baz", "BAZ"); + this.tag.setItems(m); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("foo", checkboxElement1.attribute("value").getValue()); + assertEquals("FOO", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("bar", checkboxElement2.attribute("value").getValue()); + assertEquals(delimiter + "BAR", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("baz", checkboxElement3.attribute("value").getValue()); + assertEquals(delimiter + "BAZ", spanElement3.getStringValue()); + } + + public void testWithMultiValueWithEditor() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setItems(new Object[] {" foo", " bar", " baz"}); + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + MyStringTrimmerEditor editor = new MyStringTrimmerEditor(); + bindingResult.getPropertyEditorRegistry().registerCustomEditor(String.class, editor); + getPageContext().getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, bindingResult); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + assertEquals(3, editor.allProcessedValues.size()); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals(" foo", checkboxElement1.attribute("value").getValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals(" bar", checkboxElement2.attribute("value").getValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals(" baz", checkboxElement3.attribute("value").getValue()); + } + + public void testWithMultiValueWithReverseEditor() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setItems(new Object[] {"FOO", "BAR", "BAZ"}); + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + MyLowerCaseEditor editor = new MyLowerCaseEditor(); + bindingResult.getPropertyEditorRegistry().registerCustomEditor(String.class, editor); + getPageContext().getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, bindingResult); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("FOO", checkboxElement1.attribute("value").getValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("BAR", checkboxElement2.attribute("value").getValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("BAZ", checkboxElement3.attribute("value").getValue()); + } + + public void testCollectionOfPets() throws Exception { + this.tag.setPath("pets"); + List allPets = new ArrayList(); + allPets.add(new ItemPet("Rudiger")); + allPets.add(new ItemPet("Spot")); + allPets.add(new ItemPet("Checkers")); + allPets.add(new ItemPet("Fluffy")); + allPets.add(new ItemPet("Mufty")); + this.tag.setItems(allPets); + this.tag.setItemValue("name"); + this.tag.setItemLabel("label"); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("pets", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("Rudiger", checkboxElement1.attribute("value").getValue()); + assertEquals("RUDIGER", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("pets", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("Spot", checkboxElement2.attribute("value").getValue()); + assertEquals("SPOT", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("pets", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("Checkers", checkboxElement3.attribute("value").getValue()); + assertEquals("CHECKERS", spanElement3.getStringValue()); + Element spanElement4 = (Element) document.getRootElement().elements().get(3); + Element checkboxElement4 = (Element) spanElement4.elements().get(0); + assertEquals("input", checkboxElement4.getName()); + assertEquals("checkbox", checkboxElement4.attribute("type").getValue()); + assertEquals("pets", checkboxElement4.attribute("name").getValue()); + assertEquals("checked", checkboxElement4.attribute("checked").getValue()); + assertEquals("Fluffy", checkboxElement4.attribute("value").getValue()); + assertEquals("FLUFFY", spanElement4.getStringValue()); + Element spanElement5 = (Element) document.getRootElement().elements().get(4); + Element checkboxElement5 = (Element) spanElement5.elements().get(0); + assertEquals("input", checkboxElement5.getName()); + assertEquals("checkbox", checkboxElement5.attribute("type").getValue()); + assertEquals("pets", checkboxElement5.attribute("name").getValue()); + assertEquals("checked", checkboxElement5.attribute("checked").getValue()); + assertEquals("Mufty", checkboxElement5.attribute("value").getValue()); + assertEquals("MUFTY", spanElement5.getStringValue()); + } + + /** + * Test case where items toString() doesn't fit the item ID + */ + public void testCollectionOfItemPets() throws Exception { + this.tag.setPath("someSet"); + List allPets = new ArrayList(); + allPets.add(new ItemPet("PET1")); + allPets.add(new ItemPet("PET2")); + allPets.add(new ItemPet("PET3")); + this.tag.setItems(allPets); + this.tag.setItemValue("name"); + this.tag.setItemLabel("label"); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("someSet", checkboxElement1.attribute("name").getValue()); + assertNotNull("should be checked", checkboxElement1.attribute("checked")); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("PET1", checkboxElement1.attribute("value").getValue()); + assertEquals("PET1", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("someSet", checkboxElement2.attribute("name").getValue()); + assertNotNull("should be checked", checkboxElement2.attribute("checked")); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("PET2", checkboxElement2.attribute("value").getValue()); + assertEquals("PET2", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("someSet", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("PET3", checkboxElement3.attribute("value").getValue()); + assertEquals("PET3", spanElement3.getStringValue()); + } + + public void testCollectionOfPetsWithEditor() throws Exception { + this.tag.setPath("pets"); + List allPets = new ArrayList(); + allPets.add(new ItemPet("Rudiger")); + allPets.add(new ItemPet("Spot")); + allPets.add(new ItemPet("Checkers")); + allPets.add(new ItemPet("Fluffy")); + allPets.add(new ItemPet("Mufty")); + this.tag.setItems(allPets); + this.tag.setItemLabel("label"); + this.tag.setId("myId"); + + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + PropertyEditorSupport editor = new ItemPet.CustomEditor(); + bindingResult.getPropertyEditorRegistry().registerCustomEditor(ItemPet.class, editor); + getPageContext().getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, bindingResult); + + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement1 = (Element) document.getRootElement().elements().get(0); + Element checkboxElement1 = (Element) spanElement1.elements().get(0); + assertEquals("input", checkboxElement1.getName()); + assertEquals("checkbox", checkboxElement1.attribute("type").getValue()); + assertEquals("pets", checkboxElement1.attribute("name").getValue()); + assertEquals("checked", checkboxElement1.attribute("checked").getValue()); + assertEquals("Rudiger", checkboxElement1.attribute("value").getValue()); + assertEquals("RUDIGER", spanElement1.getStringValue()); + Element spanElement2 = (Element) document.getRootElement().elements().get(1); + Element checkboxElement2 = (Element) spanElement2.elements().get(0); + assertEquals("input", checkboxElement2.getName()); + assertEquals("checkbox", checkboxElement2.attribute("type").getValue()); + assertEquals("pets", checkboxElement2.attribute("name").getValue()); + assertEquals("checked", checkboxElement2.attribute("checked").getValue()); + assertEquals("Spot", checkboxElement2.attribute("value").getValue()); + assertEquals("SPOT", spanElement2.getStringValue()); + Element spanElement3 = (Element) document.getRootElement().elements().get(2); + Element checkboxElement3 = (Element) spanElement3.elements().get(0); + assertEquals("input", checkboxElement3.getName()); + assertEquals("checkbox", checkboxElement3.attribute("type").getValue()); + assertEquals("pets", checkboxElement3.attribute("name").getValue()); + assertNull("not checked", checkboxElement3.attribute("checked")); + assertEquals("Checkers", checkboxElement3.attribute("value").getValue()); + assertEquals("CHECKERS", spanElement3.getStringValue()); + Element spanElement4 = (Element) document.getRootElement().elements().get(3); + Element checkboxElement4 = (Element) spanElement4.elements().get(0); + assertEquals("input", checkboxElement4.getName()); + assertEquals("checkbox", checkboxElement4.attribute("type").getValue()); + assertEquals("pets", checkboxElement4.attribute("name").getValue()); + assertEquals("checked", checkboxElement4.attribute("checked").getValue()); + assertEquals("Fluffy", checkboxElement4.attribute("value").getValue()); + assertEquals("FLUFFY", spanElement4.getStringValue()); + Element spanElement5 = (Element) document.getRootElement().elements().get(4); + Element checkboxElement5 = (Element) spanElement5.elements().get(0); + assertEquals("input", checkboxElement5.getName()); + assertEquals("checkbox", checkboxElement5.attribute("type").getValue()); + assertEquals("pets", checkboxElement5.attribute("name").getValue()); + assertEquals("checked", checkboxElement5.attribute("checked").getValue()); + assertEquals("Mufty", checkboxElement5.attribute("value").getValue()); + assertEquals("MUFTY", spanElement5.getStringValue()); + } + + public void testWithNullValue() throws Exception { + try { + this.tag.setPath("name"); + this.tag.doStartTag(); + fail("Should not be able to render with a null value when binding to a non-boolean."); + } + catch (IllegalArgumentException ex) { + // success + } + } + + public void testHiddenElementOmittedOnDisabled() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setItems(new Object[] {"foo", "bar", "baz"}); + this.tag.setDisabled("true"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element rootElement = document.getRootElement(); + assertEquals("Both tag and hidden element rendered incorrectly", 3, rootElement.elements().size()); + Element spanElement = (Element) document.getRootElement().elements().get(0); + Element checkboxElement = (Element) spanElement.elements().get(0); + assertEquals("input", checkboxElement.getName()); + assertEquals("checkbox", checkboxElement.attribute("type").getValue()); + assertEquals("stringArray", checkboxElement.attribute("name").getValue()); + assertEquals("checked", checkboxElement.attribute("checked").getValue()); + assertEquals("disabled", checkboxElement.attribute("disabled").getValue()); + assertEquals("foo", checkboxElement.attribute("value").getValue()); + } + + public void testSpanElementCustomizable() throws Exception { + this.tag.setPath("stringArray"); + this.tag.setItems(new Object[] {"foo", "bar", "baz"}); + this.tag.setElement("element"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + String output = getOutput(); + + // wrap the output so it is valid XML + output = "" + output + ""; + + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(output)); + Element spanElement = (Element) document.getRootElement().elements().get(0); + assertEquals("element", spanElement.getName()); + } + + private Date getDate() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, 10); + cal.set(Calendar.MONTH, 10); + cal.set(Calendar.DATE, 10); + cal.set(Calendar.HOUR, 10); + cal.set(Calendar.MINUTE, 10); + cal.set(Calendar.SECOND, 10); + return cal.getTime(); + } + + protected TestBean createTestBean() { + List colours = new ArrayList(); + colours.add(Colour.BLUE); + colours.add(Colour.RED); + colours.add(Colour.GREEN); + + List pets = new ArrayList(); + pets.add(new Pet("Rudiger")); + pets.add(new Pet("Spot")); + pets.add(new Pet("Fluffy")); + pets.add(new Pet("Mufty")); + + Set someObjects = new HashSet(); + someObjects.add(new ItemPet("PET1")); + someObjects.add(new ItemPet("PET2")); + + this.bean = new TestBean(); + this.bean.setDate(getDate()); + this.bean.setName("Rob Harrop"); + this.bean.setJedi(true); + this.bean.setSomeBoolean(new Boolean(true)); + this.bean.setStringArray(new String[] {"bar", "foo"}); + this.bean.setSomeIntegerArray(new Integer[] {new Integer(2), new Integer(1)}); + this.bean.setOtherColours(colours); + this.bean.setPets(pets); + this.bean.setSomeSet(someObjects); + List list = new ArrayList(); + list.add("foo"); + list.add("bar"); + this.bean.setSomeList(list); + return this.bean; + } + + + private static class MyStringTrimmerEditor extends StringTrimmerEditor { + + public final Set allProcessedValues = new HashSet(); + + public MyStringTrimmerEditor() { + super(false); + } + + public void setAsText(String text) { + super.setAsText(text); + this.allProcessedValues.add(getValue()); + } + } + + + private static class MyLowerCaseEditor extends PropertyEditorSupport { + + public void setAsText(String text) throws IllegalArgumentException { + setValue(text.toLowerCase()); + } + + public String getAsText() { + return ObjectUtils.nullSafeToString(getValue()).toUpperCase(); + } + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/Country.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/Country.java new file mode 100644 index 00000000000..4f1e72264fc --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/Country.java @@ -0,0 +1,86 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags.form; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Rob Harrop + * @author Sam Brannen + */ +public class Country { + + public static final Country COUNTRY_AT = new Country("AT", "Austria"); + + public static final Country COUNTRY_NL = new Country("NL", "Netherlands"); + + public static final Country COUNTRY_UK = new Country("UK", "United Kingdom"); + + public static final Country COUNTRY_US = new Country("US", "United States"); + + + private final String isoCode; + + private final String name; + + + public Country(String isoCode, String name) { + this.isoCode = isoCode; + this.name = name; + } + + + public String getIsoCode() { + return this.isoCode; + } + + public String getName() { + return this.name; + } + + + public String toString() { + return this.name + "(" + this.isoCode + ")"; + } + + public static Country getCountryWithIsoCode(final String isoCode) { + if (COUNTRY_AT.isoCode.equals(isoCode)) { + return COUNTRY_AT; + } + if (COUNTRY_NL.isoCode.equals(isoCode)) { + return COUNTRY_NL; + } + if (COUNTRY_UK.isoCode.equals(isoCode)) { + return COUNTRY_UK; + } + if (COUNTRY_US.isoCode.equals(isoCode)) { + return COUNTRY_US; + } + return null; + } + + public static List getCountries() { + List countries = new ArrayList(); + countries.add(COUNTRY_AT); + countries.add(COUNTRY_NL); + countries.add(COUNTRY_UK); + countries.add(COUNTRY_US); + return countries; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/ErrorsTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/ErrorsTagTests.java new file mode 100644 index 00000000000..9d2e5faafc6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/ErrorsTagTests.java @@ -0,0 +1,408 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags.form; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.tagext.BodyTag; +import javax.servlet.jsp.tagext.Tag; + +import org.springframework.beans.TestBean; +import org.springframework.mock.web.MockBodyContent; +import org.springframework.mock.web.MockPageContext; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.web.servlet.support.RequestContext; +import org.springframework.web.servlet.tags.RequestContextAwareTag; + +/** + * @author Rob Harrop + * @author Rick Evans + * @author Juergen Hoeller + * @author Mark Fisher + */ +public class ErrorsTagTests extends AbstractFormTagTests { + + private static final String COMMAND_NAME = "testBean"; + + private ErrorsTag tag; + + + protected void onSetUp() { + this.tag = new ErrorsTag() { + protected TagWriter createTagWriter() { + return new TagWriter(getWriter()); + } + }; + this.tag.setPath("name"); + this.tag.setParent(getFormTag()); + this.tag.setPageContext(getPageContext()); + } + + protected TestBean createTestBean() { + return new TestBean(); + } + + + public void testWithExplicitNonWhitespaceBodyContent() throws Exception { + String mockContent = "This is some explicit body content"; + this.tag.setBodyContent(new MockBodyContent(mockContent, getWriter())); + + // construct an errors instance of the tag + TestBean target = new TestBean(); + target.setName("Rob Harrop"); + Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); + errors.rejectValue("name", "some.code", "Default Message"); + + exposeBindingResult(errors); + + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + assertEquals(mockContent, getOutput()); + } + + public void testWithExplicitWhitespaceBodyContent() throws Exception { + this.tag.setBodyContent(new MockBodyContent("\t\n ", getWriter())); + + // construct an errors instance of the tag + TestBean target = new TestBean(); + target.setName("Rob Harrop"); + Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); + errors.rejectValue("name", "some.code", "Default Message"); + + exposeBindingResult(errors); + + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertElementTagOpened(output); + assertElementTagClosed(output); + + assertContainsAttribute(output, "id", "name.errors"); + assertBlockTagContains(output, "Default Message"); + } + + public void testWithExplicitEmptyWhitespaceBodyContent() throws Exception { + this.tag.setBodyContent(new MockBodyContent("", getWriter())); + + // construct an errors instance of the tag + TestBean target = new TestBean(); + target.setName("Rob Harrop"); + Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); + errors.rejectValue("name", "some.code", "Default Message"); + + exposeBindingResult(errors); + + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertElementTagOpened(output); + assertElementTagClosed(output); + + assertContainsAttribute(output, "id", "name.errors"); + assertBlockTagContains(output, "Default Message"); + } + + public void testWithErrors() throws Exception { + // construct an errors instance of the tag + TestBean target = new TestBean(); + target.setName("Rob Harrop"); + Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); + errors.rejectValue("name", "some.code", "Default Message"); + errors.rejectValue("name", "too.short", "Too Short"); + + exposeBindingResult(errors); + + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertElementTagOpened(output); + assertElementTagClosed(output); + + assertContainsAttribute(output, "id", "name.errors"); + assertBlockTagContains(output, "
"); + assertBlockTagContains(output, "Default Message"); + assertBlockTagContains(output, "Too Short"); + } + + public void testWithEscapedErrors() throws Exception { + // construct an errors instance of the tag + TestBean target = new TestBean(); + target.setName("Rob Harrop"); + Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); + errors.rejectValue("name", "some.code", "Default <> Message"); + errors.rejectValue("name", "too.short", "Too & Short"); + + exposeBindingResult(errors); + + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertElementTagOpened(output); + assertElementTagClosed(output); + + assertContainsAttribute(output, "id", "name.errors"); + assertBlockTagContains(output, "
"); + assertBlockTagContains(output, "Default <> Message"); + assertBlockTagContains(output, "Too & Short"); + } + + public void testWithNonEscapedErrors() throws Exception { + this.tag.setHtmlEscape("false"); + + // construct an errors instance of the tag + TestBean target = new TestBean(); + target.setName("Rob Harrop"); + Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); + errors.rejectValue("name", "some.code", "Default <> Message"); + errors.rejectValue("name", "too.short", "Too & Short"); + + exposeBindingResult(errors); + + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertElementTagOpened(output); + assertElementTagClosed(output); + + assertContainsAttribute(output, "id", "name.errors"); + assertBlockTagContains(output, "
"); + assertBlockTagContains(output, "Default <> Message"); + assertBlockTagContains(output, "Too & Short"); + } + + public void testWithErrorsAndCustomElement() throws Exception { + // construct an errors instance of the tag + TestBean target = new TestBean(); + target.setName("Rob Harrop"); + Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); + errors.rejectValue("name", "some.code", "Default Message"); + errors.rejectValue("name", "too.short", "Too Short"); + + exposeBindingResult(errors); + + this.tag.setElement("div"); + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertElementTagOpened(output); + assertElementTagClosed(output); + + assertContainsAttribute(output, "id", "name.errors"); + assertBlockTagContains(output, "
"); + assertBlockTagContains(output, "Default Message"); + assertBlockTagContains(output, "Too Short"); + } + + public void testWithoutErrors() throws Exception { + Errors errors = new BeanPropertyBindingResult(new TestBean(), "COMMAND_NAME"); + exposeBindingResult(errors); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertEquals(0, output.length()); + } + + public void testWithoutErrorsInstance() throws Exception { + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertEquals(0, output.length()); + } + + public void testAsBodyTag() throws Exception { + Errors errors = new BeanPropertyBindingResult(new TestBean(), "COMMAND_NAME"); + errors.rejectValue("name", "some.code", "Default Message"); + errors.rejectValue("name", "too.short", "Too Short"); + exposeBindingResult(errors); + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + assertNotNull(getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE)); + String bodyContent = "Foo"; + this.tag.setBodyContent(new MockBodyContent(bodyContent, getWriter())); + this.tag.doEndTag(); + this.tag.doFinally(); + assertEquals(bodyContent, getOutput()); + assertNull(getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE)); + } + + public void testAsBodyTagWithExistingMessagesAttribute() throws Exception { + String existingAttribute = "something"; + getPageContext().setAttribute(ErrorsTag.MESSAGES_ATTRIBUTE, existingAttribute); + Errors errors = new BeanPropertyBindingResult(new TestBean(), "COMMAND_NAME"); + errors.rejectValue("name", "some.code", "Default Message"); + errors.rejectValue("name", "too.short", "Too Short"); + exposeBindingResult(errors); + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + assertNotNull(getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE)); + assertTrue(getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE) instanceof List); + String bodyContent = "Foo"; + this.tag.setBodyContent(new MockBodyContent(bodyContent, getWriter())); + this.tag.doEndTag(); + this.tag.doFinally(); + assertEquals(bodyContent, getOutput()); + assertEquals(existingAttribute, getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE)); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2788 + */ + public void testAsBodyTagWithErrorsAndExistingMessagesAttributeInNonPageScopeAreNotClobbered() throws Exception { + String existingAttribute = "something"; + getPageContext().setAttribute(ErrorsTag.MESSAGES_ATTRIBUTE, existingAttribute, PageContext.APPLICATION_SCOPE); + Errors errors = new BeanPropertyBindingResult(new TestBean(), "COMMAND_NAME"); + errors.rejectValue("name", "some.code", "Default Message"); + errors.rejectValue("name", "too.short", "Too Short"); + exposeBindingResult(errors); + int result = this.tag.doStartTag(); + assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); + assertNotNull(getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE)); + assertTrue(getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE) instanceof List); + String bodyContent = "Foo"; + this.tag.setBodyContent(new MockBodyContent(bodyContent, getWriter())); + this.tag.doEndTag(); + this.tag.doFinally(); + assertEquals(bodyContent, getOutput()); + assertEquals(existingAttribute, + getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE, PageContext.APPLICATION_SCOPE)); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2788 + */ + public void testAsBodyTagWithNoErrorsAndExistingMessagesAttributeInApplicationScopeAreNotClobbered() throws Exception { + assertWhenNoErrorsExistingMessagesInScopeAreNotClobbered(PageContext.APPLICATION_SCOPE); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2788 + */ + public void testAsBodyTagWithNoErrorsAndExistingMessagesAttributeInSessionScopeAreNotClobbered() throws Exception { + assertWhenNoErrorsExistingMessagesInScopeAreNotClobbered(PageContext.SESSION_SCOPE); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2788 + */ + public void testAsBodyTagWithNoErrorsAndExistingMessagesAttributeInPageScopeAreNotClobbered() throws Exception { + assertWhenNoErrorsExistingMessagesInScopeAreNotClobbered(PageContext.PAGE_SCOPE); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-2788 + */ + public void testAsBodyTagWithNoErrorsAndExistingMessagesAttributeInRequestScopeAreNotClobbered() throws Exception { + assertWhenNoErrorsExistingMessagesInScopeAreNotClobbered(PageContext.REQUEST_SCOPE); + } + + /** + * http://opensource.atlassian.com/projects/spring/browse/SPR-4005 + */ + public void testOmittedPathMatchesObjectErrorsOnly() throws Exception { + this.tag.setPath(null); + Errors errors = new BeanPropertyBindingResult(new TestBean(), "COMMAND_NAME"); + errors.reject("some.code", "object error"); + errors.rejectValue("name", "some.code", "field error"); + exposeBindingResult(errors); + this.tag.doStartTag(); + assertNotNull(getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE)); + this.tag.doEndTag(); + String output = getOutput(); + assertBlockTagContains(output, "object error"); + assertFalse(output.indexOf("field error") != -1); + } + + protected void exposeBindingResult(Errors errors) { + // wrap errors in a Model + Map model = new HashMap(); + model.put(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, errors); + + // replace the request context with one containing the errors + MockPageContext pageContext = getPageContext(); + RequestContext context = new RequestContext((HttpServletRequest) pageContext.getRequest(), model); + pageContext.setAttribute(RequestContextAwareTag.REQUEST_CONTEXT_PAGE_ATTRIBUTE, context); + } + + private void assertElementTagOpened(String output) { + assertTrue(output.startsWith("<" + this.tag.getElement() + " ")); + } + + private void assertElementTagClosed(String output) { + assertTrue(output.endsWith("")); + } + + private void assertWhenNoErrorsExistingMessagesInScopeAreNotClobbered(int scope) throws JspException { + String existingAttribute = "something"; + getPageContext().setAttribute(ErrorsTag.MESSAGES_ATTRIBUTE, existingAttribute, scope); + + Errors errors = new BeanPropertyBindingResult(new TestBean(), "COMMAND_NAME"); + exposeBindingResult(errors); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + String output = getOutput(); + assertEquals(0, output.length()); + + assertEquals(existingAttribute, getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE, scope)); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java new file mode 100644 index 00000000000..24b22bc25ef --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java @@ -0,0 +1,182 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags.form; + +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.tagext.Tag; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.AssertThrows; + +/** + * @author Rob Harrop + * @author Rick Evans + * @author Juergen Hoeller + */ +public class FormTagTests extends AbstractHtmlElementTagTests { + + private static final String REQUEST_URI = "/my/form"; + + private static final String QUERY_STRING = "foo=bar"; + + + private FormTag tag; + + private MockHttpServletRequest request; + + + protected void onSetUp() { + this.tag = new FormTag() { + protected TagWriter createTagWriter() { + return new TagWriter(getWriter()); + } + }; + this.tag.setPageContext(getPageContext()); + } + + protected void extendRequest(MockHttpServletRequest request) { + request.setRequestURI(REQUEST_URI); + request.setQueryString(QUERY_STRING); + this.request = request; + } + + + public void testWriteForm() throws Exception { + String commandName = "myCommand"; + String name = "formName"; + String action = "/form.html"; + String method = "POST"; + String target = "myTarget"; + String enctype = "my/enctype"; + String acceptCharset = "iso-8859-1"; + String onsubmit = "onsubmit"; + String onreset = "onreset"; + String autocomplete = "off"; + String cssClass = "myClass"; + String cssStyle = "myStyle"; + + this.tag.setName(name); + this.tag.setCssClass(cssClass); + this.tag.setCssStyle(cssStyle); + this.tag.setCommandName(commandName); + this.tag.setAction(action); + this.tag.setMethod(method); + this.tag.setTarget(target); + this.tag.setEnctype(enctype); + this.tag.setAcceptCharset(acceptCharset); + this.tag.setOnsubmit(onsubmit); + this.tag.setOnreset(onreset); + this.tag.setAutocomplete(autocomplete); + + int result = this.tag.doStartTag(); + assertEquals(Tag.EVAL_BODY_INCLUDE, result); + assertEquals("Form attribute not exposed", commandName, + getPageContext().getRequest().getAttribute(FormTag.MODEL_ATTRIBUTE_VARIABLE_NAME)); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + this.tag.doFinally(); + assertNull("Form attribute not cleared after tag ends", + getPageContext().getRequest().getAttribute(FormTag.MODEL_ATTRIBUTE_VARIABLE_NAME)); + + String output = getOutput(); + assertFormTagOpened(output); + assertFormTagClosed(output); + + assertContainsAttribute(output, "class", cssClass); + assertContainsAttribute(output, "style", cssStyle); + assertContainsAttribute(output, "action", action); + assertContainsAttribute(output, "method", method); + assertContainsAttribute(output, "target", target); + assertContainsAttribute(output, "enctype", enctype); + assertContainsAttribute(output, "accept-charset", acceptCharset); + assertContainsAttribute(output, "onsubmit", onsubmit); + assertContainsAttribute(output, "onreset", onreset); + assertContainsAttribute(output, "autocomplete", autocomplete); + assertContainsAttribute(output, "id", commandName); + assertContainsAttribute(output, "name", name); + } + + public void testWithActionFromRequest() throws Exception { + String commandName = "myCommand"; + String enctype = "my/enctype"; + String method = "POST"; + String onsubmit = "onsubmit"; + String onreset = "onreset"; + + this.tag.setCommandName(commandName); + this.tag.setMethod(method); + this.tag.setEnctype(enctype); + this.tag.setOnsubmit(onsubmit); + this.tag.setOnreset(onreset); + + int result = this.tag.doStartTag(); + assertEquals(Tag.EVAL_BODY_INCLUDE, result); + assertEquals("Form attribute not exposed", commandName, + getPageContext().getAttribute(FormTag.MODEL_ATTRIBUTE_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + + result = this.tag.doEndTag(); + assertEquals(Tag.EVAL_PAGE, result); + + this.tag.doFinally(); + assertNull("Form attribute not cleared after tag ends", + getPageContext().getAttribute(FormTag.MODEL_ATTRIBUTE_VARIABLE_NAME, PageContext.REQUEST_SCOPE)); + + String output = getOutput(); + assertFormTagOpened(output); + assertFormTagClosed(output); + + assertContainsAttribute(output, "action", REQUEST_URI + "?" + QUERY_STRING); + assertContainsAttribute(output, "method", method); + assertContainsAttribute(output, "enctype", enctype); + assertContainsAttribute(output, "onsubmit", onsubmit); + assertContainsAttribute(output, "onreset", onreset); + assertAttributeNotPresent(output, "name"); + } + + public void testWithNullResolvedCommand() throws Exception { + new AssertThrows(IllegalArgumentException.class, + "Must not be able to have a command name that resolves to null") { + public void test() throws Exception { + tag.setCommandName("${null}"); + tag.doStartTag(); + } + }.runTest(); + } + + /* + * See http://opensource.atlassian.com/projects/spring/browse/SPR-2645 + */ + public void testXSSScriptingExploitWhenActionIsResolvedFromQueryString() throws Exception { + String xssQueryString = QUERY_STRING + "&stuff=\">"; + request.setQueryString(xssQueryString); + tag.doStartTag(); + assertEquals("

", + getOutput()); + } + + + private static void assertFormTagOpened(String output) { + assertTrue(output.startsWith("")); + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/HiddenInputTagTests.java b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/HiddenInputTagTests.java new file mode 100644 index 00000000000..133ebecbf4f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/web/servlet/tags/form/HiddenInputTagTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.tags.form; + +import org.springframework.beans.TestBean; +import org.springframework.validation.BeanPropertyBindingResult; + +import javax.servlet.jsp.tagext.Tag; + +/** + * @author Rob Harrop + */ +public class HiddenInputTagTests extends AbstractFormTagTests { + + private HiddenInputTag tag; + + private TestBean bean; + + protected void onSetUp() { + this.tag = new HiddenInputTag() { + protected TagWriter createTagWriter() { + return new TagWriter(getWriter()); + } + }; + this.tag.setPageContext(getPageContext()); + } + + public void testRender() throws Exception { + this.tag.setPath("name"); + int result = this.tag.doStartTag(); + assertEquals(Tag.SKIP_BODY, result); + + String output = getOutput(); + + assertTagOpened(output); + assertTagClosed(output); + + assertContainsAttribute(output, "type", "hidden"); + assertContainsAttribute(output, "value", "Sally Greenwood"); + } + + public void testWithCustomBinder() throws Exception { + this.tag.setPath("myFloat"); + + BeanPropertyBindingResult errors = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); + errors.getPropertyAccessor().registerCustomEditor(Float.class, new SimpleFloatEditor()); + exposeBindingResult(errors); + + assertEquals(Tag.SKIP_BODY, this.tag.doStartTag()); + + String output = getOutput(); + + assertTagOpened(output); + assertTagClosed(output); + + assertContainsAttribute(output, "type", "hidden"); + assertContainsAttribute(output, "value", "12.34f"); + } + + private void assertTagClosed(String output) { + assertTrue(output.endsWith("/>")); + } + + private void assertTagOpened(String output) { + assertTrue(output.startsWith("")); + } + + protected final void assertTagOpened(String output) { + assertTrue("Tag not opened properly", output.startsWith(" + assertAttributeNotPresent(output, "name"); + // id attribute is supported, but we don't want it + assertAttributeNotPresent(output, "id"); + assertTrue(output.startsWith("