001: package org.apache.ojb.broker.metadata;
002:
003: import java.util.ArrayList;
004: import java.util.List;
005: import java.util.Collection;
006: import java.util.Iterator;
007:
008: import org.apache.commons.lang.ClassUtils;
009: import org.apache.ojb.broker.*;
010: import org.apache.ojb.broker.accesslayer.OJBIterator;
011: import org.apache.ojb.broker.query.Query;
012: import org.apache.ojb.broker.query.QueryByCriteria;
013: import org.apache.ojb.broker.query.QueryFactory;
014: import org.apache.ojb.broker.sequence.Repository;
015: import org.apache.ojb.broker.util.ClassHelper;
016: import org.apache.ojb.broker.util.logging.Logger;
017: import org.apache.ojb.broker.util.logging.LoggerFactory;
018: import org.apache.ojb.junit.JUnitExtensions;
019:
020: /**
021: *
022: * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
023: * @version $Id: MetadataMultithreadedTest.java,v 1.7.2.3 2005/03/03 21:38:12 mkalen Exp $
024: */
025: public class MetadataMultithreadedTest extends
026: JUnitExtensions.MultiThreadedTestCase {
027: // we change table name in test for target class
028: private String newTestObjectString = "SM_TAB_MAX_AA";
029: private Class targetTestClass = Repository.SMMaxA.class;
030: int loops = 7;
031: int threads = 4;
032: // need min 80% free memory after test campared with
033: // beginning, else test fails
034: int minimalFreeMemAfterTest = 80;
035:
036: private String oldTestObjectString;
037: DescriptorRepository defaultRepository;
038:
039: protected final Logger logger = LoggerFactory.getLogger(this
040: .getClass());
041:
042: public MetadataMultithreadedTest(String s) {
043: super (s);
044: }
045:
046: public static void main(String[] args) {
047: String[] arr = { MetadataMultithreadedTest.class.getName() };
048: junit.textui.TestRunner.main(arr);
049: }
050:
051: private long getTotalMemory() {
052: long result = Long.MAX_VALUE;
053: // TODO: find a solution for this problem, or uncomment if we cancel 1.2 support
054: // result = Runtime.getRuntime().maxMemory(); // not available in JDK 1.2
055: return result;
056: }
057:
058: protected void setUp() throws Exception {
059: super .setUp();
060: MetadataManager mm = MetadataManager.getInstance();
061: // enable the per thread changes of metadata
062: mm.setEnablePerThreadChanges(true);
063: defaultRepository = mm.copyOfGlobalRepository();
064: }
065:
066: protected void tearDown() throws Exception {
067: super .tearDown();
068: MetadataManager.getInstance().setEnablePerThreadChanges(false);
069: }
070:
071: private String getTestObjectString() {
072: return oldTestObjectString;
073: }
074:
075: public void testProxiedLoading() throws Exception {
076: PersistenceBroker broker = null;
077: try {
078: MetadataManager mm = MetadataManager.getInstance();
079: // Store the current repository mappings under a profile key
080: DescriptorRepository repository = mm.getRepository();
081: String profileKey = "TestMappings";
082: mm.addProfile(profileKey, repository);
083:
084: // "Destroy" this thread's mappings
085: mm.setDescriptor(defaultRepository);
086:
087: ProductGroupWithCollectionProxy pgTemplate = new ProductGroupWithCollectionProxy();
088: pgTemplate.setGroupId(new Integer(6));
089: Query query = QueryFactory.newQueryByExample(pgTemplate);
090:
091: broker = PersistenceBrokerFactory
092: .defaultPersistenceBroker();
093: Collection groups;
094: Iterator groupIter;
095: ProductGroupWithCollectionProxy pg;
096:
097: assertNotNull(groupIter = (OJBIterator) broker
098: .getIteratorByQuery(query));
099: assertTrue(groupIter.hasNext());
100:
101: // We have not named any OJB profiles, so using dynamic proxies at this stage is not
102: // supported
103: Throwable expectedThrowable = null;
104: try {
105: System.err
106: .println("------ The following exception is part of the tests...");
107: groupIter.next();
108: } catch (Throwable t) {
109: expectedThrowable = t;
110: System.err.println("------");
111: }
112: assertNotNull("Should get metadata exception from proxy",
113: expectedThrowable);
114: ((OJBIterator) groupIter).releaseDbResources();
115:
116: // Load the repository profile and re-try loading.
117: broker.clearCache();
118: mm.loadProfile(profileKey);
119: assertNotNull(groups = broker.getCollectionByQuery(query));
120: assertEquals(1, groups.size());
121: assertNotNull(groupIter = groups.iterator());
122: assertTrue(groupIter.hasNext());
123: assertNotNull(pg = (ProductGroupWithCollectionProxy) groupIter
124: .next());
125: assertFalse(groupIter.hasNext());
126: assertEquals(pgTemplate.getGroupId(), pg.getGroupId());
127: Collection articles;
128: assertNotNull(articles = pg.getAllArticlesInGroup());
129: assertEquals(6, articles.size());
130:
131: TestCaseRunnable tct[] = new TestCaseRunnable[] { new LazyLoading(
132: articles) };
133: runTestCaseRunnables(tct);
134: } finally {
135: if (broker != null)
136: broker.close();
137: }
138:
139: }
140:
141: /**
142: * Regression test for loading CollectionProxy data in a thread where the profile
143: * is swapped, and the thread-local broker is closed, between CollectionProxy construction
144: * and retrieveCollections-call.
145: * @throws Exception on unexpected failure
146: */
147: public void testCollectionProxySwapProfiles() throws Exception {
148: PersistenceBroker broker = null;
149: try {
150: MetadataManager mm = MetadataManager.getInstance();
151:
152: // Store the current repository mappings under a profile key and load it
153: DescriptorRepository repository = mm.getRepository();
154: String profileKey = "TestMappings";
155: mm.addProfile(profileKey, repository);
156: mm.loadProfile(profileKey);
157:
158: // Load object and proxy
159: ProductGroupWithCollectionProxy pgTemplate = new ProductGroupWithCollectionProxy();
160: pgTemplate.setGroupId(new Integer(6));
161: Query query = QueryFactory.newQueryByExample(pgTemplate);
162: broker = PersistenceBrokerFactory
163: .defaultPersistenceBroker();
164: ProductGroupWithCollectionProxy productGroup;
165: assertNotNull(productGroup = (ProductGroupWithCollectionProxy) broker
166: .getObjectByQuery(query));
167:
168: // Close broker to make sure proxy needs a new internal one
169: broker.close();
170:
171: // Swap profile (to a completely empty one)
172: final String emptyKey = "EMPTY";
173: DescriptorRepository emptyDr = new DescriptorRepository();
174: mm.addProfile(emptyKey, emptyDr);
175: mm.loadProfile(emptyKey);
176:
177: List collectionProxy = productGroup.getAllArticlesInGroup();
178: assertNotNull(collectionProxy);
179:
180: // Load proxy data, will throw ClassNotPersistenceCapableException
181: // if not reactivating profile with new thread-local broker
182: assertNotNull(collectionProxy.get(0));
183: } finally {
184: if (broker != null)
185: broker.close();
186: }
187: }
188:
189: public void testRuntimeMetadataChanges() throws Exception {
190: PersistenceBroker broker = null;
191: try {
192: MetadataManager.getInstance().setDescriptor(
193: defaultRepository);
194:
195: ClassDescriptor cld;
196: long memoryUseBeforeTest;
197: long memoryUseAfterTest;
198: try {
199: // prepare for test
200: long period = System.currentTimeMillis();
201: broker = PersistenceBrokerFactory
202: .defaultPersistenceBroker();
203: cld = broker.getClassDescriptor(targetTestClass);
204:
205: // we manipulate the schema name of the class
206: // thus we note the original value
207: oldTestObjectString = cld.getFullTableName();
208: broker.close();
209:
210: // cleanup JVM
211: Runtime.getRuntime().gc();
212: Thread.sleep(200);
213: Runtime.getRuntime().gc();
214:
215: // start test
216: long memory = Runtime.getRuntime().freeMemory();
217: long totalMemory = getTotalMemory();
218:
219: int count = 0;
220: for (int k = 0; k < loops; k++) {
221: TestCaseRunnable tct[] = new TestCaseRunnable[threads];
222: for (int i = 0; i < threads; i++) {
223: if (i % 2 == 0)
224: tct[i] = new ThreadedUsingBroker(loops);
225: else
226: tct[i] = new GlobalUsingBroker(loops);
227: }
228: // run test classes
229: runTestCaseRunnables(tct);
230: ++count;
231: if (logger.isDebugEnabled()) {
232: logger.debug("Free/total Memory after loop "
233: + count
234: + ": "
235: + convertToMB(Runtime.getRuntime()
236: .freeMemory()) + "/"
237: + convertToMB(getTotalMemory()) + "MB");
238: }
239: }
240: period = System.currentTimeMillis() - period;
241: if (logger.isDebugEnabled()) {
242: logger
243: .debug(ClassUtils
244: .getShortClassName(MetadataMultithreadedTest.class)
245: + " take: "
246: + period
247: + " ms for "
248: + loops
249: + " loops, creating each with "
250: + threads + " threads");
251: logger
252: .debug("Free/total Memory before test: "
253: + convertToMB(memory)
254: + "/"
255: + convertToMB(totalMemory) + "MB");
256: }
257: Runtime.getRuntime().gc();
258: Thread.sleep(200);
259: Runtime.getRuntime().gc();
260: Runtime.getRuntime().gc();
261:
262: memoryUseBeforeTest = convertToMB(memory);
263: memoryUseAfterTest = convertToMB(Runtime.getRuntime()
264: .freeMemory());
265: if (logger.isDebugEnabled()) {
266: logger
267: .debug("Free/total Memory after test and gc: "
268: + memoryUseAfterTest
269: + "/"
270: + convertToMB(getTotalMemory())
271: + "MB");
272: logger.debug("Do cleanup now ...");
273: }
274: } finally {
275: MetadataManager.getInstance()
276: .setEnablePerThreadChanges(false);
277: }
278: // get new PB instance
279: broker = PersistenceBrokerFactory
280: .defaultPersistenceBroker();
281: cld = broker.getClassDescriptor(targetTestClass);
282: String name = cld.getFullTableName();
283: assertEquals(oldTestObjectString, name);
284: assertFalse(MetadataManager.getInstance()
285: .isEnablePerThreadChanges());
286: double d = ((double) memoryUseAfterTest)
287: / ((double) memoryUseBeforeTest);
288: int result = (int) (d * 100);
289: if (result < minimalFreeMemAfterTest) {
290: fail("** When using a offical version of OJB, ignore this failure! **"
291: + " Memory usage after this test differs more than "
292: + (100 - minimalFreeMemAfterTest)
293: + "% from beginning, this may indicate"
294: + " a memory leak (GC can't free unused metadata objects), but this could also be a result"
295: + " of your JVM settings. Please re-run test.");
296: }
297: } finally {
298: if (broker != null)
299: broker.close();
300: }
301: }
302:
303: private long convertToMB(long byteValue) {
304: return (byteValue / 1024) / 1024;
305: }
306:
307: // ======================================================================
308: // inner test class
309: // ======================================================================
310: class ThreadedUsingBroker extends
311: JUnitExtensions.MultiThreadedTestCase.TestCaseRunnable {
312: int loops;
313: String title = "ThreadedUsingBroker_"
314: + System.currentTimeMillis();
315:
316: public ThreadedUsingBroker() {
317: }
318:
319: public ThreadedUsingBroker(int loops) {
320: this .loops = loops;
321: }
322:
323: public void runTestCase() throws Exception {
324: MetadataManager mm = MetadataManager.getInstance();
325: DescriptorRepository dr = mm.copyOfGlobalRepository();
326: ClassDescriptor cld = dr.getDescriptorFor(targetTestClass);
327: // we change a class descriptor value
328: cld.setTableName(newTestObjectString);
329: // set the changed repository for this thread
330: mm.setDescriptor(dr);
331:
332: int k = 0;
333: while (k < loops) {
334: PersistenceBroker broker = null;
335: try {
336: broker = PersistenceBrokerFactory
337: .defaultPersistenceBroker();
338: cld = broker.getClassDescriptor(targetTestClass);
339: String name = cld.getFullTableName();
340: assertEquals(newTestObjectString, name);
341: assertTrue(MetadataManager.getInstance()
342: .isEnablePerThreadChanges());
343: } finally {
344: if (broker != null)
345: broker.close();
346: }
347:
348: try {
349: broker = PersistenceBrokerFactory
350: .defaultPersistenceBroker();
351: // check made changes
352: cld = broker.getClassDescriptor(targetTestClass);
353: String name = cld.getFullTableName();
354: assertEquals(newTestObjectString, name);
355: assertTrue(MetadataManager.getInstance()
356: .isEnablePerThreadChanges());
357:
358: // query a test object
359: Query query = new QueryByCriteria(Person.class,
360: null, true);
361: broker.getCollectionByQuery(query);
362: // store target object
363: /*
364: store some complex objects to check if references to
365: metadata classes are cached
366: */
367: Project project = new Project();
368: project.setTitle(title);
369:
370: Person p1 = new Person();
371: p1.setFirstname(title);
372: List l1 = new ArrayList();
373: l1.add(project);
374: p1.setProjects(l1);
375:
376: Person p2 = new Person();
377: p2.setFirstname(title);
378: List l2 = new ArrayList();
379: l2.add(project);
380: p2.setProjects(l2);
381:
382: Role r1 = new Role();
383: r1.setPerson(p1);
384: r1.setRoleName(title);
385: r1.setProject(project);
386: List roles1 = new ArrayList();
387: roles1.add(r1);
388:
389: Role r2 = new Role();
390: r2.setPerson(p2);
391: r2.setRoleName(title);
392: r2.setProject(project);
393: List roles2 = new ArrayList();
394: roles2.add(r2);
395:
396: p1.setRoles(roles1);
397: p2.setRoles(roles2);
398:
399: Object obj = ClassHelper
400: .newInstance(targetTestClass);
401:
402: broker.beginTransaction();
403: broker.store(obj);
404: broker.store(p1);
405: broker.store(p2);
406: broker.commitTransaction();
407: // delete target object
408: broker.beginTransaction();
409: broker.delete(obj);
410: //broker.delete(p1);
411: //broker.delete(p2);
412: broker.commitTransaction();
413: } finally {
414: if (broker != null)
415: broker.close();
416: }
417:
418: k++;
419: try {
420: Thread.sleep(5);
421: } catch (InterruptedException e) {
422: }
423: }
424:
425: }
426: }
427:
428: // ======================================================================
429: // inner test class
430: // ======================================================================
431: class GlobalUsingBroker extends
432: JUnitExtensions.MultiThreadedTestCase.TestCaseRunnable {
433: int loops;
434:
435: public GlobalUsingBroker(int loops) {
436: this .loops = loops;
437: }
438:
439: public void runTestCase() {
440: PersistenceBroker broker = null;
441: int k = 0;
442: try {
443: while (k < loops) {
444: try {
445: MetadataManager.getInstance().setDescriptor(
446: defaultRepository);
447: broker = PersistenceBrokerFactory
448: .defaultPersistenceBroker();
449: ClassDescriptor cld = broker
450: .getClassDescriptor(targetTestClass);
451: assertTrue(MetadataManager.getInstance()
452: .isEnablePerThreadChanges());
453: String name = cld.getFullTableName();
454: // this PB instance use unchanged global metadata repository
455: assertEquals(getTestObjectString(), name);
456: } finally {
457: if (broker != null)
458: broker.close();
459: }
460: try {
461: broker = PersistenceBrokerFactory
462: .defaultPersistenceBroker();
463: ClassDescriptor cld = broker
464: .getClassDescriptor(targetTestClass);
465: assertTrue(MetadataManager.getInstance()
466: .isEnablePerThreadChanges());
467: String name = cld.getFullTableName();
468: // this PB instance use unchanged global metadata repository
469: assertEquals(getTestObjectString(), name);
470: // System.out.println("Default: found "+name);
471:
472: // query a test object
473: Query query = new QueryByCriteria(Person.class,
474: null, true);
475: broker.getCollectionByQuery(query);
476: // store target object
477: Object obj = ClassHelper
478: .newInstance(targetTestClass);
479: broker.beginTransaction();
480: broker.store(obj);
481: broker.commitTransaction();
482: // delete target object
483: broker.beginTransaction();
484: broker.delete(obj);
485: broker.commitTransaction();
486: } finally {
487: if (broker != null)
488: broker.close();
489: }
490:
491: k++;
492: try {
493: Thread.sleep(5);
494: } catch (InterruptedException e) {
495: }
496: }
497: } catch (Exception e) {
498: e.printStackTrace();
499: throw new OJBRuntimeException(e);
500: }
501: }
502: }
503:
504: /**
505: * Inner test class for lazy materialization of CollectionProxy in different thread.
506: */
507: protected class LazyLoading extends
508: JUnitExtensions.MultiThreadedTestCase.TestCaseRunnable {
509: private Collection articles;
510:
511: public LazyLoading(Collection articles) {
512: assertNotNull(this .articles = articles);
513: }
514:
515: public void runTestCase() throws Throwable {
516: // Explicitly clear descriptor repository in this thread (similar to loading
517: // profile with unrelated class-mappings).
518: DescriptorRepository dr = new DescriptorRepository();
519: MetadataManager.getInstance().setDescriptor(dr);
520: Article article;
521: int numArticles = 0;
522: for (Iterator iterator = articles.iterator(); iterator
523: .hasNext();) {
524: assertNotNull(article = (Article) iterator.next());
525: assertNotNull(article.getArticleId());
526: assertFalse(new Integer(0).equals(article
527: .getArticleId()));
528: numArticles++;
529: }
530: assertEquals(6, numArticles);
531: }
532: }
533:
534: }
|