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 org.apache.commons.lang.StringUtils;
19  import org.apache.log4j.Logger;
20  import org.junit.Before;
21  import org.junit.runner.RunWith;
22  import org.springframework.beans.factory.annotation.Autowired;
23  import org.springframework.context.ApplicationContext;
24  import org.springframework.context.support.FileSystemXmlApplicationContext;
25  import org.springframework.core.io.ClassPathResource;
26  import org.springframework.test.context.ContextConfiguration;
27  import org.springframework.test.context.TestExecutionListeners;
28  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
29  import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
30  import org.springframework.test.context.transaction.BeforeTransaction;
31  import org.springframework.test.context.transaction.TransactionConfiguration;
32  import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
33  import org.springframework.transaction.TransactionDefinition;
34  import org.springframework.transaction.TransactionStatus;
35  import org.springframework.transaction.annotation.Transactional;
36  import org.springframework.transaction.jta.JtaTransactionManager;
37  import org.springframework.transaction.support.DefaultTransactionDefinition;
38  
39  import javax.persistence.EntityManager;
40  import javax.persistence.PersistenceContext;
41  import java.io.BufferedReader;
42  import java.io.File;
43  import java.io.FileNotFoundException;
44  import java.io.FileReader;
45  import java.io.IOException;
46  import java.lang.reflect.Field;
47  import java.util.List;
48  
49  /**
50   * This test class will load your dao and gives you access to the shared
51   * entityManager em. Also passes the @Dao and @PersistenceFileLocation
52   * to system properties from the annotations.
53   * <p>
54   * Extend this class and set the
55   * <ul>
56   * <li>&#064;PersistenceFileLocation
57   * <li>&#064;Dao
58   * </ul>
59   * <p>
60   * &#064;PersistenceFileLocation defines the persistence.xml location if it is
61   * named something else.
62   * <p>
63   * &#064;Dao defines the Dao implementation class, and an optional application
64   * context that contains a list of beans that should be persisted. The list bean
65   * should be called "persistList". SQL files that should be loaded can also be defined here with the
66   * testSqlFile parameter.  This should be an SQL file.
67   * <p>
68   * This test class is &#064;Transactional, so all tests will be rolled back.
69   * That means the data you load will be in the same state for each test.
70   * <p>
71   * Example:
72   * 
73   * <pre>
74   * &#064;PersistenceFileLocation(&quot;classpath:META-INF/custom-persistence.xml&quot;)
75   * public class DaoCommonTest extends AbstractTransactionalDaoTest {
76   * 
77   * &#064;Dao(value = &quot;org.kuali.student.MyDaoImpl&quot;, 
78   *      testDataFile = &quot;classpath:META-INF/pretest-data-beans-1.xml,pretest-data-beans-2.xml&quot;)
79   * public MyDao myDao;
80   * 
81   * &#064;Test
82   * public void test1() {
83   *	MyObject a = myDao.foo();
84   *	MyObject b = em.find(MyObject.class,1);
85   *	assertEquals(a.id,b.id);
86   * }
87   * }
88   * </pre>
89   * 
90   * Example of application context for preloading data:
91   * 
92   * <pre>
93   * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
94   * &lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
95   *  xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
96   *  xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&quot;&gt;
97   *  
98   *  &lt;bean id=&quot;persistList&quot;
99   *  class=&quot;org.springframework.beans.factory.config.ListFactoryBean&quot;&gt;
100  *	&lt;property name=&quot;sourceList&quot;&gt;
101  *		&lt;list&gt;
102  *			&lt;ref bean=&quot;value1&quot; /&gt;
103  *			&lt;ref bean=&quot;value2&quot; /&gt;
104  *		&lt;/list&gt;
105  *	&lt;/property&gt;
106  *  &lt;/bean&gt;
107  *  
108  *  &lt;bean id=&quot;value1&quot;
109  *  class=&quot;org.kuali.student.Value&quot;&gt;
110  *	&lt;property name=&quot;value&quot; value=&quot;Value Number One&quot; /&gt;
111  *  &lt;/bean&gt;
112  *  
113  *  &lt;bean id=&quot;value2&quot;
114  *  class=&quot;org.kuali.student.Value&quot;&gt;
115  *	&lt;property name=&quot;value&quot; value=&quot;Value Number Two&quot; /&gt;
116  *  &lt;/bean&gt;
117  * 
118  * &lt;/beans&gt;
119  * </pre>
120  */
121 @RunWith(SpringJUnit4ClassRunner.class)
122 @ContextConfiguration(locations = { "classpath:META-INF/default-dao-context-test.xml" })
123 @TestExecutionListeners( { TransactionalTestExecutionListener.class,
124 		DaoTestDependencyInjectorListener.class,
125 		DirtiesContextTestExecutionListener.class })
126 @Transactional
127 @TransactionConfiguration(transactionManager = "JtaTxManager")
128 public abstract class AbstractTransactionalDaoTest {
129 	final Logger LOG = Logger.getLogger(AbstractTransactionalDaoTest.class);
130 	@PersistenceContext
131 	protected EntityManager em;
132 
133 	@Autowired
134 	private JtaTransactionManager jtaTxManager;	
135 	
136 	private static boolean preloadedData=false;
137 
138 	/**
139 	 * Loads the application context defined in the &#064;Dao testDataFile
140 	 * attribute. Then uses the EntityManager em to persist the beans in
141 	 * persistList
142 	 */
143 	@Before
144 	public void preLoadBeans() {
145 		for (Field f : this.getClass().getDeclaredFields()) {
146 			if (f.isAnnotationPresent(Dao.class)) {
147 				Dao dao = f.getAnnotation(Dao.class);
148 				if (dao.testDataFile().length() > 0) {
149 					ApplicationContext ac = new FileSystemXmlApplicationContext(
150 							dao.testDataFile());
151 					for (Object o : (List<?>) ac.getBean("persistList")) {
152 						em.persist(o);
153 					}
154 					em.flush();
155 				}
156 			}
157 		}
158 	}
159 	
160 	@BeforeTransaction
161 	public void preLoadData() throws IOException  {
162 		if(!preloadedData){
163 			preloadedData=true;
164 			
165 			for (Field f : this.getClass().getDeclaredFields()) {
166 				if (f.isAnnotationPresent(Dao.class)) {
167 					Dao dao = f.getAnnotation(Dao.class);
168 					if (dao.testSqlFile().length() > 0) {
169 						if (dao.testSqlFile().startsWith("classpath:")) {
170 							String file = dao.testSqlFile().substring("classpath:".length());
171 							String[] files = file.split("\\s*,\\s*");
172 							for(String testFile : files) {
173 								File sqlFile = new ClassPathResource(testFile).getFile();
174 								process(sqlFile);
175 							}
176 						} else {
177 							String[] files = dao.testSqlFile().split("\\s*,\\s*");
178 							for(String testFile : files) {
179 								File sqlFile = new File(testFile);
180 								process(sqlFile);
181 							}
182 						}
183 					}
184 				}
185 			}
186 		}
187 	}
188 
189 	private void process(File sqlFile) throws FileNotFoundException {
190 		BufferedReader in
191 		   = new BufferedReader(new FileReader(sqlFile));
192 		String ln;
193 		
194 		//Check if oracle
195 		TransactionDefinition txDefinition = new DefaultTransactionDefinition() ;
196 		TransactionStatus txStatus = jtaTxManager.getTransaction(txDefinition);
197 	
198 		try {
199 		
200 			while((ln=in.readLine())!=null){
201 				if(!ln.startsWith("/")&&!ln.startsWith("--")&&StringUtils.isNotBlank(ln)){
202 					ln=ln.replaceFirst("[;/]\\s*$","");
203                     System.err.println(ln);
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 }