Project

General

Profile

Download (15.7 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2014 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
package eu.etaxonomy.cdm.api.service;
10

    
11
import java.util.Arrays;
12
import java.util.List;
13
import java.util.UUID;
14

    
15
import org.apache.log4j.Logger;
16
import org.hibernate.LazyInitializationException;
17
import org.junit.Assert;
18
import org.junit.Ignore;
19
import org.junit.Test;
20
import org.unitils.database.annotations.Transactional;
21
import org.unitils.database.util.TransactionMode;
22
import org.unitils.dbunit.annotation.DataSet;
23
import org.unitils.spring.annotation.SpringBeanByType;
24

    
25
import eu.etaxonomy.cdm.model.agent.Person;
26
import eu.etaxonomy.cdm.model.agent.Team;
27
import eu.etaxonomy.cdm.model.common.Annotation;
28
import eu.etaxonomy.cdm.model.common.CdmBase;
29
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
30
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
31
import eu.etaxonomy.cdm.model.description.Feature;
32
import eu.etaxonomy.cdm.model.description.TaxonDescription;
33
import eu.etaxonomy.cdm.model.description.TextData;
34
import eu.etaxonomy.cdm.model.name.BotanicalName;
35
import eu.etaxonomy.cdm.model.name.NonViralName;
36
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
37
import eu.etaxonomy.cdm.model.reference.Reference;
38
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
39
import eu.etaxonomy.cdm.model.taxon.Taxon;
40
import eu.etaxonomy.cdm.test.integration.CdmIntegrationTest;
41

    
42
/**
43
 * This test class tries to describe how hibernate works with objects (save, update, merge).
44
 *
45
 * @author cmathew
46
 * @date 17 Sep 2014
47
 *
48
 */
49

    
50
public class HandlingCdmEntitiesTest extends CdmIntegrationTest {
51

    
52
    @SuppressWarnings("unused")
53
	private static final Logger logger = Logger.getLogger(CommonServiceImplTest.class);
54

    
55
    private static final String LIE_TEAMMEMBERS_NOSESSION = "failed to lazily initialize a collection of role: eu.etaxonomy.cdm.model.agent.Team.teamMembers, could not initialize proxy - no Session";
56
    private static final String LIE_NOSESSION = "could not initialize proxy - no Session";
57

    
58
    @SpringBeanByType
59
    private IReferenceService referenceService;
60

    
61
    @SpringBeanByType
62
    private IAnnotationService annotationService;
63

    
64
    @SpringBeanByType
65
    private ITaxonService taxonService;
66

    
67
    @SpringBeanByType
68
    private IAgentService agentService;
69

    
70
    @SpringBeanByType
71
    private ICommonService commonService;
72

    
73
    public static final String[] includeTables = new String[]{
74
        "TAXONBASE",
75
        "TAXONNAMEBASE",
76
        "AGENTBASE",
77
        "AGENTBASE_AGENTBASE",
78
        "HOMOTYPICALGROUP"
79
    };
80

    
81
    @Override
82
    @Ignore
83
    @Test
84
    @Transactional(TransactionMode.DISABLED)
85
    public final void createTestDataSet() {
86
        Team combAuthor = Team.NewTitledInstance("Avengers", "Avengers");
87
        combAuthor.addTeamMember(Person.NewTitledInstance("Iron Man"));
88
        BotanicalName name = TaxonNameBase.NewBotanicalInstance(null, "Abies alba", null, null, null, null, null, null, null);
89
        name.setCombinationAuthorship(combAuthor);
90
        Taxon taxon = Taxon.NewInstance(name, null);
91
        UUID taxonUuid = taxonService.save(taxon).getUuid();
92
        printDataSetWithNull(System.out,false,null,includeTables);
93
    }
94

    
95
    @Test
96
    @DataSet
97
    @Transactional(TransactionMode.DISABLED)
98
    public void testNonTransactionalUpdateForExistingTaxon() {
99
        // this method tests the updating of a 'truely' detached object which
100
        // attempts to initialize a lazy loaded proxy object while trying to
101
        // update the same.
102

    
103
        // setting the TransactionMode for this method to DISABLED is important
104
        // to ensure that transaction boundaries remain at the service layer calls
105
        // to simulate detachment and update of the persisted object
106

    
107
        UUID taxonUuid = UUID.fromString("23c35977-01b5-452c-9225-ecce440034e0");
108

    
109
        // ---- loading taxon with find (uuid) ----
110

    
111
        Taxon taxon = (Taxon)taxonService.find(taxonUuid);
112

    
113
        // at this point the taxonNew object is detached and all lazy loaded proxy
114
        // objects in the object graph (including teamMembers) will have values of
115
        // initialized=false and session=null
116

    
117
        // since name is lazy loaded the call to getName should fail
118
        try {
119
            CdmBase.deproxy(taxon.getName(),NonViralName.class);
120
            Assert.fail("LazyInitializationException not thrown for lazy loaded Taxon.name");
121
        } catch(LazyInitializationException lie) {
122

    
123
            if(!lie.getMessage().equals(LIE_NOSESSION)) {
124
                Assert.fail("LazyInitializationException thrown, but not : " + LIE_NOSESSION);
125
            }
126
        }
127

    
128
        // ---- loading taxon with find (id) ----
129

    
130
        taxon = (Taxon)commonService.find(taxon.getClass(), taxon.getId());
131

    
132
        // at this point the taxonNew object is detached and all lazy loaded proxy
133
        // objects in the object graph (including teamMembers) will have values of
134
        // initialized=false and session=null
135

    
136
        // since name is lazy loaded the call to getName should fail
137
        try {
138
            CdmBase.deproxy(taxon.getName(),NonViralName.class);
139
            Assert.fail("LazyInitializationException not thrown for lazy loaded Taxon.name");
140
        } catch(LazyInitializationException lie) {
141

    
142
            if(!lie.getMessage().equals(LIE_NOSESSION)) {
143
                Assert.fail("LazyInitializationException thrown, but not : " + LIE_NOSESSION);
144
            }
145
        }
146

    
147
        // ---- loading taxon with findTaxonByUuid ----
148

    
149
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
150
                "name"
151
        });
152

    
153
        // loading the taxon with its taxon name object pre-initialized
154
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
155

    
156
        // at this point the taxonNew object is detached and all lazy loaded proxy
157
        // objects in the object graph (including teamMembers) will have values of
158
        // initialized=false and session=null
159

    
160
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
161

    
162
        // normally this call should throw a lazy loading exception since
163
        // the combinationAuthorship object is not initialized, but
164
        // the findTaxonByUuid performs this initialization (via the
165
        // AdvancedBeanInitializer) since the combinationAuthorship
166
        // is annotated with CacheUpdate
167

    
168
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorship(),Team.class);
169

    
170
        // setting the protected title cache to false to ensure that
171
        // TeamDefaultCacheStrategy.getTitleCache is called, which in turn tries
172
        // to initialize the teamMembers persistent collection which fails
173

    
174
        team.setProtectedTitleCache(false);
175

    
176
        try {
177
            taxonService.update(taxon);
178
            Assert.fail("LazyInitializationException not thrown for lazy loaded Team.teamMembers");
179
        } catch(LazyInitializationException lie) {
180

    
181
            if(!lie.getMessage().equals(LIE_TEAMMEMBERS_NOSESSION)) {
182
                Assert.fail("LazyInitializationException thrown, but not : " + LIE_TEAMMEMBERS_NOSESSION);
183
            }
184
        }
185

    
186
        // the above fails due to the fact that hibernate does not resolve lazy
187
        // loading on a detached object until the object is persisted. The attempt
188
        // to initialize teamMembers before the object graph is persisted means that
189
        // the current session is not yet attached to the proxy objects and hibernate
190
        // tries to use the existing session set in the teamMembers object which is
191
        // null, leading to the exception
192

    
193
        // setting the protected title cache to true to ensure that
194
        // TeamDefaultCacheStrategy.getTitleCache is not called, implying
195
        // that the teamMembers are not initialized, so no exception is thrown
196

    
197
        team.setProtectedTitleCache(true);
198
        taxonService.update(taxon);
199

    
200
    }
201

    
202
    @Test
203
    @DataSet
204
    public void testTransactionalUpdateAfterFindTaxonByUuidForExistingTaxon() {
205
        // this method tests the updating of a detached object inside a single
206
        // transaction.
207

    
208
        // this method is transactional, meaning that a transaction is started
209
        // at the start of the method and ends only with the end of the method
210

    
211
        // since this method is transactional, any object initialized within this method
212
        // will have a valid session attached to any lazy loaded proxy objects
213
        // in the object graph (including teamMembers)
214

    
215
        UUID taxonUuid = UUID.fromString("23c35977-01b5-452c-9225-ecce440034e0");
216

    
217
        // ---- loading taxon with find (uuid) ----
218

    
219
        Taxon taxon = (Taxon)taxonService.find(taxonUuid);
220

    
221
        // at this point the taxonNew object is detached and all lazy loaded proxy
222
        // objects in the object graph (including teamMembers) will have a new
223
        // session attached implying that all the following calls will succeed
224

    
225
        NonViralName nvn =  CdmBase.deproxy(taxon.getName(),NonViralName.class);
226
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorship(),Team.class);
227
        taxonService.update(taxon);
228

    
229
        // ---- loading taxon with find (id) ----
230

    
231
        taxon = (Taxon)commonService.find(taxon.getClass(), taxon.getId());
232

    
233
        // at this point the taxonNew object is detached and all lazy loaded proxy
234
        // objects in the object graph (including teamMembers) will have a new
235
        // session attached implying that all the following calls will succeed
236

    
237
        nvn =  CdmBase.deproxy(taxon.getName(),NonViralName.class);
238
        team = CdmBase.deproxy(nvn.getCombinationAuthorship(),Team.class);
239
        taxonService.update(taxon);
240

    
241
        // ---- loading taxon with findTaxonByUuid ----
242

    
243
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
244
                "name"
245
        });
246

    
247
        // loading the taxon with its taxon name object pre-initialized
248
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
249

    
250
        nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
251
        team = CdmBase.deproxy(nvn.getCombinationAuthorship(),Team.class);
252

    
253
        // since a valid session is now attached to teamMembers, forcing the
254
        // initializing of the teamMembers (in TeamDefaultCacheStrategy.getTitleCache)
255
        // by setting the protected title cache to false does not throw an exception
256
        // because the teamMember persistent collection now has a valid session,
257
        // which is used to initialize the persistent collection
258

    
259
        team.setProtectedTitleCache(false);
260
        taxonService.update(taxon);
261
    }
262

    
263
    @Test
264
    @Transactional(TransactionMode.DISABLED)
265
    public void testNonTransactionalUpdateForNewTaxon() {
266

    
267
        // this test is only to prove that the update problem occurs
268
        // also for newly created objects (as expected)
269

    
270
        // create / save new taxon with name and author team with team member
271

    
272
        Team combAuthor = Team.NewTitledInstance("X-Men", "X-Men");
273
        combAuthor.addTeamMember(Person.NewTitledInstance("Wolverine"));
274

    
275

    
276
        BotanicalName name = TaxonNameBase.NewBotanicalInstance(null, "Pinus Alba", null, null, null, null, null, null,  null);
277
        name.setCombinationAuthorship(combAuthor);
278

    
279
        Taxon taxon = Taxon.NewInstance(name, null);
280

    
281
        UUID taxonUuid = taxonService.save(taxon).getUuid();
282

    
283
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
284
                "name"
285
        });
286

    
287
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
288

    
289
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
290
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorship(),Team.class);
291
        team.setProtectedTitleCache(false);
292

    
293
        try {
294
            taxonService.update(taxon);
295
            Assert.fail("LazyInitializationException not thrown for lazy loaded Team.teamMembers");
296
        } catch(LazyInitializationException lie) {
297

    
298
            if(!lie.getMessage().equals(LIE_TEAMMEMBERS_NOSESSION)) {
299
                Assert.fail("LazyInitializationException thrown, but not : " + LIE_TEAMMEMBERS_NOSESSION);
300
            }
301
        }
302

    
303
    }
304

    
305
    @Test
306
    @DataSet
307
    @Transactional(TransactionMode.DISABLED)
308
    public void testNonTransactionalMergeForExistingTaxon() {
309
        // this method tests the updating of a 'truely' detached object
310
        // using merge
311

    
312
        // setting the TransactionMode for this method to DISABLED is important
313
        // to ensure that transaction boundaries remain at the service layer calls
314
        // to simulate detachment and update of the persisted object
315

    
316
        UUID taxonUuid = UUID.fromString("23c35977-01b5-452c-9225-ecce440034e0");
317

    
318
        // ---- loading taxon with find (uuid) ----
319

    
320
        Taxon taxon = (Taxon)taxonService.find(taxonUuid);
321

    
322
        // at this point the taxonNew object is detached and all lazy loaded proxy
323
        // objects in the object graph (including teamMembers) will have values of
324
        // initialized=false and session=null
325

    
326
        taxonService.merge(taxon);
327

    
328
        // ---- loading taxon with find (id) ----
329

    
330
        taxon = (Taxon)commonService.find(taxon.getClass(), taxon.getId());
331

    
332
        taxonService.merge(taxon);
333

    
334
        // ---- loading taxon with findTaxonByUuid ----
335

    
336
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
337
                "name"
338
        });
339

    
340
        // loading the taxon with its taxon name object pre-initialized
341
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
342

    
343
        // at this point the taxonNew object is detached and all lazy loaded proxy
344
        // objects in the object graph (including teamMembers) will have values of
345
        // initialized=false and session=null
346

    
347
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
348

    
349
        // normally this call should throw a lazy loading exception since
350
        // the combinationAuthorship object is not initialized, but
351
        // the findTaxonByUuid performs this initialization (via the
352
        // AdvancedBeanInitializer) since the combinationAuthorship
353
        // is annotated with CacheUpdate
354

    
355
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorship(),Team.class);
356

    
357
        // setting the protected title cache to false to ensure that
358
        // TeamDefaultCacheStrategy.getTitleCache is called, which in turn tries
359
        // to initialize the teamMembers persistent collection which fails
360
        team.setProtectedTitleCache(false);
361

    
362

    
363
        taxonService.merge(taxon);
364

    
365
    }
366

    
367

    
368
    @Test
369
    public final void testTaxonDescriptionMerge() {
370

    
371
        BotanicalName name = TaxonNameBase.NewBotanicalInstance(null, "Abies alba", null, null, null, null, null, null, null);
372
        Taxon taxon = Taxon.NewInstance(name, null);
373
        TaxonDescription description = TaxonDescription.NewInstance(taxon);
374

    
375
        TextData textData = TextData.NewInstance();
376

    
377
        textData.setFeature(Feature.ECOLOGY());
378
        description.addElement(textData);
379

    
380
        DescriptionElementSource descriptionElementSource = DescriptionElementSource.NewInstance(OriginalSourceType.PrimaryTaxonomicSource);
381

    
382
        textData.addSource(descriptionElementSource);
383

    
384
        taxonService.merge(taxon);
385
    }
386

    
387
    @Test  //testing of bidirectionality of supplemental data #5743
388
    public final void testReferenceWithAnnotationMerge() {
389

    
390
        Reference ref = ReferenceFactory.newBook();
391

    
392
        ref.addAnnotation(Annotation.NewDefaultLanguageInstance("ref"));
393

    
394
        referenceService.merge(ref);
395
    }
396

    
397
    @Test //testing of bidirectionality of supplemental data #5743
398
    public final void testAnnotationMerge() {
399

    
400
        Reference ref = ReferenceFactory.newBook();
401

    
402
        Annotation annotation = Annotation.NewDefaultLanguageInstance("anno");
403
        ref.addAnnotation(annotation);
404

    
405
        annotationService.merge(annotation);
406
    }
407
}
(9-9/33)