View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.common.test.spring;
17  
18  import java.io.BufferedReader;
19  import java.io.File;
20  import java.io.FileNotFoundException;
21  import java.io.FileReader;
22  import java.io.IOException;
23  import java.lang.reflect.Field;
24  import java.util.List;
25  
26  import javax.persistence.EntityManager;
27  import javax.persistence.PersistenceContext;
28  
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.log4j.Logger;
31  import org.junit.Before;
32  import org.junit.runner.RunWith;
33  import org.springframework.beans.factory.annotation.Autowired;
34  import org.springframework.context.ApplicationContext;
35  import org.springframework.context.support.FileSystemXmlApplicationContext;
36  import org.springframework.core.io.ClassPathResource;
37  import org.springframework.test.context.ContextConfiguration;
38  import org.springframework.test.context.TestExecutionListeners;
39  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
40  import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
41  import org.springframework.test.context.transaction.BeforeTransaction;
42  import org.springframework.test.context.transaction.TransactionConfiguration;
43  import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
44  import org.springframework.transaction.TransactionDefinition;
45  import org.springframework.transaction.TransactionStatus;
46  import org.springframework.transaction.annotation.Transactional;
47  import org.springframework.transaction.jta.JtaTransactionManager;
48  import org.springframework.transaction.support.DefaultTransactionDefinition;
49  
50  /**
51   * This test class will load your dao and gives you access to the shared
52   * entityManager em. Also passes the @Dao and @PersistenceFileLocation
53   * to system properties from the annotations.
54   * <p>
55   * Extend this class and set the
56   * <ul>
57   * <li>&#064;PersistenceFileLocation
58   * <li>&#064;Dao
59   * </ul>
60   * <p>
61   * &#064;PersistenceFileLocation defines the persistence.xml location if it is
62   * named something else.
63   * <p>
64   * &#064;Dao defines the Dao implementation class, and an optional application
65   * context that contains a list of beans that should be persisted. The list bean
66   * should be called "persistList". SQL files that should be loaded can also be defined here with the
67   * testSqlFile parameter.  This should be an SQL file.
68   * <p>
69   * This test class is &#064;Transactional, so all tests will be rolled back.
70   * That means the data you load will be in the same state for each test.
71   * <p>
72   * Example:
73   * 
74   * <pre>
75   * &#064;PersistenceFileLocation(&quot;classpath:META-INF/custom-persistence.xml&quot;)
76   * public class DaoCommonTest extends AbstractTransactionalDaoTest {
77   * 
78   * &#064;Dao(value = &quot;org.kuali.student.MyDaoImpl&quot;, 
79   *      testDataFile = &quot;classpath:META-INF/pretest-data-beans-1.xml,pretest-data-beans-2.xml&quot;)
80   * public MyDao myDao;
81   * 
82   * &#064;Test
83   * public void test1() {
84   *	MyObject a = myDao.foo();
85   *	MyObject b = em.find(MyObject.class,1);
86   *	assertEquals(a.id,b.id);
87   * }
88   * }
89   * </pre>
90   * 
91   * Example of application context for preloading data:
92   * 
93   * <pre>
94   * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
95   * &lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
96   *  xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
97   *  xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&quot;&gt;
98   *  
99   *  &lt;bean id=&quot;persistList&quot;
100  *  class=&quot;org.springframework.beans.factory.config.ListFactoryBean&quot;&gt;
101  *	&lt;property name=&quot;sourceList&quot;&gt;
102  *		&lt;list&gt;
103  *			&lt;ref bean=&quot;value1&quot; /&gt;
104  *			&lt;ref bean=&quot;value2&quot; /&gt;
105  *		&lt;/list&gt;
106  *	&lt;/property&gt;
107  *  &lt;/bean&gt;
108  *  
109  *  &lt;bean id=&quot;value1&quot;
110  *  class=&quot;org.kuali.student.Value&quot;&gt;
111  *	&lt;property name=&quot;value&quot; value=&quot;Value Number One&quot; /&gt;
112  *  &lt;/bean&gt;
113  *  
114  *  &lt;bean id=&quot;value2&quot;
115  *  class=&quot;org.kuali.student.Value&quot;&gt;
116  *	&lt;property name=&quot;value&quot; value=&quot;Value Number Two&quot; /&gt;
117  *  &lt;/bean&gt;
118  * 
119  * &lt;/beans&gt;
120  * </pre>
121  */
122 @RunWith(SpringJUnit4ClassRunner.class)
123 @ContextConfiguration(locations = { "classpath:META-INF/default-dao-context-test.xml" })
124 @TestExecutionListeners( { TransactionalTestExecutionListener.class,
125 		DaoTestDependencyInjectorListener.class,
126 		DirtiesContextTestExecutionListener.class })
127 @Transactional
128 @TransactionConfiguration(transactionManager = "JtaTxManager")
129 public abstract class AbstractTransactionalDaoTest {
130 	final Logger LOG = Logger.getLogger(AbstractTransactionalDaoTest.class);
131 	@PersistenceContext
132 	protected EntityManager em;
133 
134 	@Autowired
135 	private JtaTransactionManager jtaTxManager;	
136 	
137 	
138 	private static boolean preloadedData=false;
139 	/**
140 	 * Loads the application context defined in the &#064;Dao testDataFile
141 	 * attribute. Then uses the EntityManager em to persist the beans in
142 	 * persistList
143 	 */
144 	@Before
145 	public void preLoadBeans() {
146 		for (Field f : this.getClass().getDeclaredFields()) {
147 			if (f.isAnnotationPresent(Dao.class)) {
148 				Dao dao = f.getAnnotation(Dao.class);
149 				if (dao.testDataFile().length() > 0) {
150 					ApplicationContext ac = new FileSystemXmlApplicationContext(
151 							dao.testDataFile());
152 					for (Object o : (List<?>) ac.getBean("persistList")) {
153 						em.persist(o);
154 					}
155 					em.flush();
156 				}
157 			}
158 		}
159 	}
160 	
161 	@BeforeTransaction
162 	public void preLoadData() throws IOException  {
163 		if(!preloadedData){
164 			preloadedData=true;
165 			
166 			for (Field f : this.getClass().getDeclaredFields()) {
167 				if (f.isAnnotationPresent(Dao.class)) {
168 					Dao dao = f.getAnnotation(Dao.class);
169 					if (dao.testSqlFile().length() > 0) {
170 						if (dao.testSqlFile().startsWith("classpath:")) {
171 							String file = dao.testSqlFile().substring("classpath:".length());
172 							String[] files = file.split("\\s*,\\s*");
173 							for(String testFile : files) {
174 								File sqlFile = new ClassPathResource(testFile).getFile();
175 								process(sqlFile);
176 							}
177 						} else {
178 							String[] files = dao.testSqlFile().split("\\s*,\\s*");
179 							for(String testFile : files) {
180 								File sqlFile = new File(testFile);
181 								process(sqlFile);
182 							}
183 						}
184 					}
185 				}
186 			}
187 		}
188 	}
189 
190 	private void process(File sqlFile) throws FileNotFoundException {
191 		BufferedReader in
192 		   = new BufferedReader(new FileReader(sqlFile));
193 		String ln;
194 		
195 		//Check if oracle
196 		TransactionDefinition txDefinition = new DefaultTransactionDefinition() ;
197 		TransactionStatus txStatus = jtaTxManager.getTransaction(txDefinition);
198 	
199 		try {
200 		
201 			while((ln=in.readLine())!=null){
202 				if(!ln.startsWith("/")&&!ln.startsWith("--")&&StringUtils.isNotBlank(ln)){
203 					ln=ln.replaceFirst("[;/]\\s*$","");
204 					em.createNativeQuery(ln).executeUpdate();
205 				}
206 			}
207 			jtaTxManager.commit(txStatus);
208 		} catch (Exception e) {
209 			LOG.error(e);
210 			jtaTxManager.rollback(txStatus);
211 		}
212 		finally{
213 			try {
214 				in.close();
215 			} catch (IOException e) {
216 				LOG.error("IO Stream closed " + e);
217 			}
218 		}
219 	}
220 	
221 	/**
222 	 * Passes some variables so they can be used in the application context
223 	 */
224 	public AbstractTransactionalDaoTest() {
225 		super();
226 		// Grab annotations and pass them as System properties
227 		if (this.getClass().isAnnotationPresent(PersistenceFileLocation.class)) {
228 			PersistenceFileLocation a = this.getClass().getAnnotation(
229 					PersistenceFileLocation.class);
230 			System.setProperty("ks.test.persistenceLocation", a.value());
231 		} else {
232 			System.setProperty("ks.test.persistenceLocation",
233 					"classpath:META-INF/persistence.xml");
234 		}
235 	}
236 }