001: package org.apache.ojb.odmg;
002:
003: import java.io.Serializable;
004: import java.util.Collection;
005: import java.util.List;
006:
007: import org.apache.ojb.broker.PersistenceBroker;
008: import org.apache.ojb.broker.PersistenceBrokerFactory;
009: import org.apache.ojb.broker.TestHelper;
010: import org.apache.ojb.broker.query.Criteria;
011: import org.apache.ojb.broker.query.QueryFactory;
012: import org.apache.ojb.junit.OJBTestCase;
013: import org.apache.ojb.odmg.locking.LockManager;
014: import org.apache.ojb.odmg.locking.LockManagerFactory;
015: import org.apache.ojb.odmg.shared.Article;
016: import org.apache.commons.beanutils.PropertyUtils;
017: import org.apache.commons.lang.builder.ToStringBuilder;
018: import org.apache.commons.lang.builder.EqualsBuilder;
019: import org.odmg.Database;
020: import org.odmg.Implementation;
021: import org.odmg.LockNotGrantedException;
022: import org.odmg.OQLQuery;
023: import org.odmg.Transaction;
024:
025: /**
026: * Test optimistic and pessimistic locking mechanisms
027: */
028: public class LockingTest extends OJBTestCase {
029: public static void main(String[] args) {
030: String[] arr = { LockingTest.class.getName() };
031: junit.textui.TestRunner.main(arr);
032: }
033:
034: private static String PRE = "LockingTest_"
035: + System.currentTimeMillis() + "_";
036:
037: private Implementation odmg1;
038: private Database db1;
039:
040: private Implementation odmg2;
041: private Database db2;
042:
043: public LockingTest(String name) {
044: super (name);
045: }
046:
047: public void setUp() throws Exception {
048: super .setUp();
049: String databaseName = TestHelper.DEF_DATABASE_NAME;
050:
051: odmg1 = OJB.getInstance();
052: db1 = odmg1.newDatabase();
053: db1.open(databaseName, Database.OPEN_READ_WRITE);
054:
055: odmg2 = OJB.getInstance();
056: db2 = odmg2.newDatabase();
057: db2.open(databaseName, Database.OPEN_READ_WRITE);
058:
059: }
060:
061: public void tearDown() throws Exception {
062: if (odmg1.currentTransaction() != null)
063: odmg1.currentTransaction().abort();
064: db1.close();
065:
066: if (odmg2.currentTransaction() != null)
067: odmg2.currentTransaction().abort();
068: db2.close();
069: super .tearDown();
070: }
071:
072: public void testWrite_1() throws Exception {
073: String name = "testWrite_1_" + System.currentTimeMillis();
074: LockObject bean = new LockObject(name + "_bean_dummy");
075:
076: performSaveMethod(bean.getId(), bean);
077:
078: Transaction tx = odmg1.newTransaction();
079: tx.begin();
080: OQLQuery query = odmg1.newOQLQuery();
081: query.create("select objs from " + LockObject.class.getName()
082: + " where value = $1");
083: query.bind(name + "_bean_dummy");
084: List result = (List) query.execute();
085: tx.commit();
086: assertEquals(1, result.size());
087: LockObject tmp = (LockObject) result.get(0);
088: assertEquals(bean, tmp);
089: }
090:
091: public void testWrite_2() throws Exception {
092: String name = "testWrite_2_" + System.currentTimeMillis();
093:
094: Transaction tx = odmg1.newTransaction();
095: tx.begin();
096: LockObject tmp = new LockObject(name + "_temp");
097: db1.makePersistent(tmp);
098: tx.commit();
099:
100: LockObject bean = new LockObject(name + "_bean_dummy");
101: bean.setId(tmp.getId());
102:
103: performSaveMethod(tmp.getId(), bean);
104:
105: tx = odmg1.newTransaction();
106: tx.begin();
107: OQLQuery query = odmg1.newOQLQuery();
108: query.create("select objs from " + LockObject.class.getName()
109: + " where value = $1");
110: query.bind(name + "_bean_dummy");
111: List result = (List) query.execute();
112: tx.commit();
113: assertEquals(1, result.size());
114: tmp = (LockObject) result.get(0);
115: assertEquals(bean, tmp);
116: }
117:
118: /**
119: * This method should reproduce a problem with Cocoon and OJB1.0.3
120: */
121: private LockObject performSaveMethod(Integer testId, LockObject bean)
122: throws Exception {
123: LockObject toBeEdited = null;
124: Transaction tx = odmg1.newTransaction();
125: tx.begin();
126: OQLQuery query = odmg1.newOQLQuery();
127: query.create("select objs from " + LockObject.class.getName()
128: + " where id = $1");
129: query.bind(testId);
130: List result = (List) query.execute();
131: if (result.size() != 0) {
132: toBeEdited = (LockObject) result.get(0);
133: if (toBeEdited != null) {
134: try {
135: PropertyUtils.copyProperties(toBeEdited, bean);
136: tx.commit();
137: } catch (Exception e) {
138: e.printStackTrace();
139: fail("Unexpected exception: " + e.getMessage());
140: }
141: // use new tx to check released locks for objects
142: tx = odmg1.newTransaction();
143: tx.begin();
144: tx.lock(toBeEdited, Transaction.UPGRADE);
145: tx.commit();
146: } else {
147: tx.abort();
148: }
149: } else {
150: try {
151: tx.lock(bean, Transaction.WRITE);
152: tx.commit();
153: } catch (Exception e) {
154: e.printStackTrace();
155: fail("Unexpected exception: " + e.getMessage());
156: }
157: }
158: return toBeEdited;
159: }
160:
161: /**
162: * Test multiple locks on the same object
163: */
164: public void testMultipleLocks() throws Exception {
165: long timestamp = System.currentTimeMillis();
166: String name = "testMultipleLocks_" + timestamp;
167: String nameUpdated = "testMultipleLocks_Updated_" + timestamp;
168: TransactionExt tx = (TransactionExt) odmg1.newTransaction();
169: LockObjectOpt obj = new LockObjectOpt();
170: tx.begin();
171: tx.lock(obj, Transaction.WRITE);
172: obj.setValue(name);
173: tx.lock(obj, Transaction.WRITE);
174: tx.lock(obj, Transaction.UPGRADE);
175: tx.commit();
176:
177: OQLQuery query = odmg1.newOQLQuery();
178: query.create("select all from " + LockObjectOpt.class.getName()
179: + " where value like $1");
180: query.bind(name);
181: Collection result = (Collection) query.execute();
182: assertNotNull(result);
183: assertEquals(1, result.size());
184:
185: tx.begin();
186: tx.lock(obj, Transaction.WRITE);
187: tx.lock(obj, Transaction.WRITE);
188: obj.setValue(nameUpdated);
189: tx.lock(obj, Transaction.WRITE);
190: tx.lock(obj, Transaction.UPGRADE);
191: tx.commit();
192:
193: query = odmg1.newOQLQuery();
194: query.create("select all from " + LockObjectOpt.class.getName()
195: + " where value like $1");
196: query.bind(nameUpdated);
197: result = (Collection) query.execute();
198: assertNotNull(result);
199: assertEquals(1, result.size());
200: }
201:
202: public void testLockBasics() throws Exception {
203: TransactionImpl tx1 = (TransactionImpl) odmg1.newTransaction();
204: TransactionImpl tx2 = (TransactionImpl) odmg2.newTransaction();
205:
206: Article a = new Article();
207: a.setArticleId(333);
208:
209: tx1.begin();
210: tx2.begin();
211: LockManager lm = LockManagerFactory.getLockManager();
212: boolean success1 = lm.writeLock(tx1, a);
213: boolean success2 = lm.writeLock(tx2, a);
214:
215: boolean success3 = lm.releaseLock(tx1, a);
216:
217: assertTrue("1st lock should succeed", success1);
218: assertTrue("2nd lock should not succeed", !success2);
219: assertTrue("release should succeed", success3);
220:
221: try {
222: tx1.abort();
223: tx2.abort();
224: } catch (Exception e) {
225: }
226: }
227:
228: public void testLockBasics2() throws Exception {
229: TransactionImpl tx1 = (TransactionImpl) odmg1.newTransaction();
230: TransactionImpl tx2 = (TransactionImpl) odmg2.newTransaction();
231:
232: Article a1 = new Article();
233: a1.setArticleId(333);
234:
235: Article a2 = new Article();
236: a2.setArticleId(333);
237:
238: tx1.begin();
239: tx2.begin();
240: LockManager lm = LockManagerFactory.getLockManager();
241:
242: assertFalse(tx1.getGUID().equals(tx2.getGUID()));
243:
244: assertTrue("1st lock should succeed", lm.writeLock(tx1, a1));
245: assertFalse("2nd lock should not succeed", lm
246: .writeLock(tx2, a2));
247: lm.releaseLock(tx2, a2);
248: lm.releaseLock(tx2, a1);
249: assertFalse(lm.checkWrite(tx2, a1));
250: assertFalse(lm.checkWrite(tx2, a2));
251: assertTrue(lm.checkWrite(tx1, a1));
252: assertTrue(lm.checkWrite(tx1, a2));
253: //assertFalse("2nd release should not succeed", lm.releaseLock(tx2, a2));
254: //assertFalse("2nd release should not succeed", lm.releaseLock(tx2, a1));
255: assertTrue("release should succeed", lm.releaseLock(tx1, a2));
256: assertTrue("2nd object lock should succeed", lm.writeLock(tx2,
257: a2));
258: assertTrue("release 2nd object lock should succeed", lm
259: .releaseLock(tx2, a2));
260:
261: try {
262: tx1.abort();
263: tx2.abort();
264: } catch (Exception e) {
265: }
266: }
267:
268: /**
269: * test proper treatment of Optimistic Locking in
270: * ODMG transactions
271: */
272: public void testOptimisticLockBasics() throws Exception {
273: TransactionImpl tx1 = (TransactionImpl) odmg1.newTransaction();
274: TransactionImpl tx2 = (TransactionImpl) odmg2.newTransaction();
275:
276: LockObjectOpt obj = new LockObjectOpt();
277:
278: tx1.begin();
279:
280: tx1.lock(obj, Transaction.WRITE);
281: obj.setValue("tx1");
282: tx1.commit();
283:
284: obj.setVersion(obj.getVersion() - 1);
285: tx2.begin();
286: tx2.lock(obj, Transaction.WRITE);
287:
288: obj.setValue("tx2");
289: try {
290: tx2.commit();
291: // OL exceptions should be signalled as ODMG LockNotGrantedExceptions
292: // so that users can react accordingly
293: fail("Optimistic locking exception expected");
294: } catch (LockNotGrantedException ex) {
295: assertTrue("expected that a OL exception is caught", true);
296: } catch (Exception e) {
297: e.printStackTrace();
298: fail("Wrong kind of exception thrown, expected 'LockNotGrantedException', but was "
299: + e.getMessage());
300: }
301: }
302:
303: /**
304: * factory method that createa an PerformanceArticle
305: *
306: * @return the created PerformanceArticle object
307: */
308: private Article createArticle(String name) {
309: Article a = new Article();
310:
311: a.setArticleName(PRE + name);
312: a.setMinimumStock(100);
313: a.setOrderedUnits(17);
314: a.setPrice(0.45);
315: a.setProductGroupId(1);
316: a.setStock(234);
317: a.setSupplierId(4);
318: a.setUnit("bottle");
319: return a;
320: }
321:
322: public void testLockLoop() throws Exception {
323: int loops = 10;
324: Article[] arr = new Article[loops];
325: for (int i = 0; i < loops; i++) {
326: Article a = createArticle("testLockLoop");
327: arr[i] = a;
328: }
329:
330: TransactionImpl tx = (TransactionImpl) odmg1.newTransaction();
331: tx.begin();
332: for (int i = 0; i < arr.length; i++) {
333: tx.lock(arr[i], Transaction.WRITE);
334: }
335: LockManager lm = LockManagerFactory.getLockManager();
336: boolean success = lm.writeLock(tx, arr[(loops - 2)]);
337: assertTrue("lock should succeed", success);
338: tx.commit();
339:
340: TransactionImpl tx2 = (TransactionImpl) odmg2.newTransaction();
341: tx2.begin();
342: success = lm.writeLock(tx2, arr[(loops - 2)]);
343: assertTrue("lock should succeed", success);
344:
345: OQLQuery query = odmg2.newOQLQuery();
346: String sql = "select allArticles from "
347: + Article.class.getName() + " where articleName = \""
348: + PRE + "testLockLoop" + "\"";
349: query.create(sql);
350: int result = ((List) query.execute()).size();
351: tx2.commit();
352: assertEquals("Wrong number of objects wrote to DB", loops,
353: result);
354:
355: PersistenceBroker broker = PersistenceBrokerFactory
356: .defaultPersistenceBroker();
357: broker.clearCache();
358: Criteria crit = new Criteria();
359: crit.addLike("articleName", PRE + "testLockLoop");
360: result = broker.getCount(QueryFactory.newQuery(Article.class,
361: crit));
362: broker.close();
363: assertEquals("Wrong number of objects wrote to DB", loops,
364: result);
365: }
366:
367: /**
368: * Test object.
369: */
370: public static class LockObject implements Serializable {
371: private Integer id;
372: private String value;
373:
374: public LockObject() {
375: }
376:
377: public LockObject(String value) {
378: this .value = value;
379: }
380:
381: public boolean equals(Object obj) {
382: if (obj == null || !(obj instanceof LockObject)) {
383: return false;
384: } else {
385: LockObject tmp = (LockObject) obj;
386: return new EqualsBuilder().append(id, tmp.id).append(
387: value, tmp.value).isEquals();
388: }
389: }
390:
391: public String toString() {
392: return new ToStringBuilder(this ).append("id", id).append(
393: "value", value).toString();
394: }
395:
396: public Integer getId() {
397: return id;
398: }
399:
400: public void setId(Integer id) {
401: this .id = id;
402: }
403:
404: public String getValue() {
405: return value;
406: }
407:
408: public void setValue(String value) {
409: this .value = value;
410: }
411: }
412:
413: /**
414: * Test object with optimistic locking enabled.
415: */
416: public static class LockObjectOpt extends LockObject {
417: private int version;
418:
419: public LockObjectOpt() {
420: }
421:
422: public LockObjectOpt(String value) {
423: super (value);
424: }
425:
426: public boolean equals(Object obj) {
427: if (obj == null || !(obj instanceof LockObjectOpt)) {
428: return false;
429: } else {
430: LockObjectOpt tmp = (LockObjectOpt) obj;
431: return new EqualsBuilder().append(version, tmp.version)
432: .isEquals()
433: && super .equals(obj);
434: }
435: }
436:
437: public String toString() {
438: return new ToStringBuilder(this ).append("super",
439: super .toString()).append("version", version)
440: .toString();
441: }
442:
443: public int getVersion() {
444: return version;
445: }
446:
447: public void setVersion(int version) {
448: this.version = version;
449: }
450: }
451: }
|