Project

General

Profile

Download (15.6 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.description.DescriptionElementSource;
30
import eu.etaxonomy.cdm.model.description.Feature;
31
import eu.etaxonomy.cdm.model.description.TaxonDescription;
32
import eu.etaxonomy.cdm.model.description.TextData;
33
import eu.etaxonomy.cdm.model.name.IBotanicalName;
34
import eu.etaxonomy.cdm.model.name.INonViralName;
35
import eu.etaxonomy.cdm.model.name.TaxonName;
36
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
37
import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
38
import eu.etaxonomy.cdm.model.reference.Reference;
39
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
40
import eu.etaxonomy.cdm.model.taxon.Taxon;
41
import eu.etaxonomy.cdm.test.integration.CdmIntegrationTest;
42

    
43
/**
44
 * This test class tries to describe how hibernate works with objects (save, update, merge).
45
 *
46
 * @author cmathew
47
 * @since 17 Sep 2014
48
 */
49
public class HandlingCdmEntitiesTest extends CdmIntegrationTest {
50

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

    
54
    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";
55
    private static final String LIE_NOSESSION = "could not initialize proxy - no Session";
56

    
57
    private static final UUID taxonUuid = UUID.fromString("23c35977-01b5-452c-9225-ecce440034e0");
58

    
59
    @SpringBeanByType
60
    private IReferenceService referenceService;
61

    
62
    @SpringBeanByType
63
    private IAnnotationService annotationService;
64

    
65
    @SpringBeanByType
66
    private ITaxonService taxonService;
67

    
68
    @SpringBeanByType
69
    private IAgentService agentService;
70

    
71
    @SpringBeanByType
72
    private ICommonService commonService;
73

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
146
        // ---- loading taxon with findTaxonByUuid ----
147

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

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

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

    
159
        TaxonName nvn = CdmBase.deproxy(taxon.getName());
160

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

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

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

    
173
        team.setProtectedTitleCache(false);
174

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

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

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

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

    
196
        team.setProtectedTitleCache(true);
197
        team.setProtectedCollectorTitleCache(true);
198
        team.setProtectedNomenclaturalTitleCache(true);
199
        taxonService.update(taxon);
200

    
201
    }
202

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

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

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

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

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

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

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

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

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

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

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

    
240
        // ---- loading taxon with findTaxonByUuid ----
241

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

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

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

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

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

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

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

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

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

    
274

    
275
        IBotanicalName name = TaxonNameFactory.NewBotanicalInstance(null, "Pinus Alba", null, null, null, null, null, null,  null);
276
        name.setCombinationAuthorship(combAuthor);
277

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

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

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

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

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

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

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

    
302
    }
303

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

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

    
315
        // ---- loading taxon with find (uuid) ----
316

    
317
        Taxon taxon = (Taxon)taxonService.find(taxonUuid);
318

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

    
323
        taxonService.merge(taxon);
324

    
325
        // ---- loading taxon with find (id) ----
326

    
327
        taxon = commonService.find(taxon.getClass(), taxon.getId());
328

    
329
        taxonService.merge(taxon);
330

    
331
        // ---- loading taxon with findTaxonByUuid ----
332

    
333
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
334
                "name"
335
        });
336

    
337
        // loading the taxon with its taxon name object pre-initialized
338
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
339

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

    
344
        INonViralName nvn = CdmBase.deproxy(taxon.getName());
345

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

    
352
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorship(),Team.class);
353

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

    
359

    
360
        taxonService.merge(taxon);
361

    
362
    }
363

    
364

    
365
    @Test
366
    public final void testTaxonDescriptionMerge() {
367

    
368
        IBotanicalName name = TaxonNameFactory.NewBotanicalInstance(null, "Abies alba", null, null, null, null, null, null, null);
369
        Taxon taxon = Taxon.NewInstance(name, null);
370
        TaxonDescription description = TaxonDescription.NewInstance(taxon);
371

    
372
        TextData textData = TextData.NewInstance();
373

    
374
        textData.setFeature(Feature.ECOLOGY());
375
        description.addElement(textData);
376

    
377
        DescriptionElementSource descriptionElementSource = DescriptionElementSource.NewInstance(OriginalSourceType.PrimaryTaxonomicSource);
378

    
379
        textData.addSource(descriptionElementSource);
380

    
381
        taxonService.merge(taxon);
382
    }
383

    
384
    @Test  //testing of bidirectionality of supplemental data #5743
385
    public final void testReferenceWithAnnotationMerge() {
386

    
387
        Reference ref = ReferenceFactory.newBook();
388

    
389
        ref.addAnnotation(Annotation.NewDefaultLanguageInstance("ref"));
390

    
391
        referenceService.merge(ref);
392
    }
393

    
394
    @Test //testing of bidirectionality of supplemental data #5743
395
    public final void testAnnotationMerge() {
396

    
397
        Reference ref = ReferenceFactory.newBook();
398

    
399
        Annotation annotation = Annotation.NewDefaultLanguageInstance("anno");
400
        ref.addAnnotation(annotation);
401

    
402
        annotationService.merge(annotation);
403
    }
404
}
(9-9/37)