Project

General

Profile

Download (28.5 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 *
3
 */
4
package eu.etaxonomy.cdm.persistence.dao.initializer;
5

    
6
import java.beans.PropertyDescriptor;
7
import java.io.Serializable;
8
import java.lang.reflect.InvocationTargetException;
9
import java.lang.reflect.Method;
10
import java.lang.reflect.ParameterizedType;
11
import java.lang.reflect.Type;
12
import java.lang.reflect.TypeVariable;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Optional;
20
import java.util.Set;
21

    
22
import org.apache.commons.beanutils.PropertyUtils;
23
import org.apache.log4j.Logger;
24
import org.hibernate.Hibernate;
25
import org.hibernate.HibernateException;
26
import org.hibernate.Query;
27
import org.hibernate.collection.internal.AbstractPersistentCollection;
28
import org.hibernate.collection.internal.PersistentMap;
29
import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.CollectionProxy;
30
import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.MapProxy;
31
import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.SortedMapProxy;
32
import org.hibernate.proxy.HibernateProxy;
33
import org.springframework.beans.factory.annotation.Autowired;
34

    
35
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
36
import eu.etaxonomy.cdm.model.common.CdmBase;
37
import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
38
import eu.etaxonomy.cdm.persistence.dao.hibernate.HibernateBeanInitializer;
39
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
40

    
41
/**
42
 * For now this is a test if we can improve performance for bean initializing
43
 * @author a.mueller
44
 * @since 2013-10-25
45
 *
46
 */
47
public class AdvancedBeanInitializer extends HibernateBeanInitializer {
48

    
49
    public static final Logger logger = Logger.getLogger(AdvancedBeanInitializer.class);
50

    
51
    @Autowired
52
    ICdmGenericDao genericDao;
53

    
54
    @Override
55
    public void initialize(Object bean, List<String> propertyPaths) {
56
        List<Object> beanList = new ArrayList<Object>(1);
57
        beanList.add(bean);
58
        initializeAll(beanList, propertyPaths);
59
    }
60

    
61
    //TODO optimize algorithm ..
62
    @Override
63
    public <C extends Collection<?>> C initializeAll(C beanList,  List<String> propertyPaths) {
64

    
65
        if (beanList == null || beanList.isEmpty()){
66
            return beanList;
67
        }
68

    
69
        //autoinitialize
70
        for (Object bean : beanList){
71
            autoinitializeBean(bean);
72
        }
73

    
74
        if(propertyPaths == null){
75
            return beanList;
76
        }
77

    
78

    
79
        //new
80
         BeanInitNode rootPath = BeanInitNode.createInitTree(propertyPaths);
81
        if (logger.isTraceEnabled()){logger.trace(rootPath.toStringTree());}
82

    
83

    
84
        if(logger.isDebugEnabled()){ logger.debug(">> starting to initialize beanlist ; class(e.g.):" + beanList.iterator().next().getClass().getSimpleName());}
85
        rootPath.addBeans(beanList);
86
        initializeNodeRecursive(rootPath);
87

    
88

    
89
        //old - keep for safety (this may help to initialize those beans that are not yet correctly initialized by the AdvancedBeanInitializer
90
        if(logger.isTraceEnabled()){logger.trace("Start old initalizer ... ");};
91
        for (Object bean :beanList){
92
            Collections.sort(propertyPaths);
93
            for(String propPath : propertyPaths){
94
//		            initializePropertyPath(bean, propPath);
95
            }
96
        }
97

    
98
        if(logger.isDebugEnabled()){ logger.debug("   Completed initialization of beanlist "); }
99
        return beanList;
100

    
101
    }
102

    
103

    
104
    //new
105
    private void initializeNodeRecursive(BeanInitNode rootPath) {
106
        initializeNode(rootPath);
107
        for (BeanInitNode childPath : rootPath.getChildrenList()){
108
            initializeNodeRecursive(childPath);
109
        }
110
        rootPath.resetBeans();
111
    }
112

    
113
    /**
114
     * Initializes the given single <code>propPath</code> String.
115
     *
116
     * @param bean
117
     * @param propPath
118
     */
119
    private void initializeNode(BeanInitNode node) {
120
        if(logger.isDebugEnabled()){logger.debug(" processing " + node.toString());}
121
        if (node.isRoot()){
122
            return;
123
        }else if (node.isWildcard()){
124
            initializeNodeWildcard(node);
125
        } else {
126
            initializeNodeNoWildcard(node);
127
        }
128
    }
129

    
130
    // if propPath only contains a wildcard (* or $)
131
    // => do a batch initialization of *toOne or *toMany relations
132
    private void initializeNodeWildcard(BeanInitNode node) {
133
//			boolean initToMany = node.isToManyWildcard();
134
        Map<Class<?>, Set<Object>> parentBeans = node.getParentBeans();
135
        for (Class<?> clazz : parentBeans.keySet()){
136
            //new
137
            for (Object bean : parentBeans.get(clazz)){
138

    
139
                if(Collection.class.isAssignableFrom(bean.getClass())){
140
//				        old: initializeAllEntries((Collection<?>)bean, true, initToMany);  //TODO is this a possible case at all??
141
                    throw new RuntimeException("Collection no longer expected in 'initializeNodeWildcard()'. Therefore an exception is thrown.");
142
                } else if(Map.class.isAssignableFrom(bean.getClass())) {
143
//				        old: initializeAllEntries(((Map<?,?>)bean).values(), true, initToMany);  ////TODO is this a possible case at all??
144
                    throw new RuntimeException("Map no longer expected in 'initializeNodeWildcard()'. Therefore an exception is thrown.");
145
                } else{
146
                    prepareBeanWildcardForBulkLoad(node, bean);
147
                }
148
            }
149
            //end new
150

    
151
//		    	initializeNodeWildcardOld(initToMany, beans, clazz);  //if switched on move bulkLoadLazies up
152
        }
153

    
154
        //
155
        bulkLoadLazies(node);
156
    }
157

    
158
    /**
159
     * @param initToMany
160
     * @param beans
161
     * @param clazz
162
     */
163
    private void initializeNodeWildcardOld(boolean initToMany,
164
            Map<Class<?>, Set<Object>> beans, Class<?> clazz) {
165
        for (Object bean : beans.get(clazz)){
166

    
167
            if(Collection.class.isAssignableFrom(bean.getClass())){
168
                initializeAllEntries((Collection<?>)bean, true, initToMany);
169
            } else if(Map.class.isAssignableFrom(bean.getClass())) {
170
                initializeAllEntries(((Map<?,?>)bean).values(), true, initToMany);
171
            } else{
172
                initializeBean(bean, true, initToMany);
173
            }
174
        }
175
    }
176

    
177
    private void prepareBeanWildcardForBulkLoad(BeanInitNode node, Object bean){
178

    
179
        if(logger.isTraceEnabled()){logger.trace(">> prepare bulk wildcard initialization of a bean of type " + bean.getClass().getSimpleName()); }
180
        Set<Class<?>> restrictions = new HashSet<Class<?>>();
181
        restrictions.add(CdmBase.class);
182
        if(node.isToManyWildcard()){
183
            restrictions.add(Collection.class);
184
        }
185
        Set<PropertyDescriptor> props = getProperties(bean, restrictions);
186
        for(PropertyDescriptor propertyDescriptor : props){
187
            try {
188
                String property = propertyDescriptor.getName();
189

    
190
//                  invokeInitialization(bean, propertyDescriptor);
191
                Object propertyValue = PropertyUtils.getProperty( bean, property);
192

    
193
                preparePropertyValueForBulkLoadOrStore(node, bean, property,  propertyValue );
194

    
195
            } catch (IllegalAccessException e) {
196
                logger.error("Illegal access on property " + propertyDescriptor.getName());
197
            } catch (InvocationTargetException e) {
198
                logger.info("Cannot invoke property " + propertyDescriptor.getName() + " not found");
199
            } catch (NoSuchMethodException e) {
200
                logger.info("Property " + propertyDescriptor.getName() + " not found");
201
            }
202
        }
203
        if(logger.isTraceEnabled()){logger.trace(" completed bulk wildcard initialization of a bean");}
204
    }
205

    
206

    
207
    /**
208
     * Initializes all objects matching the given node, where the
209
     * node does not represent a wildcard but a single field or
210
     * a nested path. Splits the next path token off and keeps
211
     * the remaining as nestedPath
212
     *
213
     * @param node
214
     */
215
    private void initializeNodeNoWildcard(BeanInitNode node) {
216

    
217
        String property = node.getPath();
218
        int pos;
219

    
220
        // is the property indexed?
221
        Integer index = null;
222
        if((pos = property.indexOf('[')) > 0){
223
            String indexString = property.substring(pos + 1, property.indexOf(']'));
224
            index = Integer.valueOf(indexString);
225
            property = property.substring(0, pos);
226
        }
227

    
228
        //Class targetClass = HibernateProxyHelper.getClassWithoutInitializingProxy(bean); // used for debugging
229

    
230
        for (Class<?> parentClazz : node.getParentBeans().keySet()){
231
            if (logger.isTraceEnabled()){logger.trace(" invoke initialization on "+ node.toString()+ " beans of class " + parentClazz.getSimpleName() + " ... ");}
232

    
233
            Set<Object> parentBeans = node.getParentBeans().get(parentClazz);
234

    
235
            if (index != null){
236
                logger.warn("Property path index not yet implemented for 'new'");
237
            }
238
            //new
239
            for (Object parentBean : parentBeans){
240
                preparePropertyForSingleBean(node, property, parentClazz, parentBean);
241
            }//end for
242
            //end new
243
//			 initializeNodeNoWildcardOld(node, property, index, parentBeans);  //move bulkLoadLazies up again, if uncomment this line
244
        } //end for
245
        bulkLoadLazies(node);
246
    }
247

    
248
    /**
249
     * Prepare a single property of a non-collection bean. Collections are handled elsewhere.
250
     */
251
    private void preparePropertyForSingleBean(BeanInitNode node, String property, Class<?> parentClazz, Object bean) {
252
        String propertyName = mapFieldToPropertyName(property, bean.getClass().getSimpleName());
253
        try{
254
            Object propertyValue = PropertyUtils.getProperty(bean, propertyName);
255
            preparePropertyValueForBulkLoadOrStore(node, bean, property, propertyValue);
256
        } catch (IllegalAccessException e) {
257
            String message = "Illegal access on property " + property;
258
            logger.error(message);
259
            throw new RuntimeException(message, e);
260
        } catch (InvocationTargetException e) {
261
            String message = "Cannot invoke property " + property + " not found";
262
            logger.error(message);
263
            throw new RuntimeException(message, e);
264
        } catch (NoSuchMethodException e) {
265
            String message = "Property " + propertyName + " not found for class " + parentClazz;
266
            logger.info(message);
267
            //don't throw exception as sometimes property paths will include non matching property names due to subclassing
268
            //#5077  comment 12
269
        }
270
    }
271

    
272
//    /**
273
//     * @param node
274
//     * @param property
275
//     * @param index
276
//     * @param parentBeans
277
//     * @throws IllegalAccessException
278
//     * @throws InvocationTargetException
279
//     * @throws NoSuchMethodException
280
//     */
281
//    private void initializeNodeNoWildcardOld(BeanInitNode node,
282
//                String property,
283
//                Integer index,
284
//                Set<Object> parentBeans)
285
//            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
286
//    {
287
//        for (Object bean : parentBeans){
288
//
289
//            PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(bean, property);
290
//            if (logger.isTraceEnabled()){logger.trace("   unwrap " + node.toStringNoWildcard() + " ... ");}
291
//            // [1] initialize the bean named by property
292
//            Object unwrappedPropertyBean = invokeInitialization(bean, propertyDescriptor);
293
//            if (logger.isTraceEnabled()){logger.trace("   unwrap " + node.toStringNoWildcard() + " - DONE ");}
294
//
295
//
296
//            // [2]
297
//            // handle property
298
//            if(unwrappedPropertyBean != null ){
299
//                initializeNodeSinglePropertyOld(node, property, index, bean, unwrappedPropertyBean);
300
//            }
301
//        }
302
//    }
303

    
304
    /**
305
     * @param node
306
     * @param propertyValue
307
     * @param parentBean
308
     * @param param
309
     */
310
    private void preparePropertyValueForBulkLoadOrStore(BeanInitNode node,
311
            Object parentBean,
312
            String param,
313
            Object propertyValue)
314
    {
315
        BeanInitNode sibling = node.getSibling(param);
316

    
317
        if (propertyValue instanceof AbstractPersistentCollection ){
318
            //collections
319
            if (!node.hasWildcardToManySibling()){  //if wildcard sibling exists the lazies are already prepared there
320
                AbstractPersistentCollection collection = (AbstractPersistentCollection)propertyValue;
321
                if (collection.wasInitialized()){
322
                    storeInitializedCollection(collection, node, param);
323
                }else{
324
//						Class<?> parentClass = parentBean.getClass();
325
//						int parentId = ((CdmBase)parentBean).getId();
326
                    if (sibling != null){
327
                        sibling.putLazyCollection(collection);
328
                    }else{
329
                        node.putLazyCollection(collection);
330
                    }
331
                }
332
            }
333
        } else if (propertyValue instanceof CollectionProxy
334
                || propertyValue instanceof MapProxy<?, ?>
335
                || propertyValue instanceof SortedMapProxy<?, ?>){
336
            //hibernate envers collections
337
            //TODO check if other code works with audited data at all as we use HQL queries
338
            if (!node.hasWildcardToManySibling()){  //if wildcard sibling exists the lazies are already prepared there
339
                Collection<?> collection = (Collection<?>)propertyValue;
340
                //TODO it is difficult to find out if an envers collection is initialized
341
                //but possibly via reflection. If the "delegate" parameter is null it is not yet initialized.
342
                //However, as we do not know if envers initialization works at all together with the AdvancedBeanInitializer
343
                //we initialize each collection immediately here by calling size()
344
                collection.size();  //initialize
345
                storeInitializedEnversCollection(collection, node, param);
346
            }
347
        }else{
348
            //singles
349
            if (!node.hasWildcardToOneSibling()){  //if wildcard exists the lazies are already prepared there
350
                if (! Hibernate.isInitialized(propertyValue)){
351
                    if (propertyValue instanceof HibernateProxy){
352
                        Serializable id = ((HibernateProxy)propertyValue).getHibernateLazyInitializer().getIdentifier();
353
                        Class<?> persistedClass = ((HibernateProxy)propertyValue).getHibernateLazyInitializer().getPersistentClass();
354
                        if (sibling != null){
355
                            sibling.putLazyBean(persistedClass, id);
356
                        }else{
357
                            node.putLazyBean(persistedClass, id);
358
                        }
359

    
360
                    }else{
361
                        logger.warn("Lazy value is not of type HibernateProxy. This is not yet handled.");
362
                    }
363
                }else if (propertyValue == null){
364
                    // do nothing
365
                }else{
366
                    if (propertyValue instanceof HibernateProxy){  //TODO remove hibernate dependency
367
                        propertyValue = initializeInstance(propertyValue);
368
                    }
369
                    autoinitializeBean(propertyValue);
370
                    node.addBean(propertyValue);
371
                }
372
            }
373
        }
374
    }
375

    
376
    private void autoinitializeBean(Object bean) {
377
        invokePropertyAutoInitializers(bean);
378
    }
379

    
380
    private void autoinitializeBean(CdmBase bean, AutoInit autoInit) {
381
        for(AutoPropertyInitializer<CdmBase> init : autoInit.initlializers) {
382
            init.initialize(bean);
383
        }
384
    }
385

    
386
	private void storeInitializedCollection(AbstractPersistentCollection persistedCollection,
387
			BeanInitNode node, String param) {
388

    
389
	    Collection<?> collection;
390
		if (persistedCollection  instanceof Collection) {
391
			collection = (Collection<?>) persistedCollection;
392
		}else if (persistedCollection instanceof Map) {
393
			collection = ((Map<?,?>)persistedCollection).values();
394
		}else{
395
			throw new RuntimeException ("Non Map and non Collection cas not handled in storeInitializedCollection()");
396
		}
397
		for (Object value : collection){
398
			preparePropertyValueForBulkLoadOrStore(node, null, param, value);
399
		}
400
	}
401

    
402
	/**
403
	 * @see #storeInitializedCollection(AbstractPersistentCollection, BeanInitNode, String)alizedCollection
404
	 */
405
	private void storeInitializedEnversCollection(Collection<?> enversCollection,
406
            BeanInitNode node, String param) {
407
	    if (enversCollection instanceof CollectionProxy
408
                || enversCollection instanceof MapProxy<?, ?>
409
                || enversCollection instanceof SortedMapProxy<?, ?>){
410
	        Collection<?> collection;
411
	        if (enversCollection instanceof MapProxy
412
	                || enversCollection instanceof SortedMapProxy<?, ?>) {
413
	            collection = ((Map<?,?>)enversCollection).values();
414
	        }else if (enversCollection instanceof CollectionProxy) {
415
	            collection = enversCollection;
416
	        }else{
417
	            throw new RuntimeException ("Non MapProxy and non CollectionProxy case not handled in storeInitializedEnversCollection()");
418
	        }
419
	        for (Object value : collection){
420
	            preparePropertyValueForBulkLoadOrStore(node, null, param, value);
421
	        }
422
	    }
423
    }
424

    
425

    
426
	/**
427
	 * Load all beans which are added to the node
428
	 * and which are not yet initialized in bulk.
429
	 * @param node
430
	 */
431
	private void bulkLoadLazies(BeanInitNode node) {
432
		if (logger.isTraceEnabled()){logger.trace("bulk load " +  node);}
433
		//beans
434
		bulkLoadLazyBeans(node);
435
		//collections
436
		bulkLoadLazyCollections(node);
437
		if (logger.isDebugEnabled()){logger.debug("bulk load " +  node + " - DONE ");}
438
	}
439

    
440

    
441
    /**
442
     * Loads all lazy beans added to the node and empty the lazy bean collection of the node.
443
     * Lazy collections are initialized elsewhere: {@link #bulkLoadLazyCollections(BeanInitNode)}
444
     * @param node the {@link BeanInitNode} to load the lazy beans for
445
     */
446
    private void bulkLoadLazyBeans(BeanInitNode node) {
447
        for (Class<?> clazz : node.getLazyBeans().keySet()){
448
            Set<Serializable> idSet = node.getLazyBeans().get(clazz);
449
            if (idSet != null && ! idSet.isEmpty()){
450

    
451
                if (logger.isTraceEnabled()){logger.trace("bulk load beans of class " +  clazz.getSimpleName());}
452
                //TODO use entity name
453
                String hql = " SELECT c FROM %s as c %s WHERE c.id IN (:idSet) ";
454
                AutoInit autoInit = addAutoinitFetchLoading(clazz, "c");
455
                hql = String.format(hql, clazz.getSimpleName(), autoInit.leftJoinFetch);
456
                if (logger.isTraceEnabled()){logger.trace(hql);}
457
                Query query = genericDao.getHqlQuery(hql);
458
                query.setParameterList("idSet", idSet);
459
                List<Object> list = query.list();
460

    
461
                if (logger.isTraceEnabled()){
462
//                    String beanList = "";
463
//                    for(Object id : idSet){
464
//                        Set<Serializable> bean = node.getLazyBeans().get(id);
465
//                        beanList += bean.getClass().getSimpleName() + "<" + id + "> ";
466
//                    }
467
                    logger.trace("initialize bulk loaded beans of class " +  clazz.getSimpleName() + ": " + idSet );
468
                }
469
                for (Object object : list){
470
                    if (object instanceof HibernateProxy){  //TODO remove hibernate dependency
471
                        object = initializeInstance(object);
472
                    }
473
                    autoinitializeBean((CdmBase)object, autoInit);
474
                    node.addBean(object);
475
                }
476
                if (logger.isTraceEnabled()){logger.trace("bulk load - DONE");}
477
            }
478
        }
479
        node.resetLazyBeans();
480
    }
481

    
482
    /**
483
     * Loads all lazy collections added to the node and empty the lazy collections collection of the node.
484
     * Lazy beans are initialized elsewhere: {@link #bulkLoadLazyBeans(BeanInitNode)}
485
     * @param node the {@link BeanInitNode} to load the lazy beans for
486
     */
487
    private void bulkLoadLazyCollections(BeanInitNode node) {
488
        for (Class<?> ownerClazz : node.getLazyCollections().keySet()){
489
			Map<String, Set<Serializable>> lazyParams = node.getLazyCollections().get(ownerClazz);
490
			for (String param : lazyParams.keySet()){
491
				Set<Serializable> idSet = lazyParams.get(param);
492
				if (idSet != null && ! idSet.isEmpty()){
493
					if (logger.isTraceEnabled()){logger.trace("bulk load " + node + " collections ; ownerClass=" +  ownerClazz.getSimpleName() + " ; param = " + param);}
494

    
495
					Type collectionEntitiyType = null;
496
					PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(ownerClazz);
497
					for(PropertyDescriptor d : descriptors) {
498
					    if(d.getName().equals(param)) {
499
					        Method readMethod = d.getReadMethod();
500
                            ParameterizedType pt = (ParameterizedType) readMethod.getGenericReturnType();
501
                            Type[] actualTypeArguments = pt.getActualTypeArguments();
502
                            if(actualTypeArguments.length == 2) {
503
                                // this must be a map of <Language, String> (aka LanguageString) there is no other case like this in the cdm
504
                                // in case of Maps the returned Collection will be the Collection of the values, so collectionEntitiyType is the
505
                                // second typeArgument
506
                                collectionEntitiyType = actualTypeArguments[1];
507
                            } else {
508
                                collectionEntitiyType = actualTypeArguments[0];
509
                            }
510
                            if(collectionEntitiyType instanceof TypeVariable) {
511
                                collectionEntitiyType = ((TypeVariable)collectionEntitiyType).getBounds()[0];
512
                            }
513
					    }
514
					}
515

    
516
					//TODO use entity name ??
517
					//get from repository
518
					List<Object[]> list;
519
					String hql = "SELECT oc " +
520
							" FROM %s as oc LEFT JOIN FETCH oc.%s as col %s" +
521
							" WHERE oc.id IN (:idSet) ";
522

    
523
					if (collectionEntitiyType instanceof ParameterizedTypeImpl){
524
					    collectionEntitiyType = ((ParameterizedTypeImpl)collectionEntitiyType).getRawType();
525
					}
526
					AutoInit autoInit = addAutoinitFetchLoading((Class<?>)collectionEntitiyType, "col");
527
                    hql = String.format(hql, ownerClazz.getSimpleName(), param,
528
					        autoInit.leftJoinFetch);
529

    
530
					try {
531
						if (logger.isTraceEnabled()){logger.trace(hql);}
532
						Query query = genericDao.getHqlQuery(hql);
533
						query.setParameterList("idSet", idSet);
534
						list = query.list();
535
						if (logger.isTraceEnabled()){logger.trace("size of retrieved list is " + list.size());}
536
					} catch (HibernateException e) {
537
						e.printStackTrace();
538
						throw e;
539
					}
540

    
541
					//getTarget and add to child node
542
					if (logger.isTraceEnabled()){logger.trace("initialize bulk loaded " + node + " collections - DONE");}
543
					for (Object parentBean : list){
544
                        try {
545
						    Object propValue = PropertyUtils.getProperty(
546
						            parentBean,
547
						            mapFieldToPropertyName(param, parentBean.getClass().getSimpleName())
548
						          );
549

    
550
							if (propValue == null){
551
							    logger.trace("Collection is null");
552
							}else {
553
							    if(propValue instanceof PersistentMap) {
554
							        propValue = ((PersistentMap)propValue).values();
555
							    }
556
							    for(Object newBean : (Collection<Object>)propValue ) {
557
							        if(newBean instanceof HibernateProxy){
558
							            newBean = initializeInstance(newBean);
559
							        }
560

    
561
							        if (HibernateProxyHelper.isInstanceOf(newBean, CdmBase.class)){
562
							            autoinitializeBean((CdmBase)newBean, autoInit);
563
							        }
564
							        node.addBean(newBean);
565
							    }
566
							}
567
                        } catch (Exception e) {
568
                            // TODO better throw an exception ?
569
                            logger.error("error while getting collection property", e);
570
                        }
571
					}
572
					if (logger.isTraceEnabled()){logger.trace("bulk load " + node + " collections - DONE");}
573
				}
574
			}
575
		}
576
		for (AbstractPersistentCollection collection : node.getUninitializedCollections()){
577
			if (! collection.wasInitialized()){  //should not happen anymore
578
				collection.forceInitialization();
579
				if (logger.isTraceEnabled()){logger.trace("forceInitialization of collection " + collection);}
580
			} else {
581
			    if (logger.isTraceEnabled()){logger.trace("collection " + collection + " is initialized - OK!");}
582
			}
583
		}
584

    
585
		node.resetLazyCollections();
586
    }
587

    
588
    private AutoInit addAutoinitFetchLoading(Class<?> clazz, String beanAlias) {
589

    
590
        AutoInit autoInit = new AutoInit();
591
        if(clazz != null) {
592
            Set<AutoPropertyInitializer<CdmBase>> inits = getAutoInitializers(clazz);
593
            for (AutoPropertyInitializer<CdmBase> init: inits){
594
                try {
595
                    Optional<String> fetchJoin = init.hibernateFetchJoin(clazz, beanAlias);
596
                    if(fetchJoin.isPresent()) {
597
                        autoInit.leftJoinFetch += fetchJoin.get();
598
                    } else {
599
                        // the AutoPropertyInitializer is not supporting LEFT JOIN FETCH so it needs to be
600
                        // used explicitly
601
                        autoInit.initlializers.add(init);
602
                    }
603
                } catch (Exception e) {
604
                    // should not happen, but just in case we fall back to explicit initialization
605
                    // and log the error
606
                    logger.error("error in fetch join processing, falling back to explicit initialization", e);
607
                    autoInit.initlializers.add(init);
608
                }
609

    
610
            }
611
        }
612
        return autoInit;
613
    }
614

    
615
    private Set<AutoPropertyInitializer<CdmBase>> getAutoInitializers(Class<?> clazz) {
616
        Set<AutoPropertyInitializer<CdmBase>> result = new HashSet<AutoPropertyInitializer<CdmBase>>();
617
        for(Class<? extends CdmBase> superClass : getBeanAutoInitializers().keySet()){
618
            if(superClass.isAssignableFrom(clazz)){
619
                result.add(getBeanAutoInitializers().get(superClass));
620
            }
621
        }
622
        return result;
623
    }
624

    
625
    /**
626
     * Rename hibernate (field) attribute to Bean property name, due to bean inconsistencies
627
     * #3841
628
     * @param param
629
     * @param ownerClass
630
     * @return
631
     */
632
    private String mapFieldToPropertyName(String param, String ownerClass) {
633
        if (ownerClass.contains("Description") && param.equals("descriptionElements")){
634
            return "elements";
635
        }
636
        if (ownerClass.startsWith("TermNode") && param.equals("children")) {
637
            return "childNodes";
638
        }
639
        if (ownerClass.startsWith("Media") && param.equals("description")) {
640
            return "allDescriptions";
641
        }
642
        else{
643
            return param;
644
        }
645
    }
646

    
647
    /**
648
     * @param node
649
     * @param property
650
     * @param index
651
     * @param bean
652
     * @param unwrappedPropertyBean
653
     */
654
    private void initializeNodeSinglePropertyOld(BeanInitNode node, String property,
655
            Integer index, Object bean, Object unwrappedPropertyBean) {
656
        Collection<?> collection = null;
657
        if(Map.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {
658
            collection = ((Map<?,?>)unwrappedPropertyBean).values();
659
        }else if (Collection.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {
660
            collection =  (Collection<?>) unwrappedPropertyBean;
661
        }
662
        if (collection != null){
663
            //collection or map
664
            if (logger.isTraceEnabled()){logger.trace(" initialize collection for " + node.toStringNoWildcard() + " ... ");}
665
            int i = 0;
666
            for (Object entrybean : collection) {
667
                if(index == null){
668
                    node.addBean(entrybean);
669
                } else if(index.equals(i)){
670
                    node.addBean(entrybean);
671
                    break;
672
                }
673
                i++;
674
            }
675
            if (logger.isTraceEnabled()){logger.trace(" initialize collection for " + node.toString() + " - DONE ");}
676

    
677
        }else {
678
            // nested bean
679
            node.addBean(unwrappedPropertyBean);
680
            setProperty(bean, property, unwrappedPropertyBean);
681
        }
682
    }
683

    
684
    private class AutoInit{
685

    
686
        String leftJoinFetch = "";
687
        Set<AutoPropertyInitializer<CdmBase>> initlializers = new HashSet<AutoPropertyInitializer<CdmBase>>();
688

    
689
        /**
690
         * @param leftJoinFetch
691
         * @param initlializers
692
         */
693
        public AutoInit() {
694
        }
695
    }
696
}
(2-2/15)