001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb3.test.clusteredentity.unit;
023:
024: import java.util.Properties;
025: import javax.naming.InitialContext;
026:
027: import org.hibernate.cache.StandardQueryCache;
028: import org.jboss.cache.Fqn;
029: import org.jboss.ejb3.entity.SecondLevelCacheUtil;
030: import org.jboss.ejb3.test.clusteredentity.classloader.Account;
031: import org.jboss.ejb3.test.clusteredentity.classloader.AccountHolderPK;
032: import org.jboss.ejb3.test.clusteredentity.classloader.EntityQueryTest;
033: import org.jboss.test.JBossClusteredTestCase;
034:
035: import junit.framework.Test;
036: import junit.framework.TestSuite;
037:
038: /**
039: * Base class for tests involving clustered entities with a scoped classloader.
040: *
041: * @author Brian Stansberry
042: * @version $Id: EntityUnitTestCase.java 57207 2006-09-26 12:06:13Z dimitris@jboss.org $
043: */
044: public class EntityClassloaderTestBase extends JBossClusteredTestCase {
045: public static final String EAR_NAME = "clusteredentity-classloader-test";
046: public static final String JAR_NAME = "clusteredentity-classloader-test";
047: public static final String PERSISTENCE_UNIT_NAME = "tempdb";
048:
049: protected org.apache.log4j.Logger log = getLog();
050:
051: protected static final long SLEEP_TIME = 300L;
052:
053: static boolean deployed0 = true;
054: static boolean deployed1 = true;
055:
056: protected static final AccountHolderPK SMITH = new AccountHolderPK(
057: "Smith", "1000");
058: protected static final AccountHolderPK JONES = new AccountHolderPK(
059: "Jones", "2000");
060: protected static final AccountHolderPK BARNEY = new AccountHolderPK(
061: "Barney", "3000");
062:
063: protected EntityQueryTest sfsb0;
064:
065: protected EntityQueryTest sfsb1;
066:
067: public EntityClassloaderTestBase(String name) {
068: super (name);
069: }
070:
071: protected void setUp() throws Exception {
072: super .setUp();
073:
074: sfsb0 = getEntityQueryTest(System
075: .getProperty("jbosstest.cluster.node0"));
076: sfsb1 = getEntityQueryTest(System
077: .getProperty("jbosstest.cluster.node1"));
078: sfsb0.cleanup();
079: sfsb1.cleanup();
080: }
081:
082: protected EntityQueryTest getEntityQueryTest(String nodeJNDIAddress)
083: throws Exception {
084: Properties prop1 = new Properties();
085: prop1.put("java.naming.factory.initial",
086: "org.jnp.interfaces.NamingContextFactory");
087: prop1.put("java.naming.factory.url.pkgs",
088: "org.jboss.naming:org.jnp.interfaces");
089: prop1.put("java.naming.provider.url", "jnp://"
090: + nodeJNDIAddress + ":1099");
091:
092: log.info("===== Naming properties for " + nodeJNDIAddress
093: + ": ");
094: log.info(prop1);
095: log.info("Create InitialContext for " + nodeJNDIAddress);
096: InitialContext ctx1 = new InitialContext(prop1);
097:
098: log.info("Lookup sfsb from " + nodeJNDIAddress);
099: EntityQueryTest eqt = (EntityQueryTest) ctx1
100: .lookup(getEarName() + "/EntityQueryTestBean/remote");
101: eqt.getCache(isOptimistic());
102:
103: return eqt;
104: }
105:
106: protected void tearDown() throws Exception {
107: if (sfsb0 != null) {
108: try {
109: sfsb0.remove();
110: } catch (Exception e) {
111: }
112: }
113: if (sfsb1 != null) {
114: try {
115: sfsb1.remove();
116: } catch (Exception e) {
117: }
118: }
119:
120: sfsb0 = sfsb1 = null;
121: }
122:
123: protected void standardEntitySetup() {
124: // sfsb0.createAccountHolder(SMITH, "94536");
125: sfsb0.createAccount(SMITH, new Integer(1001), new Integer(5),
126: "94536");
127: sfsb0.createAccount(SMITH, new Integer(1002), new Integer(15),
128: "94536");
129: sfsb0.createAccount(SMITH, new Integer(1003), new Integer(20),
130: "94536");
131:
132: // sfsb0.createAccountHolder(JONES, "63088");
133: sfsb0.createAccount(JONES, new Integer(2001), new Integer(5),
134: "63088");
135: sfsb0.createAccount(JONES, new Integer(2002), new Integer(15),
136: "63088");
137: sfsb0.createAccount(JONES, new Integer(2003), new Integer(20),
138: "63088");
139:
140: // sfsb0.createAccountHolder(BARNEY, "63088");
141: sfsb0.createAccount(BARNEY, new Integer(3001), new Integer(5),
142: "63088");
143: sfsb0.createAccount(BARNEY, new Integer(3002), new Integer(15),
144: "63088");
145: sfsb0.createAccount(BARNEY, new Integer(3003), new Integer(20),
146: "63088");
147:
148: log.info("Standard entities created");
149: }
150:
151: protected void resetRegionUsageState() {
152: String stdName = createRegionName(StandardQueryCache.class
153: .getName());
154: String acctName = createRegionName("AccountRegion");
155:
156: sfsb0.getSawRegionModification(stdName);
157: sfsb0.getSawRegionModification(acctName);
158:
159: sfsb0.getSawRegionAccess(stdName);
160: sfsb0.getSawRegionAccess(acctName);
161:
162: sfsb1.getSawRegionModification(stdName);
163: sfsb1.getSawRegionModification(acctName);
164:
165: sfsb1.getSawRegionAccess(stdName);
166: sfsb1.getSawRegionAccess(acctName);
167:
168: log.info("Region usage state cleared");
169: }
170:
171: protected void modifyEntities(EntityQueryTest bean) {
172: bean.updateAccountBranch(1001, "63088");
173: bean.updateAccountBalance(2001, 15);
174:
175: log.info("Entities modified");
176: }
177:
178: protected void restoreEntities(EntityQueryTest bean) {
179: // Undo the mods done in queryTest
180: bean.updateAccountBranch(1001, "94536");
181: bean.updateAccountBalance(2001, 5);
182:
183: log.info("Standard entities restored to initial state");
184: }
185:
186: /**
187: * Executes a series of entity operations and queries, checking that
188: * expected modifications and reads of the query cache occur.
189: *
190: * @param setupEntities <code>true</code> if entities don't exist and need
191: * to be created; <code>false</code> if they should
192: * exist and need to be returned to their initial state
193: * @param useNamedQuery <code>true</code> if named queries are to be used;
194: * <code>false</code> if the EJBQL should be passed
195: * to the Query
196: * @param useNamedRegion <code>true</code> if the query should be cached in
197: * "AccountRegion"; <code>false</code> if it should be
198: * cached in the default region
199: * @param expectInactivatedRegion <code>true</code> if the test should assume
200: * the query cache region is inactive on each
201: * server until accessed on that server;
202: * <code>false</code> if it should be assumed
203: * the region is activated and able to
204: * receive replication events.
205: */
206: protected void queryTest(boolean setupEntities,
207: boolean useNamedQuery, boolean useNamedRegion,
208: boolean expectInactivatedRegion) {
209: if (setupEntities)
210: standardEntitySetup();
211: else
212: restoreEntities(sfsb0);
213:
214: resetRegionUsageState();
215:
216: // Initial ops on node 0
217:
218: String regionName = createRegionName(useNamedRegion ? "AccountRegion"
219: : StandardQueryCache.class.getName());
220:
221: // Query on post code count
222: assertEquals("63088 has correct # of accounts", 6, sfsb0
223: .getCountForBranch("63088", useNamedQuery,
224: useNamedRegion));
225:
226: assertTrue("Query cache used " + regionName, sfsb0
227: .getSawRegionModification(regionName));
228: // Clear the access state
229: sfsb0.getSawRegionAccess(regionName);
230:
231: log.info("First query on node0 done");
232:
233: // Do it again from node 1
234: // Sleep a bit to allow async repl to happen
235: sleep(SLEEP_TIME);
236:
237: // If region isn't activated yet, should not have been modified
238: if (expectInactivatedRegion) {
239: assertFalse("Query cache remotely modified " + regionName,
240: sfsb1.getSawRegionModification(regionName));
241: // Clear the access state
242: sfsb1.getSawRegionAccess(regionName);
243: } else //if (useNamedRegion)
244: {
245: assertTrue("Query cache remotely modified " + regionName,
246: sfsb1.getSawRegionModification(regionName));
247: // Clear the access state
248: sfsb1.getSawRegionAccess(regionName);
249: }
250:
251: assertEquals("63088 has correct # of accounts", 6, sfsb1
252: .getCountForBranch("63088", useNamedQuery,
253: useNamedRegion));
254:
255: if (expectInactivatedRegion) {
256: // Query should have activated the region and then been inserted
257: assertTrue("Query cache modified " + regionName, sfsb1
258: .getSawRegionModification(regionName));
259: // Clear the access state
260: sfsb1.getSawRegionAccess(regionName);
261: }
262:
263: log.info("First query on node 1 done");
264:
265: // We now have the query cache region activated on both nodes.
266:
267: // Sleep a bit to allow async repl to happen
268: sleep(SLEEP_TIME);
269:
270: // Do some more queries on node 0
271:
272: assertEquals("Correct branch for Smith", "94536", sfsb0
273: .getBranch(SMITH, useNamedQuery, useNamedRegion));
274:
275: assertEquals("Correct high balances for Jones", 40, sfsb0
276: .getTotalBalance(JONES, useNamedQuery, useNamedRegion));
277:
278: assertTrue("Query cache used " + regionName, sfsb0
279: .getSawRegionModification(regionName));
280: // Clear the access state
281: sfsb0.getSawRegionAccess(regionName);
282:
283: log.info("Second set of queries on node0 done");
284:
285: // Sleep a bit to allow async repl to happen
286: sleep(SLEEP_TIME);
287:
288: // Do it again from node 1
289:
290: // First check if the previous queries replicated (if the region is replicable)
291:
292: assertTrue("Query cache remotely modified " + regionName, sfsb1
293: .getSawRegionModification(regionName));
294: // Clear the access state
295: sfsb1.getSawRegionAccess(regionName);
296:
297: assertEquals("Correct branch for Smith", "94536", sfsb1
298: .getBranch(SMITH, useNamedQuery, useNamedRegion));
299:
300: assertEquals("Correct high balances for Jones", 40, sfsb1
301: .getTotalBalance(JONES, useNamedQuery, useNamedRegion));
302:
303: // Should be no change; query was already there
304: assertFalse("Query cache modified " + regionName, sfsb1
305: .getSawRegionModification(regionName));
306: assertTrue("Query cache accessed " + regionName, sfsb1
307: .getSawRegionAccess(regionName));
308:
309: log.info("Second set of queries on node1 done");
310:
311: // Modify underlying data on node 1
312: modifyEntities(sfsb1);
313:
314: // Confirm query results are correct on node 0
315:
316: assertEquals("63088 has correct # of accounts", 7, sfsb0
317: .getCountForBranch("63088", useNamedQuery,
318: useNamedRegion));
319:
320: assertEquals("Correct branch for Smith", "63088", sfsb0
321: .getBranch(SMITH, useNamedQuery, useNamedRegion));
322:
323: assertEquals("Correct high balances for Jones", 50, sfsb0
324: .getTotalBalance(JONES, useNamedQuery, useNamedRegion));
325:
326: log.info("Third set of queries on node0 done");
327: }
328:
329: protected void sleep(long millis) {
330: try {
331: Thread.sleep(millis);
332: } catch (InterruptedException e) {
333: log.warn("Interrupted while sleeping", e);
334: }
335: }
336:
337: protected String createRegionName(String noPrefix) {
338: String prefix = createCacheRegionPrefix(getEarName(),
339: getJarName(), getPersistenceUnitName());
340: return "/" + prefix + "/" + noPrefix.replace('.', '/');
341: }
342:
343: protected String getEarName() {
344: return EAR_NAME;
345: }
346:
347: protected String getJarName() {
348: return JAR_NAME;
349: }
350:
351: protected String getPersistenceUnitName() {
352: return PERSISTENCE_UNIT_NAME;
353: }
354:
355: public static String createCacheRegionPrefix(String earName,
356: String jarName, String unitName) {
357: StringBuilder sb = new StringBuilder();
358: if (earName != null) {
359: sb.append(earName);
360: if (!earName.endsWith(".ear"))
361: sb.append("_ear");
362: sb.append(",");
363: }
364: if (jarName != null) {
365: sb.append(jarName);
366: if (!jarName.endsWith(".jar"))
367: sb.append("_jar");
368: sb.append(",");
369: }
370: sb.append(unitName);
371: String raw = sb.toString();
372: // Replace any '.' otherwise the JBoss Cache integration may replace
373: // it with a '/' and it will become a level in the FQN
374: String escaped = raw.replace('.', '_');
375: return escaped;
376: }
377:
378: protected boolean isOptimistic() {
379: return false;
380: }
381: }
|