|
From: <gca...@us...> - 2010-06-09 17:14:28
|
Revision: 2637
http://openutils.svn.sourceforge.net/openutils/?rev=2637&view=rev
Author: gcatania
Date: 2010-06-09 17:14:21 +0000 (Wed, 09 Jun 2010)
Log Message:
-----------
BSHD-5 wip filterMetadata support
Modified Paths:
--------------
trunk/openutils-bshd5/src/main/java/it/openutils/dao/hibernate/HibernateDAOImpl.java
trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/ExampleTree.java
trunk/openutils-bshd5/src/test/java/it/openutils/hibernate/test/HibernateDAOTest.java
Added Paths:
-----------
trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/FilterMetadataSupport.java
Modified: trunk/openutils-bshd5/src/main/java/it/openutils/dao/hibernate/HibernateDAOImpl.java
===================================================================
--- trunk/openutils-bshd5/src/main/java/it/openutils/dao/hibernate/HibernateDAOImpl.java 2010-06-08 16:08:16 UTC (rev 2636)
+++ trunk/openutils-bshd5/src/main/java/it/openutils/dao/hibernate/HibernateDAOImpl.java 2010-06-09 17:14:21 UTC (rev 2637)
@@ -27,8 +27,10 @@
import it.openutils.hibernate.example.ExampleTree;
import it.openutils.hibernate.example.FilterMetadata;
+import it.openutils.hibernate.example.FilterMetadataSupport;
import java.io.Serializable;
+import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -447,6 +449,10 @@
public List<T> findFiltered(T filter, Map<String, ? extends FilterMetadata> metadata, int maxResults, int page,
List< ? extends Criterion> criteria, Order... orders)
{
+ if (metadata == null || metadata.isEmpty())
+ {
+ return getHibernateTemplate().execute(new ExampleTreeCallback(orders, criteria, maxResults, page, filter));
+ }
return getHibernateTemplate().execute(
new HibernateCallbackForExecution(filter, page, maxResults, metadata, orders, criteria, Collections
.<String> emptyList()));
@@ -674,6 +680,60 @@
}
/**
+ * @author gcatania
+ */
+ private final class ExampleTreeCallback implements HibernateCallback<List<T>>
+ {
+
+ private final Order[] orders;
+
+ private final List< ? extends Criterion> criteria;
+
+ private final int page;
+
+ private final int maxResults;
+
+ private final T filter;
+
+ private ExampleTreeCallback(
+ Order[] orders,
+ List< ? extends Criterion> criteria,
+ int maxResults,
+ int page,
+ T filter)
+ {
+ this.orders = orders;
+ this.criteria = criteria;
+ this.page = page;
+ this.maxResults = maxResults;
+ this.filter = filter;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<T> doInHibernate(Session session) throws HibernateException, SQLException
+ {
+ Criteria crit = new ExampleTree(filter).create(session);
+ crit.setMaxResults(maxResults);
+ crit.setFirstResult(maxResults * page);
+ if (criteria != null)
+ {
+ for (Criterion c : criteria)
+ {
+ crit.add(c);
+ }
+ }
+ if (orders != null)
+ {
+ for (Order o : orders)
+ {
+ crit.addOrder(o);
+ }
+ }
+ return crit.list();
+ }
+ }
+
+ /**
* @author carone
* @version $Id$
*/
@@ -716,7 +776,7 @@
public List<T> doInHibernate(Session ses) throws HibernateException
{
// Criteria crit = ses.createCriteria(filter.getClass());
- Criteria crit = new ExampleTree(filter).create(ses);
+ Criteria crit = new FilterMetadataSupport(filter, metadata).create(ses);
crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
crit.setMaxResults(maxResults);
crit.setFirstResult(maxResults * page);
@@ -731,7 +791,6 @@
}
}
}
- // EnhancedExample.create(crit, filter, metadata);
if (!CollectionUtils.isEmpty(additionalCriteria))
{
for (Criterion criterion : additionalCriteria)
Modified: trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/ExampleTree.java
===================================================================
--- trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/ExampleTree.java 2010-06-08 16:08:16 UTC (rev 2636)
+++ trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/ExampleTree.java 2010-06-09 17:14:21 UTC (rev 2637)
@@ -55,8 +55,6 @@
public class ExampleTree
{
- // TODO figure out how to handle filter metadata
-
private final Object entity;
private Character escapeCharacter;
@@ -254,13 +252,11 @@
Object propertyValue = classMetadata.getPropertyValue(entity, propertyName, entityMode);
if (propertyType.isCollectionType())
{
- propertyValue = getCollectionValue(propertyValue);
+ propertyValue = getValueFromCollection(propertyValue);
}
if (propertyValue == null)
{
// skip null values
- // TODO: allow specifications of which values to exclude, also see
- // EnhancedExample.containsSomething()
continue;
}
@@ -358,7 +354,8 @@
return false;
}
- private Object getCollectionValue(Object collectionValue)
+ // see http://opensource2.atlassian.com/projects/hibernate/browse/HHH-879
+ private Object getValueFromCollection(Object collectionValue)
{
if (collectionValue != null)
{
Added: trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/FilterMetadataSupport.java
===================================================================
--- trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/FilterMetadataSupport.java (rev 0)
+++ trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/FilterMetadataSupport.java 2010-06-09 17:14:21 UTC (rev 2637)
@@ -0,0 +1,279 @@
+/**
+ *
+ * openutils base Spring-Hibernate DAO for java 5.0 (http://www.openmindlab.com/lab/products/bshd5.html)
+ *
+ * Copyright(C) null-2010, Openmind S.r.l. http://www.openmindonline.it
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl-2.1.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package it.openutils.hibernate.example;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.criterion.Example;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.type.Type;
+
+
+/**
+ * legacy support for filter metadata.
+ * @author gcatania
+ */
+public class FilterMetadataSupport
+{
+
+ private final Object entity;
+
+ private Map<String, ? extends FilterMetadata> filterMetadata;
+
+ /**
+ * builds an instance of {@code ExampleTree} associated with the input entity
+ * @param entity the example entity
+ */
+ public FilterMetadataSupport(Object entity, Map<String, ? extends FilterMetadata> filterMetadata)
+ {
+ if (entity == null)
+ {
+ throw new NullPointerException("Null entity.");
+ }
+ this.entity = entity;
+ this.filterMetadata = filterMetadata;
+ }
+
+ /**
+ * creates a criteria with the input session, adds to it an example for the input entity, and creates subcriteria
+ * and related examples for non-null property values on the filter entity that correspond to associations
+ * @param ses the session
+ * @return a criteria for this example tree
+ */
+ public Criteria create(Session ses)
+ {
+ return appendTo(ses.createCriteria(Hibernate.getClass(entity)), ses);
+ }
+
+ /**
+ * appends examples and subcriteria, created for the entity this example tree was initialized with, to the input
+ * criteria, and then returns it
+ * @param crit the criteria to append to
+ * @param ses the session
+ * @return the input criteria with the added subcriteria and examples
+ */
+ public Criteria appendTo(Criteria crit, Session ses)
+ {
+ return new ExampleTreeWalker(ses).walk(crit, entity);
+ }
+
+ private class ExampleTreeWalker
+ {
+
+ private final SessionFactory sessionFactory;
+
+ private EntityMode entityMode;
+
+ public ExampleTreeWalker(Session session)
+ {
+ sessionFactory = session.getSessionFactory();
+ entityMode = session.getEntityMode();
+ }
+
+ public Criteria walk(Criteria rootCriteria, Object rootEntity)
+ {
+ createSubExamples(rootCriteria, rootEntity, new String[0]);
+ return rootCriteria;
+ }
+
+ private void createSubExamples(Criteria crit, Object entity, String[] walkedProperties)
+ {
+ String path = getPath(walkedProperties);
+ Map<String, FilterMetadata> currFilterMetadata = getFilterMetadata(path);
+ crit.add(example(entity, currFilterMetadata.keySet()));
+ ClassMetadata classMetadata = sessionFactory.getClassMetadata(Hibernate.getClass(entity));
+ Type[] types = classMetadata.getPropertyTypes();
+ String[] names = classMetadata.getPropertyNames();
+ for (int i = 0; i < types.length; i++)
+ {
+ String propertyName = names[i];
+ if (alreadyWalked(walkedProperties, propertyName))
+ {
+ continue;
+ }
+ Object propertyValue = classMetadata.getPropertyValue(entity, propertyName, entityMode);
+ FilterMetadata fm = currFilterMetadata.get(propertyName);
+ if (fm != null)
+ {
+ fm.createFilter(crit, propertyName, propertyValue);
+ continue;
+ }
+
+ Type propertyType = types[i];
+ if (!propertyType.isAssociationType())
+ {
+ // handled by Example.create() or by filterMetadata
+ continue;
+ }
+
+ if (propertyType.isCollectionType())
+ {
+ propertyValue = getValueFromCollection(propertyValue);
+ }
+ if (propertyValue == null)
+ {
+ // skip null values
+ continue;
+ }
+
+ Criteria subCrit = crit.createCriteria(propertyName);
+ String[] subProperties = append(walkedProperties, propertyName);
+ createSubExamples(subCrit, propertyValue, subProperties);
+ }
+ }
+
+ private Map<String, FilterMetadata> getFilterMetadata(String path)
+ {
+ Map<String, FilterMetadata> result = new HashMap<String, FilterMetadata>();
+ for (String key : filterMetadata.keySet())
+ {
+ if (key.equals(path))
+ {
+ continue;
+ }
+ if (!key.startsWith(path))
+ {
+ continue;
+ }
+ String leftover = key.substring(path.length() + 1);
+ // skip subproperties
+ if (leftover.contains("."))
+ {
+ continue;
+ }
+ result.put(leftover, filterMetadata.get(key));
+ }
+ return result;
+ }
+
+ private String getPath(String[] walkedProperties)
+ {
+ return walkedProperties.length > 0 ? StringUtils.join(walkedProperties, '.') : StringUtils.EMPTY;
+ }
+
+ private Example example(Object entity, Set<String> propertiesToExclude)
+ {
+ Example ex = Example.create(entity);
+ for (String propertyName : propertiesToExclude)
+ {
+ // skip properties handled by filterMetadata
+ ex.excludeProperty(propertyName);
+ }
+ return ex;
+ }
+
+ /**
+ * check the property with the input name was already walked in the input path
+ * @param path the current path
+ * @param propertyName the property name about to be walked
+ * @return true if the property with the input name was already walked in the input path
+ */
+ private boolean alreadyWalked(String[] walkedProperties, String propertyName)
+ {
+ if (walkedProperties.length <= 2)
+ {
+ return false;
+ }
+ String parent = walkedProperties[walkedProperties.length - 1];
+ boolean lastWasChild = false;
+ for (int i = walkedProperties.length - 2; i > 0; i--)
+ {
+ String currPropertyName = walkedProperties[i];
+ if (currPropertyName.equals(propertyName))
+ {
+ lastWasChild = true;
+ continue;
+ }
+ if (lastWasChild)
+ {
+ if (currPropertyName.equals(parent))
+ {
+ return true;
+ }
+ else
+ {
+ lastWasChild = false;
+ }
+ }
+ }
+ return false;
+ }
+
+ private Object getValueFromCollection(Object collectionValue)
+ {
+ if (collectionValue != null)
+ {
+ if (collectionValue instanceof Collection< ? >)
+ {
+ Collection< ? > coll = (Collection< ? >) collectionValue;
+ int size = coll.size();
+ if (size == 1)
+ {
+ return coll.iterator().next();
+ }
+ if (size > 1)
+ {
+ throw new IllegalArgumentException("More than one element in filter collection is unsupported.");
+ }
+ }
+ Class< ? extends Object> clazz = collectionValue.getClass();
+ if (clazz.isArray())
+ {
+ int length = Array.getLength(collectionValue);
+ if (length == 1)
+ {
+ return Array.get(collectionValue, 0);
+ }
+ if (length > 1)
+ {
+ throw new IllegalArgumentException("More than one element in filter array is unsupported.");
+ }
+ }
+ // TODO other cases?
+ }
+ return null;
+ }
+
+ private String[] append(String[] propertyNames, String propertyName)
+ {
+ String[] result = Arrays.copyOf(propertyNames, propertyNames.length + 1);
+ result[propertyNames.length] = propertyName;
+ return result;
+ }
+ }
+
+}
Property changes on: trunk/openutils-bshd5/src/main/java/it/openutils/hibernate/example/FilterMetadataSupport.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: trunk/openutils-bshd5/src/test/java/it/openutils/hibernate/test/HibernateDAOTest.java
===================================================================
--- trunk/openutils-bshd5/src/test/java/it/openutils/hibernate/test/HibernateDAOTest.java 2010-06-08 16:08:16 UTC (rev 2636)
+++ trunk/openutils-bshd5/src/test/java/it/openutils/hibernate/test/HibernateDAOTest.java 2010-06-09 17:14:21 UTC (rev 2637)
@@ -50,6 +50,11 @@
public class HibernateDAOTest extends AbstractTransactionalTestNGSpringContextTests
{
+ /*
+ * TODO tests to perform: 1) find filtered with collection with zero, one or more elements 2) find filtered with
+ * additional criteria 3) filter metadata support
+ */
+
@Autowired
private PersonDAO personDAO;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|