cleanup
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / initializer / AdvancedBeanInitializer.java
1 /**
2 * Copyright (C) 2009 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.persistence.dao.initializer;
10
11 import java.beans.PropertyDescriptor;
12 import java.io.Serializable;
13 import java.lang.reflect.InvocationTargetException;
14 import java.lang.reflect.Method;
15 import java.lang.reflect.ParameterizedType;
16 import java.lang.reflect.Type;
17 import java.lang.reflect.TypeVariable;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Optional;
25 import java.util.Set;
26
27 import org.apache.commons.beanutils.PropertyUtils;
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.hibernate.Hibernate;
31 import org.hibernate.HibernateException;
32 import org.hibernate.Query;
33 import org.hibernate.collection.internal.AbstractPersistentCollection;
34 import org.hibernate.collection.internal.PersistentMap;
35 import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.CollectionProxy;
36 import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.MapProxy;
37 import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.SortedMapProxy;
38 import org.hibernate.proxy.HibernateProxy;
39 import org.springframework.beans.factory.annotation.Autowired;
40
41 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
42 import eu.etaxonomy.cdm.model.common.CdmBase;
43 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
44 import eu.etaxonomy.cdm.persistence.dao.hibernate.HibernateBeanInitializer;
45 import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
46
47 /**
48 * Bean initializer with improved performance.
49
50 * @author a.mueller
51 * @since 2013-10-25
52 */
53 public class AdvancedBeanInitializer<CDM extends CdmBase> extends HibernateBeanInitializer<CDM> {
54
55 private static final Logger logger = LogManager.getLogger();
56
57 @Autowired
58 private ICdmGenericDao genericDao;
59
60 @Override
61 public void initialize(Object bean, List<String> propertyPaths) {
62 List<Object> beanList = new ArrayList<>(1);
63 beanList.add(bean);
64 initializeAll(beanList, propertyPaths);
65 }
66
67 //TODO optimize algorithm ..
68 @Override
69 public <C extends Collection<?>> C initializeAll(C beanList, List<String> propertyPaths) {
70
71 if (beanList == null || beanList.isEmpty()){
72 return beanList;
73 }
74
75 //autoinitialize
76 for (Object bean : beanList){
77 autoinitializeBean(bean);
78 }
79
80 if(propertyPaths == null){
81 return beanList;
82 }
83
84 //new
85 BeanInitNode rootPath = BeanInitNode.createInitTree(propertyPaths);
86 if (logger.isTraceEnabled()){logger.trace(rootPath.toStringTree());}
87
88 if(logger.isDebugEnabled()){ logger.debug(">> starting to initialize beanlist ; class(e.g.):" + beanList.iterator().next().getClass().getSimpleName());}
89 rootPath.addBeans(beanList);
90 initializeNodeRecursive(rootPath);
91
92 //old - keep for safety (this may help to initialize those beans that are not yet correctly initialized by the AdvancedBeanInitializer
93 if(logger.isTraceEnabled()){logger.trace("Start old initalizer ... ");};
94 for (Object bean :beanList){
95 Collections.sort(propertyPaths);
96 for(String propPath : propertyPaths){
97 // initializePropertyPath(bean, propPath);
98 }
99 }
100
101 if(logger.isDebugEnabled()){ logger.debug(" Completed initialization of beanlist "); }
102 return beanList;
103 }
104
105
106 //new
107 private void initializeNodeRecursive(BeanInitNode rootPath) {
108 initializeNode(rootPath);
109 for (BeanInitNode childPath : rootPath.getChildrenList()){
110 initializeNodeRecursive(childPath);
111 }
112 rootPath.resetBeans();
113 }
114
115 /**
116 * Initializes the given single <code>propPath</code> String.
117 *
118 * @param bean
119 * @param propPath
120 */
121 private void initializeNode(BeanInitNode node) {
122 if(logger.isDebugEnabled()){logger.debug(" processing " + node.toString());}
123 if (node.isRoot()){
124 return;
125 }else if (node.isWildcard()){
126 initializeNodeWildcard(node);
127 } else {
128 initializeNodeNoWildcard(node);
129 }
130 }
131
132 // if propPath only contains a wildcard (* or $)
133 // => do a batch initialization of *toOne or *toMany relations
134 private void initializeNodeWildcard(BeanInitNode node) {
135 // boolean initToMany = node.isToManyWildcard();
136 Map<Class<?>, Set<Object>> parentBeans = node.getParentBeans();
137 for (Class<?> clazz : parentBeans.keySet()){
138 //new
139 for (Object bean : parentBeans.get(clazz)){
140
141 if(Collection.class.isAssignableFrom(bean.getClass())){
142 // old: initializeAllEntries((Collection<?>)bean, true, initToMany); //TODO is this a possible case at all??
143 throw new RuntimeException("Collection no longer expected in 'initializeNodeWildcard()'. Therefore an exception is thrown.");
144 } else if(Map.class.isAssignableFrom(bean.getClass())) {
145 // old: initializeAllEntries(((Map<?,?>)bean).values(), true, initToMany); ////TODO is this a possible case at all??
146 throw new RuntimeException("Map no longer expected in 'initializeNodeWildcard()'. Therefore an exception is thrown.");
147 } else{
148 prepareBeanWildcardForBulkLoad(node, bean);
149 }
150 }
151 //end new
152
153 // initializeNodeWildcardOld(initToMany, beans, clazz); //if switched on move bulkLoadLazies up
154 }
155
156 //
157 bulkLoadLazies(node);
158 }
159
160 /**
161 * @param initToMany
162 * @param beans
163 * @param clazz
164 */
165 private void initializeNodeWildcardOld(boolean initToMany,
166 Map<Class<?>, Set<Object>> beans, Class<?> clazz) {
167 for (Object bean : beans.get(clazz)){
168
169 if(Collection.class.isAssignableFrom(bean.getClass())){
170 initializeAllEntries((Collection<?>)bean, true, initToMany);
171 } else if(Map.class.isAssignableFrom(bean.getClass())) {
172 initializeAllEntries(((Map<?,?>)bean).values(), true, initToMany);
173 } else{
174 initializeBean(bean, true, initToMany);
175 }
176 }
177 }
178
179 private void prepareBeanWildcardForBulkLoad(BeanInitNode node, Object bean){
180
181 if(logger.isTraceEnabled()){logger.trace(">> prepare bulk wildcard initialization of a bean of type " + bean.getClass().getSimpleName()); }
182 Set<Class<?>> restrictions = new HashSet<Class<?>>();
183 restrictions.add(CdmBase.class);
184 if(node.isToManyWildcard()){
185 restrictions.add(Collection.class);
186 }
187 Set<PropertyDescriptor> props = getProperties(bean, restrictions);
188 for(PropertyDescriptor propertyDescriptor : props){
189 try {
190 String property = propertyDescriptor.getName();
191
192 // invokeInitialization(bean, propertyDescriptor);
193 Object propertyValue = PropertyUtils.getProperty( bean, property);
194
195 preparePropertyValueForBulkLoadOrStore(node, bean, property, propertyValue );
196
197 } catch (IllegalAccessException e) {
198 logger.error("Illegal access on property " + propertyDescriptor.getName());
199 } catch (InvocationTargetException e) {
200 logger.info("Cannot invoke property " + propertyDescriptor.getName() + " not found");
201 } catch (NoSuchMethodException e) {
202 logger.info("Property " + propertyDescriptor.getName() + " not found");
203 }
204 }
205 if(logger.isTraceEnabled()){logger.trace(" completed bulk wildcard initialization of a bean");}
206 }
207
208
209 /**
210 * Initializes all objects matching the given node, where the
211 * node does not represent a wildcard but a single field or
212 * a nested path. Splits the next path token off and keeps
213 * the remaining as nestedPath
214 *
215 * @param node
216 */
217 private void initializeNodeNoWildcard(BeanInitNode node) {
218
219 String property = node.getPath();
220 int pos;
221
222 // is the property indexed?
223 Integer index = null;
224 if((pos = property.indexOf('[')) > 0){
225 String indexString = property.substring(pos + 1, property.indexOf(']'));
226 index = Integer.valueOf(indexString);
227 property = property.substring(0, pos);
228 }
229
230 //Class targetClass = HibernateProxyHelper.getClassWithoutInitializingProxy(bean); // used for debugging
231
232 for (Class<?> parentClazz : node.getParentBeans().keySet()){
233 if (logger.isTraceEnabled()){logger.trace(" invoke initialization on "+ node.toString()+ " beans of class " + parentClazz.getSimpleName() + " ... ");}
234
235 Set<Object> parentBeans = node.getParentBeans().get(parentClazz);
236
237 if (index != null){
238 logger.warn("Property path index not yet implemented for 'new'");
239 }
240 //new
241 for (Object parentBean : parentBeans){
242 preparePropertyForSingleBean(node, property, parentClazz, parentBean);
243 }//end for
244 //end new
245 // initializeNodeNoWildcardOld(node, property, index, parentBeans); //move bulkLoadLazies up again, if uncomment this line
246 } //end for
247 bulkLoadLazies(node);
248 }
249
250 /**
251 * Prepare a single property of a non-collection bean. Collections are handled elsewhere.
252 */
253 private void preparePropertyForSingleBean(BeanInitNode node, String property, Class<?> parentClazz, Object bean) {
254 String propertyName = mapFieldToPropertyName(property, bean.getClass().getSimpleName());
255 try{
256 Object propertyValue = PropertyUtils.getProperty(bean, propertyName);
257 preparePropertyValueForBulkLoadOrStore(node, bean, property, propertyValue);
258 } catch (IllegalAccessException e) {
259 String message = "Illegal access on property " + property;
260 logger.error(message);
261 throw new RuntimeException(message, e);
262 } catch (InvocationTargetException e) {
263 String message = "Cannot invoke property " + property + " not found";
264 logger.error(message);
265 throw new RuntimeException(message, e);
266 } catch (NoSuchMethodException e) {
267 String message = "Property " + propertyName + " not found for class " + parentClazz;
268 logger.info(message);
269 //don't throw exception as sometimes property paths will include non matching property names due to subclassing
270 //#5077 comment 12
271 }
272 }
273
274 // /**
275 // * @param node
276 // * @param property
277 // * @param index
278 // * @param parentBeans
279 // * @throws IllegalAccessException
280 // * @throws InvocationTargetException
281 // * @throws NoSuchMethodException
282 // */
283 // private void initializeNodeNoWildcardOld(BeanInitNode node,
284 // String property,
285 // Integer index,
286 // Set<Object> parentBeans)
287 // throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
288 // {
289 // for (Object bean : parentBeans){
290 //
291 // PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(bean, property);
292 // if (logger.isTraceEnabled()){logger.trace(" unwrap " + node.toStringNoWildcard() + " ... ");}
293 // // [1] initialize the bean named by property
294 // Object unwrappedPropertyBean = invokeInitialization(bean, propertyDescriptor);
295 // if (logger.isTraceEnabled()){logger.trace(" unwrap " + node.toStringNoWildcard() + " - DONE ");}
296 //
297 //
298 // // [2]
299 // // handle property
300 // if(unwrappedPropertyBean != null ){
301 // initializeNodeSinglePropertyOld(node, property, index, bean, unwrappedPropertyBean);
302 // }
303 // }
304 // }
305
306 /**
307 * @param node
308 * @param propertyValue
309 * @param parentBean
310 * @param param
311 */
312 private void preparePropertyValueForBulkLoadOrStore(BeanInitNode node,
313 Object parentBean,
314 String param,
315 Object propertyValue)
316 {
317 BeanInitNode sibling = node.getSibling(param);
318
319 if (propertyValue instanceof AbstractPersistentCollection ){
320 //collections
321 if (!node.hasWildcardToManySibling()){ //if wildcard sibling exists the lazies are already prepared there
322 AbstractPersistentCollection collection = (AbstractPersistentCollection)propertyValue;
323 if (collection.wasInitialized()){
324 storeInitializedCollection(collection, node, param);
325 }else{
326 // Class<?> parentClass = parentBean.getClass();
327 // int parentId = ((CdmBase)parentBean).getId();
328 if (sibling != null){
329 sibling.putLazyCollection(collection);
330 }else{
331 node.putLazyCollection(collection);
332 }
333 }
334 }
335 } else if (propertyValue instanceof CollectionProxy
336 || propertyValue instanceof MapProxy<?, ?>
337 || propertyValue instanceof SortedMapProxy<?, ?>){
338 //hibernate envers collections
339 //TODO check if other code works with audited data at all as we use HQL queries
340 if (!node.hasWildcardToManySibling()){ //if wildcard sibling exists the lazies are already prepared there
341 Collection<?> collection = (Collection<?>)propertyValue;
342 //TODO it is difficult to find out if an envers collection is initialized
343 //but possibly via reflection. If the "delegate" parameter is null it is not yet initialized.
344 //However, as we do not know if envers initialization works at all together with the AdvancedBeanInitializer
345 //we initialize each collection immediately here by calling size()
346 collection.size(); //initialize
347 storeInitializedEnversCollection(collection, node, param);
348 }
349 }else{
350 //singles
351 if (!node.hasWildcardToOneSibling()){ //if wildcard exists the lazies are already prepared there
352 if (! Hibernate.isInitialized(propertyValue)){
353 if (propertyValue instanceof HibernateProxy){
354 Serializable id = ((HibernateProxy)propertyValue).getHibernateLazyInitializer().getIdentifier();
355 Class<?> persistedClass = ((HibernateProxy)propertyValue).getHibernateLazyInitializer().getPersistentClass();
356 if (sibling != null){
357 sibling.putLazyBean(persistedClass, id);
358 }else{
359 node.putLazyBean(persistedClass, id);
360 }
361
362 }else{
363 logger.warn("Lazy value is not of type HibernateProxy. This is not yet handled.");
364 }
365 }else if (propertyValue == null){
366 // do nothing
367 }else{
368 if (propertyValue instanceof HibernateProxy){ //TODO remove hibernate dependency
369 propertyValue = initializeInstance(propertyValue);
370 }
371 autoinitializeBean(propertyValue);
372 node.addBean(propertyValue);
373 }
374 }
375 }
376 }
377
378 private void autoinitializeBean(Object bean) {
379 invokePropertyAutoInitializers(bean);
380 }
381
382 private void autoinitializeBean(CdmBase bean, AutoInit autoInit) {
383 for(AutoPropertyInitializer<CdmBase> init : autoInit.initlializers) {
384 if(logger.isTraceEnabled()) {
385 logger.trace("invoking " + init.getClass().getSimpleName() + ".initialize(" + bean.getClass().getSimpleName() + ")");
386 }
387 init.initialize(bean);
388 }
389 }
390
391 private void storeInitializedCollection(AbstractPersistentCollection persistedCollection,
392 BeanInitNode node, String param) {
393
394 Collection<?> collection;
395 if (persistedCollection instanceof Collection) {
396 collection = (Collection<?>) persistedCollection;
397 }else if (persistedCollection instanceof Map) {
398 collection = ((Map<?,?>)persistedCollection).values();
399 }else{
400 throw new RuntimeException ("Non Map and non Collection cas not handled in storeInitializedCollection()");
401 }
402 for (Object value : collection){
403 preparePropertyValueForBulkLoadOrStore(node, null, param, value);
404 }
405 }
406
407 /**
408 * @see #storeInitializedCollection(AbstractPersistentCollection, BeanInitNode, String)alizedCollection
409 */
410 private void storeInitializedEnversCollection(Collection<?> enversCollection,
411 BeanInitNode node, String param) {
412 if (enversCollection instanceof CollectionProxy
413 || enversCollection instanceof MapProxy<?, ?>
414 || enversCollection instanceof SortedMapProxy<?, ?>){
415 Collection<?> collection;
416 if (enversCollection instanceof MapProxy
417 || enversCollection instanceof SortedMapProxy<?, ?>) {
418 collection = ((Map<?,?>)enversCollection).values();
419 }else if (enversCollection instanceof CollectionProxy) {
420 collection = enversCollection;
421 }else{
422 throw new RuntimeException ("Non MapProxy and non CollectionProxy case not handled in storeInitializedEnversCollection()");
423 }
424 for (Object value : collection){
425 preparePropertyValueForBulkLoadOrStore(node, null, param, value);
426 }
427 }
428 }
429
430
431 /**
432 * Load all beans which are added to the node
433 * and which are not yet initialized in bulk.
434 * @param node
435 */
436 private void bulkLoadLazies(BeanInitNode node) {
437 if (logger.isTraceEnabled()){logger.trace("bulk load " + node);}
438 //beans
439 bulkLoadLazyBeans(node);
440 //collections
441 bulkLoadLazyCollections(node);
442 if (logger.isDebugEnabled()){logger.debug("bulk load " + node + " - DONE ");}
443 }
444
445
446 /**
447 * Loads all lazy beans added to the node and empty the lazy bean collection of the node.
448 * Lazy collections are initialized elsewhere: {@link #bulkLoadLazyCollections(BeanInitNode)}
449 * @param node the {@link BeanInitNode} to load the lazy beans for
450 */
451 private void bulkLoadLazyBeans(BeanInitNode node) {
452 for (Class<?> clazz : node.getLazyBeans().keySet()){
453 Set<Serializable> idSet = node.getLazyBeans().get(clazz);
454 if (idSet != null && ! idSet.isEmpty()){
455
456 if (logger.isTraceEnabled()){logger.trace("bulk load beans of class " + clazz.getSimpleName());}
457 //TODO use entity name
458 String hql = " SELECT c FROM %s as c %s WHERE c.id IN (:idSet) ";
459 AutoInit autoInit = addAutoinitFetchLoading(clazz, "c");
460 hql = String.format(hql, clazz.getSimpleName(), autoInit.leftJoinFetch);
461 if (logger.isTraceEnabled()){logger.trace(hql);}
462 Query query = genericDao.getHqlQuery(hql);
463 query.setParameterList("idSet", idSet);
464 @SuppressWarnings("unchecked")
465 List<Object> list = query.list();
466
467 if (logger.isTraceEnabled()){
468 // String beanList = "";
469 // for(Object id : idSet){
470 // Set<Serializable> bean = node.getLazyBeans().get(id);
471 // beanList += bean.getClass().getSimpleName() + "<" + id + "> ";
472 // }
473 logger.trace("initialize bulk loaded beans of class " + clazz.getSimpleName() + ": " + idSet );
474 }
475 for (Object object : list){
476 if (object instanceof HibernateProxy){ //TODO remove hibernate dependency
477 object = initializeInstance(object);
478 }
479 autoinitializeBean((CdmBase)object, autoInit);
480 node.addBean(object);
481 }
482 if (logger.isTraceEnabled()){logger.trace("bulk load - DONE");}
483 }
484 }
485 node.resetLazyBeans();
486 }
487
488 /**
489 * Loads all lazy collections added to the node and empty the lazy collections collection of the node.
490 * Lazy beans are initialized elsewhere: {@link #bulkLoadLazyBeans(BeanInitNode)}
491 * @param node the {@link BeanInitNode} to load the lazy beans for
492 */
493 private void bulkLoadLazyCollections(BeanInitNode node) {
494 for (Class<?> ownerClazz : node.getLazyCollections().keySet()){
495 Map<String, Set<Serializable>> lazyParams = node.getLazyCollections().get(ownerClazz);
496 for (String param : lazyParams.keySet()){
497 Set<Serializable> idSet = lazyParams.get(param);
498 if (idSet != null && ! idSet.isEmpty()){
499 if (logger.isTraceEnabled()){logger.trace("bulk load " + node + " collections ; ownerClass=" + ownerClazz.getSimpleName() + " ; param = " + param);}
500
501 Type collectionEntitiyType = null;
502 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(ownerClazz);
503 for(PropertyDescriptor d : descriptors) {
504 if(d.getName().equals(param)) {
505 Method readMethod = d.getReadMethod();
506 ParameterizedType pt = (ParameterizedType) readMethod.getGenericReturnType();
507 Type[] actualTypeArguments = pt.getActualTypeArguments();
508 if(actualTypeArguments.length == 2) {
509 // this must be a map of <Language, String> (aka LanguageString) there is no other case like this in the cdm
510 // in case of Maps the returned Collection will be the Collection of the values, so collectionEntitiyType is the
511 // second typeArgument
512 collectionEntitiyType = actualTypeArguments[1];
513 } else {
514 collectionEntitiyType = actualTypeArguments[0];
515 }
516 if(collectionEntitiyType instanceof TypeVariable) {
517 collectionEntitiyType = ((TypeVariable)collectionEntitiyType).getBounds()[0];
518 }
519 }
520 }
521
522 //TODO use entity name ??
523 //get from repository
524 List<Object[]> list;
525 String hql = "SELECT oc " +
526 " FROM %s as oc LEFT JOIN FETCH oc.%s as col %s" +
527 " WHERE oc.id IN (:idSet) ";
528
529 if (collectionEntitiyType instanceof ParameterizedTypeImpl){
530 collectionEntitiyType = ((ParameterizedTypeImpl)collectionEntitiyType).getRawType();
531 }
532 AutoInit autoInit = addAutoinitFetchLoading((Class<?>)collectionEntitiyType, "col");
533 hql = String.format(hql, ownerClazz.getSimpleName(), param,
534 autoInit.leftJoinFetch);
535
536 try {
537 if (logger.isTraceEnabled()){logger.trace(hql);}
538 Query query = genericDao.getHqlQuery(hql);
539 query.setParameterList("idSet", idSet);
540 list = query.list();
541 if (logger.isTraceEnabled()){logger.trace("size of retrieved list is " + list.size());}
542 } catch (HibernateException e) {
543 e.printStackTrace();
544 throw e;
545 }
546
547 //getTarget and add to child node
548 if (logger.isTraceEnabled()){logger.trace("initialize bulk loaded " + node + " collections - DONE");}
549 for (Object parentBean : list){
550 try {
551 Object propValue = PropertyUtils.getProperty(
552 parentBean,
553 mapFieldToPropertyName(param, parentBean.getClass().getSimpleName())
554 );
555
556 if (propValue == null){
557 logger.trace("Collection is null");
558 }else {
559 if(propValue instanceof PersistentMap) {
560 propValue = ((PersistentMap)propValue).values();
561 }
562 for(Object newBean : (Collection<Object>)propValue ) {
563 if(newBean instanceof HibernateProxy){
564 newBean = initializeInstance(newBean);
565 }
566
567 if (HibernateProxyHelper.isInstanceOf(newBean, CdmBase.class)){
568 autoinitializeBean((CdmBase)newBean, autoInit);
569 }
570 node.addBean(newBean);
571 }
572 }
573 } catch (Exception e) {
574 // TODO better throw an exception ?
575 logger.error("error while getting collection property", e);
576 }
577 }
578 if (logger.isTraceEnabled()){logger.trace("bulk load " + node + " collections - DONE");}
579 }
580 }
581 }
582 for (AbstractPersistentCollection collection : node.getUninitializedCollections()){
583 if (! collection.wasInitialized()){ //should not happen anymore
584 collection.forceInitialization();
585 if (logger.isTraceEnabled()){logger.trace("forceInitialization of collection " + collection);}
586 } else {
587 if (logger.isTraceEnabled()){logger.trace("collection " + collection + " is initialized - OK!");}
588 }
589 }
590
591 node.resetLazyCollections();
592 }
593
594 private AutoInit addAutoinitFetchLoading(Class<?> clazz, String beanAlias) {
595
596 AutoInit autoInit = new AutoInit();
597 if(clazz != null) {
598 Set<AutoPropertyInitializer<CdmBase>> inits = getAutoInitializers(clazz);
599 for (AutoPropertyInitializer<CdmBase> init: inits){
600 try {
601 Optional<String> fetchJoin = init.hibernateFetchJoin(clazz, beanAlias);
602 if(fetchJoin.isPresent()) {
603 logger.trace("applying fetch join of " + init.getClass().getSimpleName());
604 autoInit.leftJoinFetch += fetchJoin.get();
605 } else {
606 // the AutoPropertyInitializer is not supporting LEFT JOIN FETCH so it needs to be
607 // used explicitly
608
609 logger.trace("adding property calling initializer: " + init.getClass().getSimpleName());
610 autoInit.initlializers.add(init);
611 }
612 } catch (Exception e) {
613 // should not happen, but just in case we fall back to explicit initialization
614 // and log the error
615 logger.error("error in fetch join processing, falling back to explicit initialization", e);
616 autoInit.initlializers.add(init);
617 }
618
619 }
620 }
621 return autoInit;
622 }
623
624 private Set<AutoPropertyInitializer<CdmBase>> getAutoInitializers(Class<?> clazz) {
625 Set<AutoPropertyInitializer<CdmBase>> result = new HashSet<AutoPropertyInitializer<CdmBase>>();
626 for(Class<? extends CdmBase> superClass : getBeanAutoInitializers().keySet()){
627 if(superClass.isAssignableFrom(clazz)){
628 result.add((AutoPropertyInitializer<CdmBase>) getBeanAutoInitializers().get(superClass));
629 }
630 }
631 return result;
632 }
633
634 /**
635 * Rename hibernate (field) attribute to Bean property name, due to bean inconsistencies
636 * #3841
637 * @param param
638 * @param ownerClass
639 * @return
640 */
641 private String mapFieldToPropertyName(String param, String ownerClass) {
642 if (ownerClass.contains("Description") && param.equals("descriptionElements")){
643 return "elements";
644 }
645 if (ownerClass.startsWith("TermNode") && param.equals("children")) {
646 return "childNodes";
647 }
648 if (ownerClass.startsWith("Media") && param.equals("description")) {
649 return "allDescriptions";
650 }
651 else{
652 return param;
653 }
654 }
655
656 /**
657 * @param node
658 * @param property
659 * @param index
660 * @param bean
661 * @param unwrappedPropertyBean
662 */
663 private void initializeNodeSinglePropertyOld(BeanInitNode node, String property,
664 Integer index, Object bean, Object unwrappedPropertyBean) {
665 Collection<?> collection = null;
666 if(Map.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {
667 collection = ((Map<?,?>)unwrappedPropertyBean).values();
668 }else if (Collection.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {
669 collection = (Collection<?>) unwrappedPropertyBean;
670 }
671 if (collection != null){
672 //collection or map
673 if (logger.isTraceEnabled()){logger.trace(" initialize collection for " + node.toStringNoWildcard() + " ... ");}
674 int i = 0;
675 for (Object entrybean : collection) {
676 if(index == null){
677 node.addBean(entrybean);
678 } else if(index.equals(i)){
679 node.addBean(entrybean);
680 break;
681 }
682 i++;
683 }
684 if (logger.isTraceEnabled()){logger.trace(" initialize collection for " + node.toString() + " - DONE ");}
685
686 }else {
687 // nested bean
688 node.addBean(unwrappedPropertyBean);
689 setProperty(bean, property, unwrappedPropertyBean);
690 }
691 }
692
693 private class AutoInit{
694
695 String leftJoinFetch = "";
696 Set<AutoPropertyInitializer<CdmBase>> initlializers = new HashSet<>();
697
698 public AutoInit() {
699 }
700 }
701 }