/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.dao.jdbc.aop; import com.liferay.portal.kernel.dao.jdbc.aop.DynamicDataSourceTargetSource; import com.liferay.portal.kernel.dao.jdbc.aop.MasterDataSource; import com.liferay.portal.kernel.dao.jdbc.aop.Operation; import com.liferay.portal.kernel.test.ReflectionTestUtil; import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor; import com.liferay.portal.kernel.transaction.Transactional; import com.liferay.portal.kernel.util.ProxyUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.spring.aop.AnnotationChainableMethodAdvice; import com.liferay.portal.spring.aop.ServiceBeanAopCacheManager; import com.liferay.portal.spring.aop.ServiceBeanMethodInvocation; import com.liferay.portal.spring.transaction.AnnotationTransactionAttributeSource; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Map; import java.util.Stack; import javax.sql.DataSource; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.junit.Assert; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; /** * @author Shuyang Zhou */ public class DynamicDataSourceAdviceTest { @ClassRule public static final CodeCoverageAssertor codeCoverageAssertor = CodeCoverageAssertor.INSTANCE; @Before public void setUp() { _dynamicDataSourceAdvice = new DynamicDataSourceAdvice(); _dynamicDataSourceTargetSource = new DefaultDynamicDataSourceTargetSource(); ClassLoader classLoader = DynamicDataSourceAdviceTest.class.getClassLoader(); InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { throw new UnsupportedOperationException(); } }; _readDataSource = (DataSource)ProxyUtil.newProxyInstance( classLoader, new Class<?>[] {DataSource.class}, invocationHandler); _dynamicDataSourceTargetSource.setReadDataSource(_readDataSource); _writeDataSource = (DataSource)ProxyUtil.newProxyInstance( classLoader, new Class<?>[] {DataSource.class}, invocationHandler); _dynamicDataSourceTargetSource.setWriteDataSource(_writeDataSource); _dynamicDataSourceAdvice.setDynamicDataSourceTargetSource( _dynamicDataSourceTargetSource); ServiceBeanAopCacheManager serviceBeanAopCacheManager = new ServiceBeanAopCacheManager(); _dynamicDataSourceAdvice.setServiceBeanAopCacheManager( serviceBeanAopCacheManager); _dynamicDataSourceAdvice.setServiceBeanAopCacheManager( serviceBeanAopCacheManager); Map<Class<? extends Annotation>, AnnotationChainableMethodAdvice<?>[]> registeredAnnotationChainableMethodAdvices = serviceBeanAopCacheManager. getRegisteredAnnotationChainableMethodAdvices(); AnnotationChainableMethodAdvice<?>[] annotationChainableMethodAdvices = registeredAnnotationChainableMethodAdvices.get( MasterDataSource.class); Assert.assertEquals( Arrays.toString(annotationChainableMethodAdvices), 1, annotationChainableMethodAdvices.length); Assert.assertNull(annotationChainableMethodAdvices[0]); Assert.assertSame( annotationChainableMethodAdvices, registeredAnnotationChainableMethodAdvices.get( MasterDataSource.class)); _dynamicDataSourceAdvice.setTransactionAttributeSource( new AnnotationTransactionAttributeSource()); } @Test public void testAnnotationType() { MasterDataSource masterDataSource = ReflectionTestUtil.getFieldValue( DynamicDataSourceAdvice.class, "_nullMasterDataSource"); Assert.assertSame( MasterDataSource.class, masterDataSource.annotationType()); } @Test public void testDynamicDataSourceAdvice() throws Throwable { TestClass testClass = new TestClass(); for (int i = 1; i <= 5; i++) { MethodInvocation methodInvocation = createMethodInvocation( testClass, "method" + i); methodInvocation.proceed(); } testClass.assertExecutions(); } protected MethodInvocation createMethodInvocation( TestClass testClass, String methodName) throws Exception { Method method = TestClass.class.getMethod(methodName); ServiceBeanMethodInvocation serviceBeanMethodInvocation = new ServiceBeanMethodInvocation(testClass, method, new Object[0]); MasterDataSource masterDataSource = method.getAnnotation( MasterDataSource.class); Annotation[] annotations = null; if (masterDataSource == null) { annotations = new Annotation[0]; } else { annotations = new Annotation[] {masterDataSource}; } ServiceBeanAopCacheManager.putAnnotations( serviceBeanMethodInvocation, annotations); serviceBeanMethodInvocation.setMethodInterceptors( Arrays.<MethodInterceptor>asList(_dynamicDataSourceAdvice)); return serviceBeanMethodInvocation; } private DynamicDataSourceAdvice _dynamicDataSourceAdvice; private DynamicDataSourceTargetSource _dynamicDataSourceTargetSource; private DataSource _readDataSource; private DataSource _writeDataSource; private class TestClass { public void assertExecutions() { Assert.assertTrue(_testMethod1); Assert.assertTrue(_testMethod2); Assert.assertTrue(_testMethod3); Assert.assertTrue(_testMethod4); Assert.assertTrue(_testMethod5); } @SuppressWarnings("unused") public void method1() throws Exception { Assert.assertEquals( Operation.WRITE, _dynamicDataSourceTargetSource.getOperation()); Assert.assertSame( _writeDataSource, _dynamicDataSourceTargetSource.getTarget()); Assert.assertEquals( TestClass.class.getName() + StringPool.PERIOD + "method1", _getCurrentMethod()); _testMethod1 = true; } @Transactional public void method2() throws Exception { Assert.assertEquals( Operation.WRITE, _dynamicDataSourceTargetSource.getOperation()); Assert.assertSame( _writeDataSource, _dynamicDataSourceTargetSource.getTarget()); Assert.assertEquals( TestClass.class.getName() + StringPool.PERIOD + "method2", _getCurrentMethod()); _testMethod2 = true; } @Transactional(readOnly = true) public void method3() throws Exception { Assert.assertEquals( Operation.READ, _dynamicDataSourceTargetSource.getOperation()); Assert.assertSame( _readDataSource, _dynamicDataSourceTargetSource.getTarget()); Assert.assertEquals( TestClass.class.getName() + StringPool.PERIOD + "method3", _getCurrentMethod()); _testMethod3 = true; } @MasterDataSource @Transactional public void method4() throws Exception { Assert.assertEquals( Operation.WRITE, _dynamicDataSourceTargetSource.getOperation()); Assert.assertSame( _writeDataSource, _dynamicDataSourceTargetSource.getTarget()); Assert.assertEquals( TestClass.class.getName() + StringPool.PERIOD + "method4", _getCurrentMethod()); _testMethod4 = true; } @MasterDataSource @Transactional(readOnly = true) public void method5() throws Exception { Assert.assertEquals( Operation.WRITE, _dynamicDataSourceTargetSource.getOperation()); Assert.assertSame( _writeDataSource, _dynamicDataSourceTargetSource.getTarget()); Assert.assertEquals( TestClass.class.getName() + StringPool.PERIOD + "method5", _getCurrentMethod()); _testMethod5 = true; } private String _getCurrentMethod() { Stack<String> stack = _dynamicDataSourceTargetSource.getMethodStack(); return stack.peek(); } private boolean _testMethod1; private boolean _testMethod2; private boolean _testMethod3; private boolean _testMethod4; private boolean _testMethod5; } }