Project

General

Profile

Download (13.7 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.CdmBase;
29
import eu.etaxonomy.cdm.model.name.BotanicalName;
30
import eu.etaxonomy.cdm.model.name.NonViralName;
31
import eu.etaxonomy.cdm.model.taxon.Taxon;
32
import eu.etaxonomy.cdm.test.integration.CdmIntegrationTest;
33

    
34
/**
35
 * This test class tries to describe how hibernate works with objects (save, update, merge).
36
 *
37
 * @author cmathew
38
 * @date 17 Sep 2014
39
 *
40
 */
41

    
42
public class HandlingCdmEntitiesTest extends CdmIntegrationTest {
43

    
44
    private static final Logger logger = Logger.getLogger(CommonServiceImplTest.class);
45

    
46
    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";
47
    private static final String LIE_NOSESSION = "could not initialize proxy - no Session";
48

    
49
    @SpringBeanByType
50
    private ITaxonService taxonService;
51

    
52
    @SpringBeanByType
53
    private IAgentService agentService;
54

    
55
    @SpringBeanByType
56
    private ICommonService commonService;
57

    
58
    public static final String[] includeTables = new String[]{
59
        "TAXONBASE",
60
        "TAXONNAMEBASE",
61
        "AGENTBASE",
62
        "AGENTBASE_AGENTBASE",
63
        "HOMOTYPICALGROUP"
64
    };
65

    
66
    @Ignore
67
    @Test
68
    @Transactional(TransactionMode.DISABLED)
69
    public final void createTestData() {
70
        Team combAuthor = Team.NewTitledInstance("Avengers", "Avengers");
71
        combAuthor.addTeamMember(Person.NewTitledInstance("Iron Man"));
72
        BotanicalName name = BotanicalName.NewInstance(null, "Abies alba", null, null, null, null, null, null, null);
73
        name.setCombinationAuthorTeam(combAuthor);
74
        Taxon taxon = Taxon.NewInstance(name, null);
75
        UUID taxonUuid = taxonService.save(taxon);
76
        printDataSetWithNull(System.out,false,null,includeTables);
77
    }
78

    
79
    @Test
80
    @DataSet
81
    @Transactional(TransactionMode.DISABLED)
82
    public void testNonTransactionalUpdateForExistingTaxon() {
83
        // this method tests the updating of a 'truely' detached object which
84
        // attempts to initialize a lazy loaded proxy object while trying to
85
        // update the same.
86

    
87
        // setting the TransactionMode for this method to DISABLED is important
88
        // to ensure that transaction boundaries remain at the service layer calls
89
        // to simulate detachment and update of the persisted object
90

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

    
93
        // ---- loading taxon with find (uuid) ----
94

    
95
        Taxon taxon = (Taxon)taxonService.find(taxonUuid);
96

    
97
        // at this point the taxonNew object is detached and all lazy loaded proxy
98
        // objects in the object graph (including teamMembers) will have values of
99
        // initialized=false and session=null
100

    
101
        // since name is lazy loaded the call to getName should fail
102
        try {
103
            CdmBase.deproxy(taxon.getName(),NonViralName.class);
104
            Assert.fail("LazyInitializationException not thrown for lazy loaded Taxon.name");
105
        } catch(LazyInitializationException lie) {
106

    
107
            if(!lie.getMessage().equals(LIE_NOSESSION)) {
108
                Assert.fail("LazyInitializationException thrown, but not : " + LIE_NOSESSION);
109
            }
110
        }
111

    
112
        // ---- loading taxon with find (id) ----
113

    
114
        taxon = (Taxon)commonService.find(taxon.getClass(), taxon.getId());
115

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

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

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

    
131
        // ---- loading taxon with findTaxonByUuid ----
132

    
133
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
134
                "name"
135
        });
136

    
137
        // loading the taxon with its taxon name object pre-initialized
138
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
139

    
140
        // at this point the taxonNew object is detached and all lazy loaded proxy
141
        // objects in the object graph (including teamMembers) will have values of
142
        // initialized=false and session=null
143

    
144
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
145

    
146
        // normally this call should throw a lazy loading exception since
147
        // the combinationAuthorTeam object is not initialized, but
148
        // the findTaxonByUuid performs this initialization (via the
149
        // AdvancedBeanInitializer) since the combinationAuthorTeam
150
        // is annotated with CacheUpdate
151

    
152
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorTeam(),Team.class);
153

    
154
        // setting the protected title cache to false to ensure that
155
        // TeamDefaultCacheStrategy.getTitleCache is called, which in turn tries
156
        // to initialize the teamMembers persistent collection which fails
157

    
158
        team.setProtectedTitleCache(false);
159

    
160
        try {
161
            taxonService.update(taxon);
162
            Assert.fail("LazyInitializationException not thrown for lazy loaded Team.teamMembers");
163
        } catch(LazyInitializationException lie) {
164

    
165
            if(!lie.getMessage().equals(LIE_TEAMMEMBERS_NOSESSION)) {
166
                Assert.fail("LazyInitializationException thrown, but not : " + LIE_TEAMMEMBERS_NOSESSION);
167
            }
168
        }
169

    
170
        // the above fails due to the fact that hibernate does not resolve lazy
171
        // loading on a detached object until the object is persisted. The attempt
172
        // to initialize teamMembers before the object graph is persisted means that
173
        // the current session is not yet attached to the proxy objects and hibernate
174
        // tries to use the existing session set in the teamMembers object which is
175
        // null, leading to the exception
176

    
177
        // setting the protected title cache to true to ensure that
178
        // TeamDefaultCacheStrategy.getTitleCache is not called, implying
179
        // that the teamMembers are not initialized, so no exception is thrown
180

    
181
        team.setProtectedTitleCache(true);
182
        taxonService.update(taxon);
183

    
184
    }
185

    
186
    @Test
187
    @DataSet
188
    public void testTransactionalUpdateAfterFindTaxonByUuidForExistingTaxon() {
189
        // this method tests the updating of a detached object inside a single
190
        // transaction.
191

    
192
        // this method is transactional, meaning that a transaction is started
193
        // at the start of the method and ends only with the end of the method
194

    
195
        // since this method is transactional, any object initialized within this method
196
        // will have a valid session attached to any lazy loaded proxy objects
197
        // in the object graph (including teamMembers)
198

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

    
201
        // ---- loading taxon with find (uuid) ----
202

    
203
        Taxon taxon = (Taxon)taxonService.find(taxonUuid);
204

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

    
209
        NonViralName nvn =  CdmBase.deproxy(taxon.getName(),NonViralName.class);
210
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorTeam(),Team.class);
211
        taxonService.update(taxon);
212

    
213
        // ---- loading taxon with find (id) ----
214

    
215
        taxon = (Taxon)commonService.find(taxon.getClass(), taxon.getId());
216

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

    
221
        nvn =  CdmBase.deproxy(taxon.getName(),NonViralName.class);
222
        team = CdmBase.deproxy(nvn.getCombinationAuthorTeam(),Team.class);
223
        taxonService.update(taxon);
224

    
225
        // ---- loading taxon with findTaxonByUuid ----
226

    
227
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
228
                "name"
229
        });
230

    
231
        // loading the taxon with its taxon name object pre-initialized
232
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
233

    
234
        nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
235
        team = CdmBase.deproxy(nvn.getCombinationAuthorTeam(),Team.class);
236

    
237
        // since a valid session is now attached to teamMembers, forcing the
238
        // initializing of the teamMembers (in TeamDefaultCacheStrategy.getTitleCache)
239
        // by setting the protected title cache to false does not throw an exception
240
        // because the teamMember persistent collection now has a valid session,
241
        // which is used to initialize the persistent collection
242

    
243
        team.setProtectedTitleCache(false);
244
        taxonService.update(taxon);
245
    }
246

    
247
    @Test
248
    @Transactional(TransactionMode.DISABLED)
249
    public void testNonTransactionalUpdateForNewTaxon() {
250

    
251
        // this test is only to prove that the update problem occurs
252
        // also for newly created objects (as expected)
253

    
254
        // create / save new taxon with name and author team with team member
255

    
256
        Team combAuthor = Team.NewTitledInstance("X-Men", "X-Men");
257
        combAuthor.addTeamMember(Person.NewTitledInstance("Wolverine"));
258

    
259

    
260
        BotanicalName name = BotanicalName.NewInstance(null, "Pinus Alba", null, null, null, null, null, null,  null);
261
        name.setCombinationAuthorTeam(combAuthor);
262

    
263
        Taxon taxon = Taxon.NewInstance(name, null);
264

    
265
        UUID taxonUuid = taxonService.save(taxon);
266

    
267
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
268
                "name"
269
        });
270

    
271
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
272

    
273
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
274
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorTeam(),Team.class);
275
        team.setProtectedTitleCache(false);
276

    
277
        try {
278
            taxonService.update(taxon);
279
            Assert.fail("LazyInitializationException not thrown for lazy loaded Team.teamMembers");
280
        } catch(LazyInitializationException lie) {
281

    
282
            if(!lie.getMessage().equals(LIE_TEAMMEMBERS_NOSESSION)) {
283
                Assert.fail("LazyInitializationException thrown, but not : " + LIE_TEAMMEMBERS_NOSESSION);
284
            }
285
        }
286

    
287
    }
288

    
289
    @Test
290
    @DataSet
291
    @Transactional(TransactionMode.DISABLED)
292
    public void testNonTransactionalMergeForExistingTaxon() {
293
        // this method tests the updating of a 'truely' detached object
294
        // using merge
295

    
296
        // setting the TransactionMode for this method to DISABLED is important
297
        // to ensure that transaction boundaries remain at the service layer calls
298
        // to simulate detachment and update of the persisted object
299

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

    
302
        // ---- loading taxon with find (uuid) ----
303

    
304
        Taxon taxon = (Taxon)taxonService.find(taxonUuid);
305

    
306
        // at this point the taxonNew object is detached and all lazy loaded proxy
307
        // objects in the object graph (including teamMembers) will have values of
308
        // initialized=false and session=null
309

    
310
        taxonService.merge(taxon);
311

    
312
        // ---- loading taxon with find (id) ----
313

    
314
        taxon = (Taxon)commonService.find(taxon.getClass(), taxon.getId());
315

    
316
        taxonService.merge(taxon);
317

    
318
        // ---- loading taxon with findTaxonByUuid ----
319

    
320
        List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[] {
321
                "name"
322
        });
323

    
324
        // loading the taxon with its taxon name object pre-initialized
325
        taxon = (Taxon)taxonService.findTaxonByUuid(taxonUuid, TAXON_INIT_STRATEGY);
326

    
327
        // at this point the taxonNew object is detached and all lazy loaded proxy
328
        // objects in the object graph (including teamMembers) will have values of
329
        // initialized=false and session=null
330

    
331
        NonViralName nvn = CdmBase.deproxy(taxon.getName(),NonViralName.class);
332

    
333
        // normally this call should throw a lazy loading exception since
334
        // the combinationAuthorTeam object is not initialized, but
335
        // the findTaxonByUuid performs this initialization (via the
336
        // AdvancedBeanInitializer) since the combinationAuthorTeam
337
        // is annotated with CacheUpdate
338

    
339
        Team team = CdmBase.deproxy(nvn.getCombinationAuthorTeam(),Team.class);
340

    
341
        // setting the protected title cache to false to ensure that
342
        // TeamDefaultCacheStrategy.getTitleCache is called, which in turn tries
343
        // to initialize the teamMembers persistent collection which fails
344
        team.setProtectedTitleCache(false);
345

    
346

    
347
        taxonService.merge(taxon);
348

    
349
    }
350
}
(7-7/27)