/**\r
- * \r
+ *\r
*/\r
package eu.etaxonomy.cdm.persistence.dao.initializer;\r
\r
import java.beans.PropertyDescriptor;\r
+import java.io.Serializable;\r
import java.lang.reflect.InvocationTargetException;\r
-import java.lang.reflect.Method;\r
-import java.lang.reflect.ParameterizedType;\r
-import java.lang.reflect.Type;\r
+import java.util.ArrayList;\r
import java.util.Collection;\r
import java.util.Collections;\r
import java.util.HashSet;\r
import java.util.Set;\r
\r
import org.apache.commons.beanutils.PropertyUtils;\r
-import org.apache.commons.lang.StringUtils;\r
import org.apache.log4j.Logger;\r
+import org.hibernate.Hibernate;\r
+import org.hibernate.HibernateException;\r
+import org.hibernate.Query;\r
+import org.hibernate.collection.internal.AbstractPersistentCollection;\r
+import org.hibernate.proxy.HibernateProxy;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
+import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;\r
import eu.etaxonomy.cdm.persistence.dao.hibernate.HibernateBeanInitializer;\r
\r
/**\r
- * For now this is to test if we can improve performance for bean initializing\r
+ * For now this is a test if we can improve performance for bean initializing\r
* @author a.mueller\r
* @date 2013-10-25\r
*\r
*/\r
public class AdvancedBeanInitializer extends HibernateBeanInitializer {\r
\r
- public static final Logger logger = Logger.getLogger(AdvancedBeanInitializer.class);\r
- \r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.persistence.dao.BeanInitializer#load(eu.etaxonomy.cdm.model.common.CdmBase)\r
- */\r
- @Override\r
- public void load(Object bean) {\r
- initializeBean(bean, true, false);\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.persistence.dao.BeanInitializer#loadFully(eu.etaxonomy.cdm.model.common.CdmBase)\r
- */\r
- @Override\r
- public void loadFully(Object bean) {\r
- initializeBean(bean, true, true);\r
- }\r
-\r
- /**\r
- * Initializes all *toOne relations of the given bean and all *toMany\r
- * relations, depending on the state of the boolean parameters\r
- * <code>cdmEntities</code> and <code>collections</code>\r
- *\r
- * @param bean\r
- * the bean to initialize\r
- * @param cdmEntities\r
- * initialize all *toOne relations to cdm entities\r
- * @param collections\r
- * initialize all *toMany relations\r
- */\r
- public void initializeBean(Object bean, boolean cdmEntities, boolean collections){\r
-\r
- if(logger.isDebugEnabled()){\r
- logger.debug(">> starting initializeBean() of " + bean + " ;class:" + bean.getClass().getSimpleName());\r
- }\r
- Set<Class> restrictions = new HashSet<Class>();\r
- if(cdmEntities){\r
- restrictions.add(CdmBase.class);\r
- }\r
- if(collections){\r
- restrictions.add(Collections.class);\r
- }\r
- Set<PropertyDescriptor> props = getProperties(bean, restrictions);\r
- for(PropertyDescriptor propertyDescriptor : props){\r
- try {\r
-\r
- invokeInitialization(bean, propertyDescriptor);\r
-\r
- } catch (IllegalAccessException e) {\r
- logger.error("Illegal access on property " + propertyDescriptor.getName());\r
- } catch (InvocationTargetException e) {\r
- logger.info("Cannot invoke property " + propertyDescriptor.getName() + " not found");\r
- } catch (NoSuchMethodException e) {\r
- logger.info("Property " + propertyDescriptor.getName() + " not found");\r
- }\r
- }\r
- if(logger.isDebugEnabled()){\r
- logger.debug(" completed initializeBean() of " + bean);\r
- }\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.persistence.dao.BeanInitializer#initializeProperties(java.lang.Object, java.util.List)\r
- */\r
- //TODO optimize algorithm ..\r
- @Override\r
- public void initialize(Object bean, List<String> propertyPaths) {\r
-\r
- invokePropertyAutoInitializers(bean);\r
-\r
- if(propertyPaths == null){\r
- return;\r
- }\r
-\r
- if(logger.isDebugEnabled()){\r
- logger.debug(">> starting to initialize " + bean + " ;class:" + bean.getClass().getSimpleName());\r
- }\r
- \r
- //new\r
- BeanInitNode rootInitializer = BeanInitNode.createInitTree(propertyPaths);\r
- System.out.println(rootInitializer.toStringTree());\r
- initializeBean(bean, rootInitializer);\r
- \r
- \r
- //old\r
- Collections.sort(propertyPaths);\r
- for(String propPath : propertyPaths){\r
- initializePropertyPath(bean, propPath);\r
- }\r
- if(logger.isDebugEnabled()){\r
- logger.debug(" Completed initialization of " + bean);\r
- }\r
-\r
- }\r
- \r
-\r
- //new\r
- \r
- public void initializeBean(Object bean, BeanInitNode rootInitializer) {\r
- initializePropertyPath(bean, rootInitializer);\r
- for (BeanInitNode child : rootInitializer.getChildrenList()){\r
- initializeBean(bean, child);\r
- }\r
- }\r
- \r
-\r
- @Override\r
- public <C extends Collection<?>> C initializeAll(C beanList, List<String> propertyPaths) {\r
- if(propertyPaths != null){\r
- for(Object bean : beanList){\r
- initialize(bean, propertyPaths);\r
- }\r
- }\r
- return beanList;\r
- }\r
-\r
- /**\r
- * Initializes the given single <code>propPath</code> String.\r
- *\r
- * @param bean\r
- * @param propPath\r
- */\r
- void initializePropertyPath(Object bean, BeanInitNode node) {\r
- if(logger.isDebugEnabled()){logger.debug("processing " + node.toString());}\r
- if (StringUtils.isBlank(node.getPath())){\r
- return;\r
- }\r
-\r
- if (node.isWildcard()){\r
- initializeWildcardPropertyPath(bean, node);\r
- } else {\r
- initializeNoWildcardPropertyPath(bean, node);\r
- }\r
- }\r
-\r
- // if propPath only contains a wildcard (* or $)\r
+ public static final Logger logger = Logger.getLogger(AdvancedBeanInitializer.class);\r
+\r
+ @Autowired\r
+ ICdmGenericDao genericDao;\r
+\r
+ @Override\r
+ public void initialize(Object bean, List<String> propertyPaths) {\r
+ List<Object> beanList = new ArrayList<Object>(1);\r
+ beanList.add(bean);\r
+ initializeAll(beanList, propertyPaths);\r
+ }\r
+\r
+ //TODO optimize algorithm ..\r
+ @Override\r
+ public <C extends Collection<?>> C initializeAll(C beanList, List<String> propertyPaths) {\r
+\r
+ if (beanList == null || beanList.isEmpty()){\r
+ return beanList;\r
+ }\r
+\r
+ //autoinitialize\r
+ for (Object bean : beanList){\r
+ autoinitializeBean(bean);\r
+ }\r
+\r
+ if(propertyPaths == null){\r
+ return beanList;\r
+ }\r
+\r
+\r
+ //new\r
+ BeanInitNode rootPath = BeanInitNode.createInitTree(propertyPaths);\r
+ if (logger.isTraceEnabled()){logger.trace(rootPath.toStringTree());}\r
+\r
+\r
+ if(logger.isDebugEnabled()){ logger.debug(">> starting to initialize beanlist ; class(e.g.):" + beanList.iterator().next().getClass().getSimpleName());}\r
+ rootPath.addBeans(beanList);\r
+ initializeNodeRecursive(rootPath);\r
+\r
+\r
+ //old - keep for safety (this may help to initialize those beans that are not yet correctly initialized by the AdvancedBeanInitializer\r
+ if(logger.isTraceEnabled()){logger.trace("Start old initalizer ... ");};\r
+ for (Object bean :beanList){\r
+ Collections.sort(propertyPaths);\r
+ for(String propPath : propertyPaths){\r
+// initializePropertyPath(bean, propPath);\r
+ }\r
+ }\r
+\r
+ if(logger.isDebugEnabled()){ logger.debug(" Completed initialization of beanlist "); }\r
+ return beanList;\r
+\r
+ }\r
+\r
+\r
+ //new\r
+ private void initializeNodeRecursive(BeanInitNode rootPath) {\r
+ initializeNode(rootPath);\r
+ for (BeanInitNode childPath : rootPath.getChildrenList()){\r
+ initializeNodeRecursive(childPath);\r
+ }\r
+ rootPath.resetBeans();\r
+ }\r
+\r
+ /**\r
+ * Initializes the given single <code>propPath</code> String.\r
+ *\r
+ * @param bean\r
+ * @param propPath\r
+ */\r
+ private void initializeNode(BeanInitNode node) {\r
+ if(logger.isDebugEnabled()){logger.debug(" processing " + node.toString());}\r
+ if (node.isRoot()){\r
+ return;\r
+ }else if (node.isWildcard()){\r
+ initializeNodeWildcard(node);\r
+ } else {\r
+ initializeNodeNoWildcard(node);\r
+ }\r
+ }\r
+\r
+ // if propPath only contains a wildcard (* or $)\r
// => do a batch initialization of *toOne or *toMany relations\r
- private void initializeWildcardPropertyPath(Object bean, BeanInitNode node) {\r
- boolean initToMany = node.getPath().equals(LOAD_2ONE_2MANY_WILDCARD);\r
- if(Collection.class.isAssignableFrom(bean.getClass())){\r
- initializeAllEntries((Collection)bean, true, initToMany);\r
- } else if(Map.class.isAssignableFrom(bean.getClass())) {\r
- initializeAllEntries(((Map)bean).values(), true, initToMany);\r
- } else{\r
- initializeBean(bean, true, initToMany);\r
- }\r
+ private void initializeNodeWildcard(BeanInitNode node) {\r
+// boolean initToMany = node.isToManyWildcard();\r
+ Map<Class<?>, Set<Object>> parentBeans = node.getParentBeans();\r
+ for (Class<?> clazz : parentBeans.keySet()){\r
+ //new\r
+ for (Object bean : parentBeans.get(clazz)){\r
+\r
+ if(Collection.class.isAssignableFrom(bean.getClass())){\r
+// old: initializeAllEntries((Collection<?>)bean, true, initToMany); //TODO is this a possible case at all??\r
+ throw new RuntimeException("Collection no longer expected in 'initializeNodeWildcard()'. Therefore an exception is thrown.");\r
+ } else if(Map.class.isAssignableFrom(bean.getClass())) {\r
+// old: initializeAllEntries(((Map<?,?>)bean).values(), true, initToMany); ////TODO is this a possible case at all??\r
+ throw new RuntimeException("Map no longer expected in 'initializeNodeWildcard()'. Therefore an exception is thrown.");\r
+ } else{\r
+ prepareBeanWildcardForBulkLoad(node, bean);\r
+ }\r
+ }\r
+ //end new\r
+\r
+// initializeNodeWildcardOld(initToMany, beans, clazz); //if switched on move bulkLoadLazies up\r
+ }\r
+\r
+ //\r
+ bulkLoadLazies(node);\r
+ }\r
+\r
+ /**\r
+ * @param initToMany\r
+ * @param beans\r
+ * @param clazz\r
+ */\r
+ private void initializeNodeWildcardOld(boolean initToMany,\r
+ Map<Class<?>, Set<Object>> beans, Class<?> clazz) {\r
+ for (Object bean : beans.get(clazz)){\r
+\r
+ if(Collection.class.isAssignableFrom(bean.getClass())){\r
+ initializeAllEntries((Collection<?>)bean, true, initToMany);\r
+ } else if(Map.class.isAssignableFrom(bean.getClass())) {\r
+ initializeAllEntries(((Map<?,?>)bean).values(), true, initToMany);\r
+ } else{\r
+ initializeBean(bean, true, initToMany);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void prepareBeanWildcardForBulkLoad(BeanInitNode node, Object bean){\r
+\r
+ if(logger.isTraceEnabled()){logger.trace(">> prepare bulk wildcard initialization of a bean of type " + bean.getClass().getSimpleName()); }\r
+ Set<Class<?>> restrictions = new HashSet<Class<?>>();\r
+ restrictions.add(CdmBase.class);\r
+ if(node.isToManyWildcard()){\r
+ restrictions.add(Collection.class);\r
+ }\r
+ Set<PropertyDescriptor> props = getProperties(bean, restrictions);\r
+ for(PropertyDescriptor propertyDescriptor : props){\r
+ try {\r
+ String property = propertyDescriptor.getName();\r
+\r
+// invokeInitialization(bean, propertyDescriptor);\r
+ Object propertyValue = PropertyUtils.getProperty( bean, property);\r
+\r
+ preparePropertyValueForBulkLoadOrStore(node, bean, property, propertyValue );\r
+\r
+ } catch (IllegalAccessException e) {\r
+ logger.error("Illegal access on property " + propertyDescriptor.getName());\r
+ } catch (InvocationTargetException e) {\r
+ logger.info("Cannot invoke property " + propertyDescriptor.getName() + " not found");\r
+ } catch (NoSuchMethodException e) {\r
+ logger.info("Property " + propertyDescriptor.getName() + " not found");\r
+ }\r
+ }\r
+ if(logger.isTraceEnabled()){logger.trace(" completed bulk wildcard initialization of a bean");}\r
+ }\r
+\r
+\r
+\r
+ // propPath contains either a single field or a nested path\r
+ // split next path token off and keep the remaining as nestedPath\r
+ private void initializeNodeNoWildcard(BeanInitNode node) {\r
+\r
+ String property = node.getPath();\r
+ int pos;\r
+\r
+ // is the property indexed?\r
+ Integer index = null;\r
+ if((pos = property.indexOf('[')) > 0){\r
+ String indexString = property.substring(pos + 1, property.indexOf(']'));\r
+ index = Integer.valueOf(indexString);\r
+ property = property.substring(0, pos);\r
+ }\r
+\r
+ //Class targetClass = HibernateProxyHelper.getClassWithoutInitializingProxy(bean); // used for debugging\r
+\r
+ for (Class<?> parentClazz : node.getParentBeans().keySet()){\r
+ if (logger.isTraceEnabled()){logger.trace(" invoke initialization on "+ node.toString()+ " beans of class " + parentClazz.getSimpleName() + " ... ");}\r
+\r
+ Set<Object> parentBeans = node.getParentBeans().get(parentClazz);\r
+\r
+ if (index != null){\r
+ logger.warn("Property path index not yet implemented for 'new'");\r
+ }\r
+ //new\r
+ for (Object parentBean : parentBeans){\r
+ try{\r
+ Object propertyValue = PropertyUtils.getProperty(parentBean, mapFieldToPropertyName(property, parentBean.getClass().getSimpleName()));\r
+ preparePropertyValueForBulkLoadOrStore(node, parentBean, property, propertyValue);\r
+ } catch (IllegalAccessException e) {\r
+ logger.error("Illegal access on property " + property);\r
+ } catch (InvocationTargetException e) {\r
+ logger.error("Cannot invoke property " + property + " not found");\r
+ } catch (NoSuchMethodException e) {\r
+ if (logger.isDebugEnabled()){logger.debug("Property " + property + " not found for class " + parentClazz);}\r
+ }\r
+ }\r
+\r
+ //end new\r
+\r
+// initializeNodeNoWildcardOld(node, property, index, parentBeans); //move bulkLoadLazies up again, if uncomment this line\r
+ }\r
+ bulkLoadLazies(node);\r
+\r
+ }\r
+\r
+ /**\r
+ * @param node\r
+ * @param property\r
+ * @param index\r
+ * @param parentBeans\r
+ * @throws IllegalAccessException\r
+ * @throws InvocationTargetException\r
+ * @throws NoSuchMethodException\r
+ */\r
+ private void initializeNodeNoWildcardOld(BeanInitNode node,\r
+ String property, Integer index, Set<Object> parentBeans)\r
+ throws IllegalAccessException, InvocationTargetException,\r
+ NoSuchMethodException {\r
+ for (Object bean : parentBeans){\r
+\r
+ PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(bean, property);\r
+ if (logger.isTraceEnabled()){logger.trace(" unwrap " + node.toStringNoWildcard() + " ... ");}\r
+ // [1] initialize the bean named by property\r
+ Object unwrappedPropertyBean = invokeInitialization(bean, propertyDescriptor);\r
+ if (logger.isTraceEnabled()){logger.trace(" unwrap " + node.toStringNoWildcard() + " - DONE ");}\r
+\r
+\r
+ // [2]\r
+ // handle property\r
+ if(unwrappedPropertyBean != null ){\r
+ initializeNodeSinglePropertyOld(node, property, index, bean, unwrappedPropertyBean);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param node\r
+ * @param propertyValue\r
+ * @param parentBean\r
+ * @param param\r
+ */\r
+ private void preparePropertyValueForBulkLoadOrStore(BeanInitNode node, Object parentBean, String param, Object propertyValue) {\r
+ BeanInitNode sibling = node.getSibling(param);\r
+\r
+ if (propertyValue instanceof AbstractPersistentCollection ){\r
+ //collections\r
+ if (!node.hasWildcardToManySibling()){ //if wildcard sibling exists the lazies are already prepared there\r
+ AbstractPersistentCollection collection = (AbstractPersistentCollection)propertyValue;\r
+ if (collection.wasInitialized()){\r
+ storeInitializedCollection(collection, node, param);\r
+ }else{\r
+// Class<?> parentClass = parentBean.getClass();\r
+// int parentId = ((CdmBase)parentBean).getId();\r
+ if (sibling != null){\r
+ sibling.putLazyCollection(collection);\r
+ }else{\r
+ node.putLazyCollection(collection);\r
+ }\r
+ }\r
+ }\r
+ }else{\r
+ //singles\r
+ if (!node.hasWildcardToOneSibling()){ //if wildcard exists the lazies are already prepared there\r
+ if (! Hibernate.isInitialized(propertyValue)){\r
+ if (propertyValue instanceof HibernateProxy){\r
+ Serializable id = ((HibernateProxy)propertyValue).getHibernateLazyInitializer().getIdentifier();\r
+ Class<?> persistedClass = ((HibernateProxy)propertyValue).getHibernateLazyInitializer().getPersistentClass();\r
+ if (sibling != null){\r
+ sibling.putLazyBean(persistedClass, id);\r
+ }else{\r
+ node.putLazyBean(persistedClass, id);\r
+ }\r
+\r
+ }else{\r
+ logger.warn("Lazy value is not of type HibernateProxy. This is not yet handled.");\r
+ }\r
+ }else if (propertyValue == null){\r
+ // do nothing\r
+ }else{\r
+ if (propertyValue instanceof HibernateProxy){ //TODO remove hibernate dependency\r
+ propertyValue = initializeInstance(propertyValue);\r
+ }\r
+ autoinitializeBean(propertyValue);\r
+ node.addBean(propertyValue);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private void autoinitializeBean(Object bean) {\r
+ invokePropertyAutoInitializers(bean);\r
+ }\r
+\r
+ private void storeInitializedCollection(AbstractPersistentCollection persistedCollection,\r
+ BeanInitNode node, String param) {\r
+ Collection<?> collection;\r
+\r
+ if (persistedCollection instanceof Collection) {\r
+ collection = (Collection<?>) persistedCollection;\r
+ }else if (persistedCollection instanceof Map) {\r
+ collection = ((Map<?,?>)persistedCollection).values();\r
+ }else{\r
+ throw new RuntimeException ("Non Map and non Collection cas not handled in storeInitializedCollection()");\r
+ }\r
+ for (Object value : collection){\r
+ preparePropertyValueForBulkLoadOrStore(node, null, param, value);\r
+ }\r
}\r
\r
- // propPath contains either a single field or a nested path\r
- // split next path token off and keep the remaining as nestedPath\r
- private void initializeNoWildcardPropertyPath(Object bean, BeanInitNode node) {\r
- \r
- String property = node.getPath();\r
- int pos;\r
-\r
- // is the property indexed?\r
- Integer index = null;\r
- if((pos = property.indexOf('[')) > 0){\r
- String indexString = property.substring(pos + 1, property.indexOf(']'));\r
- index = Integer.valueOf(indexString);\r
- property = property.substring(0, pos);\r
+ private void bulkLoadLazies(BeanInitNode node) {\r
+\r
+ if (logger.isTraceEnabled()){logger.trace("bulk load " + node);}\r
+\r
+ //beans\r
+ for (Class<?> clazz : node.getLazyBeans().keySet()){\r
+ Set<Serializable> idSet = node.getLazyBeans().get(clazz);\r
+ if (idSet != null && ! idSet.isEmpty()){\r
+\r
+ if (logger.isTraceEnabled()){logger.trace("bulk load beans of class " + clazz.getSimpleName());}\r
+ //TODO use entity name\r
+ String hql = " SELECT c FROM %s as c %s WHERE c.id IN (:idSet) ";\r
+ hql = String.format(hql, clazz.getSimpleName(), addAutoinitFetchLoading(clazz, "c"));\r
+ if (logger.isTraceEnabled()){logger.trace(hql);}\r
+ Query query = genericDao.getHqlQuery(hql);\r
+ query.setParameterList("idSet", idSet);\r
+ List<Object> list = query.list();\r
+\r
+ if (logger.isTraceEnabled()){logger.trace("initialize bulk loaded beans of class " + clazz.getSimpleName());}\r
+ for (Object object : list){\r
+ if (object instanceof HibernateProxy){ //TODO remove hibernate dependency\r
+ object = initializeInstance(object);\r
+ }\r
+ autoinitializeBean(object);\r
+ node.addBean(object);\r
+ }\r
+ if (logger.isTraceEnabled()){logger.trace("bulk load - DONE");}\r
+ }\r
}\r
-\r
- try {\r
- //Class targetClass = HibernateProxyHelper.getClassWithoutInitializingProxy(bean); // used for debugging\r
-\r
- // [2.a] initialize the bean named by property\r
-\r
- PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(bean, property);\r
- if (logger.isDebugEnabled()){logger.debug("invokeInitialization "+node+" ... ");}\r
- Object unwrappedPropertyBean = invokeInitialization(bean, propertyDescriptor);\r
- if (logger.isDebugEnabled()){logger.debug("invokeInitialization "+node+" - DONE ");}\r
- //TODO continue\r
-// node.addBean(unwrappedPropertyBean);\r
- \r
- // [2.b]\r
- // recurse into nested properties\r
- if(unwrappedPropertyBean != null ){\r
- for (BeanInitNode childNode : node.getChildrenList()){\r
- Collection<?> collection = null;\r
- if(Map.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {\r
- collection = ((Map<?,?>)unwrappedPropertyBean).values();\r
- }else if (Collection.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {\r
- collection = (Collection<?>) unwrappedPropertyBean; \r
- }\r
- if (collection != null){\r
- //collection or map\r
- if (logger.isDebugEnabled()){logger.debug(" initialize collection for " + childNode.toString() + " ... ");}\r
- int i = 0;\r
- for (Object entrybean : collection) {\r
- if(index == null){\r
- initializePropertyPath(entrybean, childNode);\r
- } else if(index.equals(i)){\r
- initializePropertyPath(entrybean, childNode);\r
- break;\r
- }\r
- i++;\r
- }\r
- if (logger.isDebugEnabled()){logger.debug(" initialize collection for " + childNode.toString() + " - DONE ");}\r
- \r
- }else {\r
- // nested bean\r
- initializePropertyPath(unwrappedPropertyBean, childNode);\r
- setProperty(bean, property, unwrappedPropertyBean);\r
- }\r
- }\r
- }\r
-\r
- } catch (IllegalAccessException e) {\r
- logger.error("Illegal access on property " + property);\r
- } catch (InvocationTargetException e) {\r
- logger.error("Cannot invoke property " + property + " not found");\r
- } catch (NoSuchMethodException e) {\r
- logger.info("Property " + property + " not found");\r
+ node.resetLazyBeans();\r
+\r
+ //collections\r
+ for (Class<?> ownerClazz : node.getLazyCollections().keySet()){\r
+ Map<String, Set<Serializable>> lazyParams = node.getLazyCollections().get(ownerClazz);\r
+ for (String param : lazyParams.keySet()){\r
+ Set<Serializable> idSet = lazyParams.get(param);\r
+ if (idSet != null && ! idSet.isEmpty()){\r
+ if (logger.isTraceEnabled()){logger.trace("bulk load " + node + " collections ; ownerClass=" + ownerClazz.getSimpleName() + " ; param = " + param);}\r
+\r
+ //TODO use entity name ??\r
+ //get from repository\r
+ List<Object[]> list;\r
+ String hql = "SELECT oc " +\r
+ " FROM %s as oc JOIN FETCH oc.%s as col %s " +\r
+ " WHERE oc.id IN (:idSet) ";\r
+\r
+// String hql = "SELECT oc.%s " +\r
+// " FROM %s as oc WHERE oc.id IN (:idSet) ";\r
+ hql = String.format(hql, ownerClazz.getSimpleName(), param,\r
+ "" /*addAutoinitFetchLoading(clazz, "col")*/);\r
+\r
+ try {\r
+ if (logger.isTraceEnabled()){logger.trace(hql);}\r
+ Query query = genericDao.getHqlQuery(hql);\r
+ query.setParameterList("idSet", idSet);\r
+ list = query.list();\r
+ } catch (HibernateException e) {\r
+ e.printStackTrace();\r
+ throw e;\r
+ }\r
+\r
+ //getTarget and add to child node\r
+ if (logger.isTraceEnabled()){logger.trace("initialize bulk loaded " + node + " collections - DONE");}\r
+ for (Object parentBean : list){\r
+ try {\r
+ Object propValue = PropertyUtils.getProperty(\r
+ parentBean,\r
+ mapFieldToPropertyName(param, parentBean.getClass().getSimpleName())\r
+ );\r
+\r
+ if (propValue == null){\r
+ logger.trace("Collection is null");\r
+ }else {\r
+ for(Object newBean : (Collection<Object>)propValue ) {\r
+ if (newBean instanceof HibernateProxy){\r
+ newBean = initializeInstance(newBean);\r
+ }\r
+ autoinitializeBean(newBean);\r
+ node.addBean(newBean);\r
+ }\r
+ }\r
+ } catch (Exception e) {\r
+ // TODO better throw an exception ?\r
+ logger.error("error while getting collection property", e);\r
+ }\r
+ }\r
+ if (logger.isTraceEnabled()){logger.trace("bulk load " + node + " collections - DONE");}\r
+ }\r
+ }\r
}\r
+ for (AbstractPersistentCollection collection : node.getUninitializedCollections()){\r
+ if (! collection.wasInitialized()){ //should not happen anymore\r
+ collection.forceInitialization();\r
+ }\r
+ }\r
+\r
+ node.resetLazyCollections();\r
+\r
+ if (logger.isDebugEnabled()){logger.debug("bulk load " + node + " - DONE ");}\r
+\r
}\r
\r
- //TODO check if needed in advanced\r
- private Object invokeInitialization(Object bean, PropertyDescriptor propertyDescriptor) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {\r
-\r
- if(propertyDescriptor == null || bean == null){\r
- return null;\r
- }\r
-\r
- // (1)\r
- // initialialization of the bean\r
- //\r
- Object propertyProxy = PropertyUtils.getProperty( bean, propertyDescriptor.getName());\r
- Object propertyBean = initializeInstance(propertyProxy);\r
-\r
- if(propertyBean != null){\r
- // (2)\r
- // auto initialialization of sub properties\r
- //\r
- if(CdmBase.class.isAssignableFrom(propertyBean.getClass())){\r
-\r
- // initialization of a single bean\r
- CdmBase cdmBaseBean = (CdmBase)propertyBean;\r
- invokePropertyAutoInitializers(cdmBaseBean);\r
-\r
- } else if(Collection.class.isAssignableFrom(propertyBean.getClass()) ||\r
- Map.class.isAssignableFrom(propertyBean.getClass()) ) {\r
-\r
- // it is a collection or map\r
- Method readMethod = propertyDescriptor.getReadMethod();\r
- Type genericReturnType = readMethod.getGenericReturnType();\r
-\r
- if(genericReturnType instanceof ParameterizedType){\r
- ParameterizedType type = (ParameterizedType) genericReturnType;\r
- Type[] typeArguments = type.getActualTypeArguments();\r
-\r
- if(typeArguments.length > 0\r
- && typeArguments[0] instanceof Class<?>\r
- && CdmBase.class.isAssignableFrom((Class<?>) typeArguments[0])){\r
-\r
- if(Collection.class.isAssignableFrom((Class<?>) type.getRawType())){\r
- for(CdmBase entry : ((Collection<CdmBase>)propertyBean)){\r
- invokePropertyAutoInitializers(entry);\r
- }\r
- }\r
- }\r
-\r
- }\r
- }\r
- }\r
-\r
- return propertyBean;\r
- }\r
-\r
- /**\r
- * @param collection of which all entities are to be initialized\r
- * @param cdmEntities initialize all *toOne relations to cdm entities\r
- * @param collections initialize all *toMany relations\r
- */\r
- private void initializeAllEntries(Collection collection, boolean cdmEntities, boolean collections) {\r
- for(Object bean : collection){\r
- initializeBean(bean, cdmEntities, collections);\r
- }\r
- }\r
+\r
+ private String addAutoinitFetchLoading(Class<?> clazz, String beanAlias) {\r
+ Set<AutoPropertyInitializer<CdmBase>> inits = getAutoInitializers(clazz);\r
+ String result = "";\r
+ for (AutoPropertyInitializer<CdmBase> init: inits){\r
+ result +=init.hibernateFetchJoin(clazz, beanAlias);\r
+ }\r
+ return result;\r
+ }\r
+\r
+ private Set<AutoPropertyInitializer<CdmBase>> getAutoInitializers(Class<?> clazz) {\r
+ Set<AutoPropertyInitializer<CdmBase>> result = new HashSet<AutoPropertyInitializer<CdmBase>>();\r
+ for(Class<? extends CdmBase> superClass : getBeanAutoInitializers().keySet()){\r
+ if(superClass.isAssignableFrom(clazz)){\r
+ result.add(getBeanAutoInitializers().get(superClass));\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Rename hibernate (field) attribute to Bean property name, due to bean inconsistencies\r
+ * #3841\r
+ * @param param\r
+ * @param ownerClass\r
+ * @return\r
+ */\r
+ private String mapFieldToPropertyName(String param, String ownerClass) {\r
+ if (ownerClass.contains("Description") && param.equals("descriptionElements")){\r
+ return "elements";\r
+ }\r
+ if (ownerClass.startsWith("FeatureNode") && param.equals("children")) {\r
+ return "childNodes";\r
+ }\r
+ else{\r
+ return param;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param node\r
+ * @param property\r
+ * @param index\r
+ * @param bean\r
+ * @param unwrappedPropertyBean\r
+ */\r
+ private void initializeNodeSinglePropertyOld(BeanInitNode node, String property,\r
+ Integer index, Object bean, Object unwrappedPropertyBean) {\r
+ Collection<?> collection = null;\r
+ if(Map.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {\r
+ collection = ((Map<?,?>)unwrappedPropertyBean).values();\r
+ }else if (Collection.class.isAssignableFrom(unwrappedPropertyBean.getClass())) {\r
+ collection = (Collection<?>) unwrappedPropertyBean;\r
+ }\r
+ if (collection != null){\r
+ //collection or map\r
+ if (logger.isTraceEnabled()){logger.trace(" initialize collection for " + node.toStringNoWildcard() + " ... ");}\r
+ int i = 0;\r
+ for (Object entrybean : collection) {\r
+ if(index == null){\r
+ node.addBean(entrybean);\r
+ } else if(index.equals(i)){\r
+ node.addBean(entrybean);\r
+ break;\r
+ }\r
+ i++;\r
+ }\r
+ if (logger.isTraceEnabled()){logger.trace(" initialize collection for " + node.toString() + " - DONE ");}\r
+\r
+ }else {\r
+ // nested bean\r
+ node.addBean(unwrappedPropertyBean);\r
+ setProperty(bean, property, unwrappedPropertyBean);\r
+ }\r
+ }\r
\r
}\r