Project

General

Profile

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

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

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

    
26
import eu.etaxonomy.cdm.model.agent.Person;
27
import eu.etaxonomy.cdm.model.agent.Team;
28
import eu.etaxonomy.cdm.model.common.Annotation;
29
import eu.etaxonomy.cdm.model.common.CdmBase;
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.BotanicalName;
34
import eu.etaxonomy.cdm.model.name.NonViralName;
35
import eu.etaxonomy.cdm.model.reference.Reference;
36
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
37
import eu.etaxonomy.cdm.model.taxon.Taxon;
38
import eu.etaxonomy.cdm.test.integration.CdmIntegrationTest;
39

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

    
48
public class HandlingCdmEntitiesTest extends CdmIntegrationTest {
49

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

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

    
56
    @SpringBeanByType
57
    private IReferenceService referenceService;
58

    
59
    @SpringBeanByType
60
    private IAnnotationService annotationService;
61

    
62
    @SpringBeanByType
63
    private ITaxonService taxonService;
64

    
65
    @SpringBeanByType
66
    private IAgentService agentService;
67

    
68
    @SpringBeanByType
69
    private ICommonService commonService;
70

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
145
        // ---- loading taxon with findTaxonByUuid ----
146

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

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

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

    
158
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
159

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

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

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

    
172
        team.setProtectedTitleCache(false);
173

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

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

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

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

    
195
        team.setProtectedTitleCache(true);
196
        taxonService.update(taxon);
197

    
198
    }
199

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

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

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

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

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

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

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

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

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

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

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

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

    
239
        // ---- loading taxon with findTaxonByUuid ----
240

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

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

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

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

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

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

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

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

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

    
273

    
274
        BotanicalName name = BotanicalName.NewInstance(null, "Pinus Alba", null, null, null, null, null, null,  null);
275
        name.setCombinationAuthorship(combAuthor);
276

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

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

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

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

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

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

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

    
301
    }
302

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

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

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

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

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

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

    
324
        taxonService.merge(taxon);
325

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

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

    
330
        taxonService.merge(taxon);
331

    
332
        // ---- loading taxon with findTaxonByUuid ----
333

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

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

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

    
345
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
346

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

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

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

    
360

    
361
        taxonService.merge(taxon);
362

    
363
    }
364

    
365

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

    
369
        BotanicalName name = BotanicalName.NewInstance(null, "Abies alba", null, null, null, null, null, null, null);
370
        Taxon taxon = Taxon.NewInstance(name, null);
371
        TaxonDescription description = TaxonDescription.NewInstance(taxon);
372

    
373
        TextData textData = TextData.NewInstance();
374

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

    
378
//        DescriptionElementSource descriptionElementSource = DescriptionElementSource.NewInstance(OriginalSourceType.PrimaryTaxonomicSource);
379
//
380
//        textData.addSource(descriptionElementSource);
381

    
382
        textData.addAnnotation(Annotation.NewDefaultLanguageInstance("abc"));
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/31)