Project

General

Profile

Download (36.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2009 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9

    
10
package eu.etaxonomy.cdm.test.function;
11

    
12
import static org.junit.Assert.assertEquals;
13
import static org.junit.Assert.assertFalse;
14
import static org.junit.Assert.assertNotSame;
15
import static org.junit.Assert.assertNull;
16
import static org.junit.Assert.assertSame;
17
import static org.junit.Assert.assertTrue;
18

    
19
import java.io.FileNotFoundException;
20
import java.util.Set;
21
import java.util.UUID;
22

    
23
import javax.sql.DataSource;
24

    
25
import org.apache.log4j.Logger;
26
import org.hibernate.LockMode;
27
import org.hibernate.Session;
28
import org.hibernate.SessionFactory;
29
import org.junit.After;
30
import org.junit.Before;
31
import org.junit.Ignore;
32
import org.junit.Test;
33
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
34
import org.springframework.orm.hibernate5.HibernateSystemException;
35
import org.springframework.orm.hibernate5.SessionHolder;
36
import org.springframework.transaction.PlatformTransactionManager;
37
import org.springframework.transaction.TransactionStatus;
38
import org.springframework.transaction.support.TransactionSynchronizationManager;
39
import org.unitils.database.annotations.Transactional;
40
import org.unitils.database.util.TransactionMode;
41
import org.unitils.dbunit.annotation.DataSet;
42
import org.unitils.spring.annotation.SpringBeanByType;
43

    
44
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
45
import eu.etaxonomy.cdm.api.service.IDescriptionService;
46
import eu.etaxonomy.cdm.api.service.IReferenceService;
47
import eu.etaxonomy.cdm.api.service.ITaxonService;
48
import eu.etaxonomy.cdm.api.service.ITermService;
49
import eu.etaxonomy.cdm.model.common.DefinedTerm;
50
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
51
import eu.etaxonomy.cdm.model.location.NamedArea;
52
import eu.etaxonomy.cdm.model.name.BotanicalName;
53
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
54
import eu.etaxonomy.cdm.model.reference.Reference;
55
import eu.etaxonomy.cdm.model.taxon.Synonym;
56
import eu.etaxonomy.cdm.model.taxon.Taxon;
57
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
58
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
59
import eu.etaxonomy.cdm.test.integration.CdmIntegrationTest;
60

    
61
/**
62
 * This test class is an exhaustive testing ground for conversations (a.k.a long running sessions)
63
 * implemented in the CDM Library by the {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder ConversationHolder}.
64
 *
65
 * @author n.hoffmann
66
 *
67
 */
68
@Transactional(TransactionMode.DISABLED)
69
public class ConcurrentSessionTest extends CdmIntegrationTest {
70

    
71
    private static final Logger logger = Logger.getLogger(ConcurrentSessionTest.class);
72

    
73
    @SpringBeanByType
74
    private SessionFactory sessionFactory;
75

    
76
    @SpringBeanByType
77
    private PlatformTransactionManager transactionManager;
78

    
79
    @SpringBeanByType
80
    private ITaxonService taxonService;
81

    
82
    @SpringBeanByType
83
    private ITermService termService;
84

    
85
    @SpringBeanByType
86
    private IReferenceService referenceService;
87

    
88
    @SpringBeanByType
89
    private IDescriptionService descriptionService;
90

    
91
    @SpringBeanByType
92
    private DataSource dataSource;
93

    
94
    @SpringBeanByType
95
    private ITaxonDao taxonDao;
96

    
97
    private ConversationHolder conversationHolder1 = null;
98
    private ConversationHolder conversationHolder2 = null;
99
    private ConversationHolder conversationHolder3 = null;
100

    
101
    private DataSource targetDataSource;
102

    
103
    private final UUID taxonUuid1 = UUID.fromString("496b1325-be50-4b0a-9aa2-3ecd610215f2");
104
    private final UUID taxonUuid2 = UUID.fromString("822d98dc-9ef7-44b7-a870-94573a3bcb46");
105

    
106
    private final UUID referenceUuid1 = UUID.fromString("596b1325-be50-4b0a-9aa2-3ecd610215f2");
107
    private final UUID referenceUuid2 = UUID.fromString("ad4322b7-4b05-48af-be70-f113e46c545e");
108

    
109

    
110

    
111

    
112
    @Before
113
    public void setup(){
114

    
115
        targetDataSource = dataSource instanceof TransactionAwareDataSourceProxy ?
116
                ((TransactionAwareDataSourceProxy)dataSource).getTargetDataSource():
117
                dataSource;
118
    }
119

    
120
    @After
121
    public void tearDown(){
122
        if(conversationHolder1 != null) {
123
            conversationHolder1.close();
124
        }
125
        if(conversationHolder2 != null) {
126
            conversationHolder2.close();
127
        }
128
        if(conversationHolder3 != null) {
129
            conversationHolder3.close();
130
        }
131

    
132

    
133
    }
134

    
135
    /**
136
     * We want to know if the data really gets persisted.
137
     */
138
    @Test
139
    @DataSet("ConcurrentSessionTest.xml")
140
    public void testProofOfDataPersistency(){
141

    
142
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
143
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
144
        // first conversation
145
        conversationHolder1.bind();
146
        conversationHolder1.startTransaction();
147
        // get a taxon
148
        TaxonBase taxonBase = taxonService.find(taxonUuid1);
149
        // get a reference
150
        Reference reference = referenceService.find(referenceUuid2);
151
        // make sure
152
        assertNotSame("this reference should not be the taxons sec.", taxonBase.getSec(), reference);
153
        // set the reference as the taxons new sec
154
        taxonBase.setSec(reference);
155
        // save and commit
156
        taxonService.save(taxonBase);
157
        conversationHolder1.commit();
158

    
159

    
160
        // second conversation
161
        conversationHolder2.bind();
162
        conversationHolder2.startTransaction();
163
        // load the same taxon in a different session
164
        TaxonBase taxonBaseInSecondTransaction = taxonService.find(taxonUuid1);
165
        // load the reference
166
        Reference referenceInSecondTransaction = referenceService.find(referenceUuid2);
167
        // we assume that
168
        assertSame("The reference should be the sec now.", taxonBaseInSecondTransaction.getSec(), referenceInSecondTransaction);
169
        assertNotSame("The reference should not be the same object as in first transaction.", reference, referenceInSecondTransaction);
170
    }
171

    
172
    /**
173
     * Test the general possibility to open two sessions at the same time
174
     */
175
    @Test
176
    @DataSet("ConcurrentSessionTest.xml")
177
    public void testTwoSessions(){
178
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
179
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
180

    
181
        conversationHolder1.bind();
182
        int context1Count = taxonDao.count();
183

    
184
        conversationHolder2.bind();
185
        int context2Count = taxonDao.count();
186

    
187
        assertEquals("Both contexts should yield the same results(at least if " +
188
                "there where no write operations in between)", context1Count, context2Count);
189

    
190
    }
191

    
192
    /**
193
     * Getting the same taxon from two different sessions using the taxon dao.
194
     * However, the resulting objects should be equal but not be the same.
195
     */
196
    @Test
197
    @DataSet("ConcurrentSessionTest.xml")
198
    public void testTwoSessionsEqualTaxon(){
199
        conversationHolder1 = new ConversationHolder(dataSource, sessionFactory, transactionManager);
200
        conversationHolder2 = new ConversationHolder(dataSource, sessionFactory, transactionManager);
201

    
202
        conversationHolder1.bind();
203
        TaxonBase taxonBase1 = taxonDao.findByUuid(taxonUuid1);
204

    
205
        conversationHolder2.bind();
206
        TaxonBase taxonBase2 = taxonDao.findByUuid(taxonUuid1);
207

    
208
        assertEquals("The objects should be equal.", taxonBase1, taxonBase2);
209
        assertNotSame("The objects should be the same.", taxonBase1, taxonBase2);
210
    }
211

    
212
    /**
213
     * Getting the same taxon from two different sessions using the taxon service.
214
     * However, the resulting objects should be equal but not be the same.
215
     */
216
    @Test
217
    @DataSet("ConcurrentSessionTest.xml")
218
    public void testTwoSessionsEqualTaxonWithTaxonService(){
219
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
220
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
221

    
222
        conversationHolder1.bind();
223
        TaxonBase taxonBase1 = taxonService.find(taxonUuid1);
224

    
225
        conversationHolder2.bind();
226
        TaxonBase taxonBase2 = taxonService.find(taxonUuid1);
227

    
228

    
229
        assertEquals("The objects should be equal", taxonBase1, taxonBase2);
230
        assertNotSame("The objects should not be the same", taxonBase1, taxonBase2);
231
    }
232

    
233
    /**
234
     * Getting the same taxon from two different sessions using the taxon service.
235
     * However, the resulting objects should be equal but not be the same.
236
     */
237
    @Test
238
    @DataSet("ConcurrentSessionTest.xml")
239
    public void testTwoSessionsRemoveTaxonBaseTaxonService(){
240
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
241
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
242

    
243
        conversationHolder1.bind();
244
        TaxonBase taxonBase1 = taxonService.find(taxonUuid1);
245
        TaxonNameBase name = taxonBase1.getName();
246
        Synonym syn = Synonym.NewInstance(name, null);
247
        taxonService.save(syn);
248
        conversationHolder1.commit();
249
        Set<TaxonBase> taxonBases = taxonBase1.getName().getTaxonBases();
250
        name.removeTaxonBase(syn);
251
        taxonService.saveOrUpdate(taxonBase1);
252
        conversationHolder1.commit();
253
        conversationHolder2.bind();
254
        conversationHolder2.startTransaction();
255

    
256

    
257
        TaxonBase taxonBase2 = taxonService.find(taxonUuid1);
258
        taxonBases = taxonBase2.getName().getTaxonBases();
259

    
260
        assertEquals("There should be only one taxon left", taxonBases.size(), 1);
261
        assertNotSame("The objects should not be the same", taxonBase1, taxonBase2);
262
    }
263

    
264
    /**
265
     * Interveaving conversations to test session within and outside conversations.
266
     */
267
    @Test
268
    @DataSet("ConcurrentSessionTest.xml")
269
    public void interveaveConversations(){
270
        TaxonBase<?> taxonBase1 = taxonService.find(taxonUuid1);
271
        Session h4Session1 = taxonService.getSession();
272

    
273
        assertNull(TransactionSynchronizationManager.getResource(sessionFactory));
274

    
275
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
276
        SessionHolder sessionHolder1 = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
277
        Session session1 = sessionHolder1.getSession();
278
        assertNotSame("The sessions should not be the same", h4Session1, session1);
279
        TaxonBase<?> taxonBase2 = taxonService.find(taxonUuid1);
280
        SessionHolder sessionHolder2 = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
281
        Session session2 = sessionHolder2.getSession();
282
        assertEquals("The session holders should be equal", sessionHolder1, sessionHolder2);
283
        assertEquals("The sessions should be equal", session1, session2);
284
        conversationHolder1.close();
285

    
286
        h4Session1 = taxonService.getSession();
287
        assertNotSame("The sessions should not be the same", h4Session1, session2);
288
        TaxonBase<?> taxonBase3 = taxonService.find(taxonUuid1);
289
        Session h4Session2 = taxonService.getSession();
290
        TaxonBase<?> taxonBase4 = taxonService.find(taxonUuid1);
291
        assertNotSame("The sessions should not be the same", h4Session1, h4Session2);
292

    
293
    }
294

    
295

    
296
    /**
297
     * Testing multiple transactions for the same conversation holder.
298
     */
299
    @Test
300
    @DataSet("ConcurrentSessionTest.xml")
301
    public void testLongConversationWithMultipleTransactions(){
302

    
303
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
304
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
305

    
306
        conversationHolder1.bind();
307
        TransactionStatus txStatusOne = conversationHolder1.startTransaction();
308
        TaxonBase taxonBase1 = taxonDao.findByUuid(taxonUuid1);
309
        TaxonNameBase taxonName1 = taxonBase1.getName();
310
        conversationHolder1.commit();
311

    
312

    
313
        conversationHolder1.bind();
314
        TransactionStatus txStatusTwo = conversationHolder1.startTransaction();
315
        TaxonNameBase taxonName2 = taxonBase1.getName();
316
        conversationHolder1.commit();
317

    
318
        assertNotSame(txStatusOne, txStatusTwo);
319
        assertSame("Two objects from different transactions should be the same, because we are still in " +
320
                "same persistence context", taxonName1, taxonName2);
321
    }
322

    
323
    /**
324
     * Switching sessions. Should not throw any exceptions
325
     */
326
    @Test
327
    @DataSet("ConcurrentSessionTest.xml")
328
    public void testSwitchSessions(){
329

    
330
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
331
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
332

    
333
        conversationHolder1.bind();
334
        //		TransactionStatus txStatusOne = transactionManager.getTransaction(definition);
335
        TaxonBase taxonBase1 = taxonService.find(taxonUuid1);
336

    
337
        conversationHolder2.bind();
338
        //		TransactionStatus txStatusTwo = transactionManager.getTransaction(definition );
339
        TaxonBase taxonBase2 = taxonService.find(taxonUuid1);
340

    
341
        conversationHolder1.bind();
342
        TaxonBase taxonBase3 = taxonService.find(taxonUuid2);
343

    
344

    
345
    }
346

    
347
    /**
348
     * Lazy loaded objects should be the same in different transactions within the
349
     * same conversation.
350
     */
351
    @Test
352
    @DataSet("ConcurrentSessionTest.xml")
353
    public void testReaccessingTheSameLazyLoadedObjectInTwoDifferentTransactions(){
354

    
355
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
356
        conversationHolder1.bind();
357
        TransactionStatus tx1 = conversationHolder1.startTransaction();
358
        TaxonBase t1 = taxonService.find(taxonUuid1);
359

    
360
        TaxonNameBase n1 = t1.getName();
361
        TransactionStatus tx2 = conversationHolder1.commit(true);
362

    
363
        TaxonNameBase n2 = t1.getName();
364

    
365
        assertSame(n1, n2);
366
        assertNotSame(tx1, tx2);
367

    
368
    }
369

    
370
    /**
371
     * Objects should be the same in different transactions within the
372
     * same conversation.
373
     */
374
    @Test
375
    @DataSet("ConcurrentSessionTest.xml")
376
    public void testReaccessingTheSameObjectInTwoDifferentTransactions(){
377

    
378
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
379
        conversationHolder1.bind();
380
        TransactionStatus tx1 = conversationHolder1.startTransaction();
381
        TaxonBase t1 = taxonService.find(taxonUuid1);
382

    
383
        TransactionStatus tx2 = conversationHolder1.commit(true);
384
        TaxonBase t2 = taxonService.find(taxonUuid1);
385

    
386
        assertSame(t1, t2);
387
        assertNotSame(tx1, tx2);
388

    
389
    }
390

    
391
    /**
392
     * Objects should be the same in the same transaction within the
393
     * same conversation.
394
     */
395
    @Test
396
    @DataSet("ConcurrentSessionTest.xml")
397
    public void testReaccessingTheSameObjectInSameTransaction(){
398

    
399
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
400
        conversationHolder1.bind();
401
        conversationHolder1.startTransaction();
402
        TaxonBase t1 = taxonService.find(taxonUuid1);
403

    
404
        // I wonder if this breaks
405
        TaxonBase t2 = taxonService.find(taxonUuid1);
406

    
407
        assertSame(t1, t2);
408

    
409
    }
410

    
411

    
412

    
413
    /**
414
     * Load an object, manipulate it and persist it by committing the transaction.
415
     * When reloading the same object we should still be in the same session
416
     */
417
    @Test
418
    @DataSet("ConcurrentSessionTest.xml")
419
    public void testSavingAndReaccessingTheSameObject(){
420

    
421
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
422
        TestConversationEnabled testConversationEnabled = new TestConversationEnabled();
423

    
424
        conversationHolder1.registerForDataStoreChanges(testConversationEnabled);
425

    
426
        conversationHolder1.bind();
427
        TransactionStatus txStatusOne = conversationHolder1.startTransaction();
428
        //		Session sessionFirstTransaction = conversationHolder11.getSession();
429
        TaxonBase taxonBase = taxonService.find(taxonUuid1);
430
        TaxonNameBase newTaxonName = BotanicalName.NewInstance(null);
431

    
432
        conversationHolder1.bind();
433
        newTaxonName.addTaxonBase(taxonBase);
434

    
435
        conversationHolder1.bind();
436
        taxonService.save(taxonBase);
437
        conversationHolder1.commit();
438

    
439

    
440
        conversationHolder1.bind();
441
        TransactionStatus txStatusTwo = conversationHolder1.startTransaction();
442

    
443
        TaxonBase taxonBase2 = taxonService.find(taxonUuid1);
444
        conversationHolder1.commit();
445

    
446
        assertEquals("The taxa should be equal.", taxonBase, taxonBase2);
447

    
448
        assertEquals("The name objects should be the same.", taxonBase.getName(), taxonBase2.getName());
449

    
450
    }
451

    
452

    
453

    
454
    /**
455
     * We load the same taxon in two different sessions. The reference of the first
456
     * taxon gets manipulated and the taxon saved afterwards.  When trying to persist the other
457
     * taxon we would expect some form of exception.
458
     *
459
     */
460
    @Test(expected=HibernateSystemException.class)
461

    
462
    @DataSet("ConcurrentSessionTest.xml")
463

    
464
    public void testWhatHappensWhenEncounteringStaleData(){
465

    
466
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
467
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
468
        conversationHolder3 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
469

    
470
        conversationHolder1.bind();
471
        TransactionStatus txStatusOne = conversationHolder1.startTransaction();
472
        TaxonBase taxonBase1 = taxonService.find(taxonUuid1);
473

    
474

    
475
        conversationHolder2.bind();
476
        TransactionStatus txStatusTwo = conversationHolder2.startTransaction();
477
        TaxonBase taxonBase2 = taxonService.find(taxonUuid1);
478

    
479

    
480
        conversationHolder1.bind();
481
        Reference reference1 = referenceService.find(referenceUuid1);
482
        assertSame("This should be the sec", taxonBase1.getSec(), reference1);
483

    
484
        Reference reference2 = referenceService.find(referenceUuid2);
485
        taxonBase1.setSec(reference2);
486
        taxonService.save(taxonBase1);
487
        conversationHolder1.commit();
488

    
489
        conversationHolder2.bind();
490
        taxonBase2.setSec(reference1);
491
        taxonService.save(taxonBase2);
492
        conversationHolder2.commit();
493

    
494
        conversationHolder3.bind();
495
        TransactionStatus txStatusThree = conversationHolder3.startTransaction();
496
        TaxonBase taxonBase3 = taxonService.find(taxonUuid1);
497
        assertNull(taxonBase3.getSec());
498
    }
499

    
500

    
501

    
502
    /**
503
     * Persist data in two different , successive transactions from different conversations
504
     */
505
    @Test
506
    @DataSet("ConcurrentSessionTest.xml")
507
    public void testProofOfDataPersistencyNewTransactionModel(){
508

    
509
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
510
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
511
        // first conversation
512
        conversationHolder1.bind();
513
        conversationHolder1.startTransaction();
514
        // get a taxon
515
        TaxonBase taxonBase = taxonService.find(taxonUuid1);
516
        // get a reference
517
        Reference reference = referenceService.find(referenceUuid2);
518
        // make sure
519
        assertNotSame("this reference should not be the taxons sec.", taxonBase.getSec(), reference);
520
        // set the reference as the taxons new sec
521
        taxonBase.setSec(reference);
522
        // save and commit
523
        taxonService.save(taxonBase);
524
        conversationHolder1.commit(false);
525

    
526

    
527
        // second conversation
528
        conversationHolder2.bind();
529
        conversationHolder2.startTransaction();
530
        // load the same taxon in a different session
531
        TaxonBase taxonBaseInSecondTransaction = taxonService.find(taxonUuid1);
532
        // load the reference
533
        Reference referenceInSecondTransaction = referenceService.find(referenceUuid2);
534
        // we assume that
535
        assertSame("The reference should be the sec now.", taxonBaseInSecondTransaction.getSec(), referenceInSecondTransaction);
536
        assertNotSame("The reference should not be the same object as in first transaction.", reference, referenceInSecondTransaction);
537

    
538
    }
539

    
540
    /**
541
     * We manipulate an object in one session and see how these change get propagated to the other session.
542
     */
543

    
544
    @Test
545
    @DataSet("ConcurrentSessionTest.xml")
546
    public void testIfDataGetsPersistedWhenFiringCommit(){
547

    
548
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
549
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
550
        // first conversation
551
        conversationHolder1.bind();
552
        conversationHolder1.startTransaction();
553
        // get a taxon
554
        TaxonBase taxonBase = taxonService.find(taxonUuid1);
555
        // get a reference
556
        Reference reference = referenceService.find(referenceUuid2);
557
        // make sure
558
        assertTrue(! taxonBase.getSec().equals(reference));
559
        assertNotSame("this reference should not be the taxons sec.", taxonBase.getSec(), reference);
560
        // set the reference as the taxons new sec
561
        taxonBase.setSec(reference);
562
        // save and commit
563
        taxonService.save(taxonBase);
564

    
565
        // second conversation
566
        conversationHolder2.bind();
567
        conversationHolder2.startTransaction();
568
        // load the same taxon in a different session, since we did not commit the first transaction,
569
        // the reference change did not make its way to the database and the references should be distinct
570
        TaxonBase taxonBaseInSecondTransaction = taxonService.find(taxonUuid1);
571
        assertFalse(taxonBase.getSec().equals(taxonBaseInSecondTransaction.getSec()));
572

    
573
        // commit the first transaction
574
        conversationHolder1.bind();
575
        conversationHolder1.commit();
576

    
577
        // as the taxonBaseInSecondTransaction still has it's data from before the first transaction was committed
578
        // we assume that the references are still not equal
579
        assertFalse(taxonBase.getSec().equals(taxonBaseInSecondTransaction.getSec()));
580

    
581
        // we call a refresh on the taxonBaseInSecondTransaction to synchronize its state with the database
582
        conversationHolder2.bind();
583
        taxonService.refresh(taxonBaseInSecondTransaction);
584

    
585
        // the objects should now be equal
586

    
587
        assertTrue(taxonBase.getSec().equals(taxonBaseInSecondTransaction.getSec()));
588
    }
589

    
590
    /**
591
     * Testing multiple transaction in a single conversation (session)
592
     */
593
    @Test
594
    @DataSet("ConcurrentSessionTest.xml")
595
    public void testMultipleTransactionsInOneSession() {
596

    
597
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
598
        conversationHolder1.bind();
599
        conversationHolder1.startTransaction();
600
        TaxonBase taxonBase1 = taxonService.find(taxonUuid1);
601
        conversationHolder1.commit();
602

    
603
        conversationHolder1.startTransaction();
604
        TaxonBase taxonBase2 = taxonService.find(taxonUuid1);
605
        conversationHolder1.commit();
606

    
607
        assertSame("The objects should be the same", taxonBase1, taxonBase2);
608
        assertEquals("The objects should be equal", taxonBase1, taxonBase2);
609
    }
610

    
611
    /**
612
     * Testing multiple transaction in a multiple conversations (session)
613
     */
614
    @Test
615
    @DataSet("ConcurrentSessionTest.xml")
616
    public void testMultipleTransactionsInMultipleSessions(){
617

    
618
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
619
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
620
        conversationHolder3 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
621

    
622
        conversationHolder1.bind();
623
        conversationHolder1.startTransaction();
624

    
625
        conversationHolder2.bind();
626
        conversationHolder2.startTransaction();
627

    
628
        conversationHolder3.bind();
629
        conversationHolder3.startTransaction();
630
    }
631

    
632
    /**
633
     * Testing both the saving of a newly created and an already existing DefinedTerm
634
     * in different sessions.
635
     */
636
    @Test
637
    @DataSet("ConcurrentSessionTest.xml")
638
    public void testSavingTheSameObjectInTwoSessions(){
639
        //new session
640
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
641
        //save newly created DefinedTerm
642
        DefinedTerm term = DefinedTerm.NewKindOfUnitInstance("XXXkindofUnitXXX", "XXXlabelXXX", "XXXlabelAbbrevXXX");
643
        persistTerm(term, termService, conversationHolder1);
644
        conversationHolder1.commit();
645

    
646
        //new session
647
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
648
        conversationHolder1.startTransaction();
649
        conversationHolder1.bind();
650

    
651
        //save newly createy term from last session
652
        persistTerm(term, termService, conversationHolder1);
653
        conversationHolder1.commit();
654

    
655
        //new session
656
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
657
        conversationHolder1.startTransaction();
658
        conversationHolder1.bind();
659

    
660
        //save already existing DefinedTerm
661
        NamedArea namedArea = NamedArea.ANTARCTICA();
662
        persistTerm(term, termService, conversationHolder1);
663
        conversationHolder1.commit();
664

    
665
        //new session
666
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
667
        conversationHolder1.startTransaction();
668
        conversationHolder1.bind();
669

    
670
        //save already existing term from last session
671
        persistTerm(namedArea, termService, conversationHolder1);
672
        conversationHolder1.commit();
673
    }
674

    
675
    private void persistTerm(DefinedTermBase<?> term, ITermService termService, ConversationHolder conversation){
676
        if(term!=null){
677
            //if the term does not exist in the DB save it
678
            if(termService.find(term.getUuid())==null){
679
                termService.saveOrUpdate(term);
680
            }
681
            //if it does exist but is not bound to the current session re-load and save it
682
            else if(!conversation.getSession().contains(term)){
683
                term = termService.load(term.getUuid());
684
                termService.saveOrUpdate(term);
685
            }
686
        }
687
    }
688

    
689
    /**
690
     * Testing inserting new data.
691
     */
692
    @Test
693
    @DataSet("ConcurrentSessionTest.xml")
694
    public void testInsert(){
695

    
696
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
697
        TestConversationEnabled testConversationEnabled = new TestConversationEnabled();
698

    
699
        conversationHolder1.registerForDataStoreChanges(testConversationEnabled);
700

    
701
        conversationHolder1.bind();
702
        conversationHolder1.startTransaction();
703
        TaxonBase newTaxon = Taxon.NewInstance(null, null);
704
        taxonService.save(newTaxon);
705
        conversationHolder1.commit();
706
    }
707

    
708
    /**
709
     * Testing updating already existing data.
710
     */
711
    @Test
712
    @DataSet("ConcurrentSessionTest.xml")
713
    public void testUpdate(){
714

    
715
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
716

    
717
        TestConversationEnabled testConversationEnabled = new TestConversationEnabled();
718

    
719
        conversationHolder1.registerForDataStoreChanges(testConversationEnabled);
720

    
721
        conversationHolder1.bind();
722
        conversationHolder1.startTransaction();
723
        TaxonBase taxonBase1 = taxonService.find(taxonUuid1);
724
        Reference reference = referenceService.find(referenceUuid2);
725
        taxonBase1.setSec(reference);
726
        taxonService.save(taxonBase1);
727
        conversationHolder1.commit();
728
    }
729

    
730
    /**
731
     * Switch sessions randomly and expect retrieved objects to be same but not equal.
732
     */
733
    @Test
734
    @DataSet("ConcurrentSessionTest.xml")
735
    public void testMultipleSessionSwitching(){
736

    
737
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
738
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
739
        conversationHolder3 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
740

    
741
        conversationHolder1.bind();
742
        TaxonBase taxon1 = taxonService.find(taxonUuid1);
743
        assertSame(conversationHolder1.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
744

    
745
        conversationHolder2.bind();
746
        TaxonBase taxon2 = taxonService.find(taxonUuid2);
747
        assertSame(conversationHolder2.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
748

    
749
        conversationHolder3.bind();
750
        TaxonBase taxon3 = taxonService.find(taxonUuid1);
751
        assertSame(conversationHolder3.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
752

    
753
        conversationHolder2.bind();
754
        TaxonNameBase name2 = taxon2.getName();
755
        assertSame(conversationHolder2.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
756

    
757
        conversationHolder3.bind();
758
        TaxonNameBase name3 = taxon3.getName();
759
        assertSame(conversationHolder3.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
760

    
761
        // Lazy loading somehow works without binding the session first
762
        TaxonNameBase name1 = taxon1.getName();
763
        assertNotSame(name1, name3);
764
        assertEquals(name1, name3);
765
        assertNotSame(conversationHolder1.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
766

    
767
    }
768

    
769
    /**
770
     * Switch sessions with multiple transactions randomly and expect retrieved objects to be same but not equal.
771
     */
772
    @Test
773
    @DataSet("ConcurrentSessionTest.xml")
774
    public void testMultipleSessionSwitchingInTransactions(){
775

    
776
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
777
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
778
        conversationHolder3 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
779

    
780
        conversationHolder1.bind();
781
        conversationHolder1.startTransaction();
782
        TaxonBase taxon1 = taxonService.find(taxonUuid1);
783
        assertSame(conversationHolder1.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
784
        conversationHolder1.commit();
785

    
786
        conversationHolder2.bind();
787
        conversationHolder2.startTransaction();
788
        TaxonBase taxon2 = taxonService.find(taxonUuid2);
789
        assertSame(conversationHolder2.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
790
        conversationHolder2.commit();
791

    
792
        conversationHolder3.bind();
793
        conversationHolder3.startTransaction();
794
        TaxonBase taxon3 = taxonService.find(taxonUuid1);
795
        assertSame(conversationHolder3.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
796
        conversationHolder3.commit();
797

    
798
        conversationHolder2.bind();
799
        conversationHolder2.startTransaction();
800
        TaxonNameBase name2 = taxon2.getName();
801
        assertSame(conversationHolder2.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
802
        conversationHolder2.commit();
803

    
804
        conversationHolder3.bind();
805
        conversationHolder3.startTransaction();
806
        TaxonNameBase name3 = taxon3.getName();
807
        assertSame(conversationHolder3.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
808

    
809
        // Lazy loading somehow works without binding the session first
810
        TaxonNameBase name1 = taxon1.getName();
811
        assertNotSame(name1, name3);
812
        assertEquals(name1, name3);
813
        assertNotSame(conversationHolder1.getSession(), conversationHolder1.getSessionFactory().getCurrentSession());
814

    
815
    }
816

    
817

    
818
    /**
819
     * Testing of locking mechanism
820
     */
821
    @Test
822
    @DataSet("ConcurrentSessionTest.xml")
823
    public void testLocking(){
824

    
825
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
826
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
827
        conversationHolder1.bind();
828
        // first session, first transaction
829
        conversationHolder1.startTransaction();
830
        TaxonBase taxonBase = taxonService.find(taxonUuid1);
831
        // leave the first transaction without committing it
832

    
833
        // start a new session with a new transaction
834
        conversationHolder2.bind();
835
        conversationHolder2.startTransaction();
836
        TaxonBase taxonBase2 = taxonService.find(taxonUuid1);
837
        taxonBase.setSec(null);
838
        conversationHolder2.commit();
839
        // transaction of the second session got committed
840

    
841
        // return to the first session and commit its transaction
842
        conversationHolder1.bind();
843
        conversationHolder1.commit();
844

    
845
        conversationHolder1.startTransaction();
846
        conversationHolder1.lock(taxonBase, LockMode.READ);
847

    
848
    }
849

    
850
    @Ignore
851
    @Test
852
    @DataSet("ConcurrentSessionTest.xml")
853
    public void testSaveOrUpdate() {
854
        // this test deals with calling a save or saveOrUpdate after binding a conversation holder
855

    
856
        // initialise the conversation holders
857
        conversationHolder1 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
858
        conversationHolder2 = new ConversationHolder(targetDataSource, sessionFactory, transactionManager);
859

    
860
        // bind the first one
861
        conversationHolder1.bind();
862
        // This is the call that makes sure that the 'taxonService.saveOrUpdate(taxonBase1);' call
863
        // later on does not flush the entire session.
864
        // The method to look at is 'processCommit(DefaultTransactionStatus status)' from
865
        // the class 'org.springframework.transaction.support.AbstractPlatformTransactionManager'
866
        // Without the following call the 'doCommit' method is called if 'status.isNewTransaction()' is true
867
        conversationHolder1.startTransaction();
868

    
869
        // load two taxon base objects
870
        TaxonBase taxonBase1 = taxonService.find(taxonUuid1);
871
        TaxonBase taxonBase2 = taxonService.find(taxonUuid2);
872

    
873
        // update taxon base object 1
874
        String titleCache1 = taxonBase1.getTitleCache();
875
        logger.info("Taxon 1 Title Cache : " + titleCache1);
876
        taxonBase1.setTitleCache(titleCache1 + "updated", false);
877
        logger.info("Taxon 1 Title Cache Updated: " + taxonBase1.getTitleCache());
878

    
879
        // update taxon base object 2
880
        String titleCache2 = taxonBase2.getTitleCache();
881
        logger.info("Taxon 2 Title Cache : " + titleCache2);
882
        taxonBase2.setTitleCache(titleCache2 + "updated", false);
883
        logger.info("Taxon 2 Title Cache Updated: " + taxonBase2.getTitleCache());
884

    
885
        // NOTE : Without the earlier 'conversationHolder1.startTransaction()' call, the
886
        // saveOrUpdate method will flush the entire session, in this case both
887
        // taxonBase1 and taxonBase2
888
        taxonService.saveOrUpdate(taxonBase1);
889

    
890
        conversationHolder2.bind();
891

    
892
        // Including the 'conversationHolder1.startTransaction()' call solves the
893
        // problem of the entire session being flushed, but throws the exception,
894
        // 'org.springframework.transaction.IllegalTransactionStateException:
895
        // Pre-bound JDBC Connection found! HibernateTransactionManager does
896
        // not support running within DataSourceTransactionManager if told to manage
897
        // the DataSource itself. It is recommended to use a single HibernateTransactionManager
898
        // for all transactions on a single DataSource, no matter whether Hibernate or JDBC access'.
899
        TaxonBase taxonBase1updated = taxonService.find(taxonUuid1);
900
        logger.info("Title Cache 1 New  Session: " + taxonBase1updated.getTitleCache());
901

    
902
        TaxonBase taxonBase2updated = taxonService.find(taxonUuid2);
903
        logger.info("Title Cache 2 New Session: " + taxonBase2updated.getTitleCache());
904

    
905
    }
906

    
907
    /* (non-Javadoc)
908
     * @see eu.etaxonomy.cdm.test.integration.CdmIntegrationTest#createTestData()
909
     */
910
    @Override
911
    public void createTestDataSet() throws FileNotFoundException {
912
        // TODO Auto-generated method stub
913

    
914
    }
915

    
916

    
917

    
918

    
919
}
(1-1/11)