Project

General

Profile

Download (15.5 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
 */
50

    
51
public class HandlingCdmEntitiesTest extends CdmIntegrationTest {
52

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

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

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

    
61
    @SpringBeanByType
62
    private IReferenceService referenceService;
63

    
64
    @SpringBeanByType
65
    private IAnnotationService annotationService;
66

    
67
    @SpringBeanByType
68
    private ITaxonService taxonService;
69

    
70
    @SpringBeanByType
71
    private IAgentService agentService;
72

    
73
    @SpringBeanByType
74
    private ICommonService commonService;
75

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
148
        // ---- loading taxon with findTaxonByUuid ----
149

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

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

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

    
161
        INonViralName nvn = CdmBase.deproxy(taxon.getName(),TaxonName.class);
162

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

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

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

    
175
        team.setProtectedTitleCache(false);
176

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

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

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

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

    
198
        team.setProtectedTitleCache(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
}
(10-10/40)