Package javango.contrib.hibernate

Source Code of javango.contrib.hibernate.HibernateQuerySetHelper

package javango.contrib.hibernate;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javango.db.ManagerException;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Value;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;

public class HibernateQuerySetHelper {
  private final static Log log = LogFactory.getLog(HibernateQuerySetHelper.class);
 
  protected HibernateUtil hibernateUtil;
  protected Class<?> modelClass;
  protected DetachedCriteria criteria;
  Map<String, DetachedCriteria> joins = new HashMap<String, DetachedCriteria>();
 
  public HibernateQuerySetHelper(HibernateUtil hibernateUtil, Class modelClass, DetachedCriteria criteria) {
    this.hibernateUtil = hibernateUtil;
    this.modelClass = modelClass;
    this.criteria = criteria;
  }

  /**
   * Returns a the keys Class[]
   * @return
   * @throws DaoException
   */
  public Class[] getPkClass() throws ManagerException {
    Configuration cfg = hibernateUtil.getConfiguration();
    PersistentClass pclass = cfg.getClassMapping(modelClass.getName());

    if (pclass == null) {
      throw new ManagerException("Unable to find class : "
          + modelClass.toString());
    }

    Property componentProperty = pclass.getIdentifierProperty();
    if (componentProperty == null) {
      Component component = pclass.getIdentifierMapper();
      if (component == null) {
        throw new ManagerException("Unable to get pk mapping");
      }
      if (log.isDebugEnabled()) log.debug(String.format("Found %d keys for model %s", component.getPropertySpan(), modelClass.getName()));

      Class<?>[] classArray = new Class[component.getColumnSpan()];
      Iterator<Property> ite = component.getPropertyIterator();
      int i = 0;
      while (ite.hasNext()) {
        Property p = ite.next();
        if (log.isDebugEnabled()) log.debug("property name: " + p.getName());
        classArray[i++] = p.getType().getReturnedClass();
      }
      return classArray;
    } else {

      Value value = componentProperty.getValue();
      if (value == null)
        throw new ManagerException("Component value is null");
      else {
        if (log.isDebugEnabled()) log.debug(String.format("Found simple key for model %s '%s'",
            modelClass.getName(), value.getType()
                .getReturnedClass()));
        return new Class[] { value.getType().getReturnedClass() };
      }
    }
  }

  public java.lang.reflect.Field findField(Class modelClass, String property) throws ManagerException {
    // TODO dry,  this is repeated in ModelForm,  maybe helper/util class..
    Class classToTry = modelClass;
    while(classToTry != null) {
      try {
        return classToTry.getDeclaredField(property);
      } catch (NoSuchFieldException e) {
        classToTry = classToTry.getSuperclass();
      }
    }
    throw new ManagerException("No such field found: " + property + " in class " + modelClass.getName());
  }
 
  public Object convert(String value, Class clazz) {   
    return ConvertUtils.convert(value, clazz);
  }
 
  public Object correctType(String fieldName, Object value) throws ManagerException {
    return correctType(fieldName, value, this.modelClass);
  }
 
  public Object correctType(String fieldName, Object value, Class clazz) throws ManagerException {
   
    // TODO May still need to convert non-strings to the correct value (ie long to double, etc).
    if (!(value instanceof String)) {
      return value;
    }   
    ClassMetadata metadata = hibernateUtil.getSessionFactory().getClassMetadata(clazz);
    if (metadata != null) {
      Type type = metadata.getPropertyType(fieldName);
      if (type instanceof CollectionType) {
        log.warn("Unable to handle collection: " + fieldName);
        return value;
      } else if (type instanceof AssociationType) {
        AssociationType assocType = (AssociationType)type;
        Class[] assocPkClass = getPkClass();
        if (assocPkClass.length > 1) {
          log.error("Multi keyed associations are not supported in correctType");
          return value;
        }
        Object o = convert((String)value, assocPkClass[0]);
        return hibernateUtil.getSession().get(assocType.getReturnedClass(), (Serializable)o);
        // TODO if return value is null should something be done??
        //return value;
      } else {
        return convert((String)value, type.getReturnedClass());
      }
     
    }
     
    // TODO is this code needed with the type.getReturnedClass from above??
    java.lang.reflect.Field field = findField(clazz, fieldName);
    return convert((String)value, field.getType());

  }
 
  public Object convertToPk(Object pk) throws ManagerException {
  if (pk == null) return null;
   
    Class[] keyClass = getPkClass();
    if (keyClass.length != 1) {
      throw new ManagerException("get(pk) not supported for composite keyed models");
    }
       
    if (pk.getClass().equals(keyClass[0])) {
      return pk;
    }   
   
    if (log.isDebugEnabled()) log.debug("Trying to convert input to type " + keyClass[0]);
   
    return convert(pk.toString(), keyClass[0]);
  }

  public void resolveProperty() {
   
  }
 
  protected Criterion getCriterion(Class searchClass, String searchType, String searchField, Object searchValue, boolean property) throws ManagerException {
    if ("like".equals(searchType)) {
      // the as400 in particular does not like likes without percents on char fields
      if (searchValue instanceof String && StringUtils.contains((String)searchValue, "%")) {
        return Restrictions.like(searchField, searchValue);
      }
      if (property) {
        return Restrictions.eqProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.eq(searchField, searchValue);
      }
    } else if ("ilike".equals(searchType)) {
      if (searchValue instanceof String && StringUtils.contains((String)searchValue, "%")) {
        return Restrictions.ilike(searchField, searchValue);
      }
      return Restrictions.eq(searchField, searchValue).ignoreCase();
    } else if ("nlike".equals(searchType)) {
      // the as400 in particular does not like likes without percents on char fields
      if (searchValue instanceof String && StringUtils.contains((String)searchValue, "%")) {
        return Restrictions.not(Restrictions.like(searchField, searchValue));
      }
      return Restrictions.ne(searchField, searchValue);
    } else if ("nilike".equals(searchType)) {
      if (searchValue instanceof String && StringUtils.contains((String)searchValue, "%")) {
        return Restrictions.not(Restrictions.ilike(searchField, searchValue));
      }
      return Restrictions.ne(searchField, searchValue).ignoreCase();
    } else if ("lte".equals(searchType)) {
      if (property) {
        return Restrictions.leProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.le(searchField, searchValue);
      }
    } else if ("gte".equals(searchType)) {
      if (property) {
        return Restrictions.geProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.ge(searchField, searchValue);
      }
    } else if ("lt".equals(searchType)) {
      if (property) {
        return Restrictions.ltProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.lt(searchField, searchValue);
      }

    } else if ("gt".equals(searchType)) {
      if (property){
        return Restrictions.gtProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.gt(searchField, searchValue);
      }

    } else if ("ilte".equals(searchType)) {
      if (property) {
        return Restrictions.leProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.le(searchField, searchValue).ignoreCase();
      }
    } else if ("igte".equals(searchType)) {
      if (property) {
        return Restrictions.geProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.ge(searchField, searchValue).ignoreCase();
      }
    } else if ("ilt".equals(searchType)) {
      if (property) {
        return Restrictions.ltProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.lt(searchField, searchValue).ignoreCase();
      }

    } else if ("igt".equals(searchType)) {
      if (property){
        return Restrictions.gtProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.gt(searchField, searchValue).ignoreCase();
      }   
     
    } else if ("eq".equals(searchType)) {
      if (searchValue == null) {
        return Restrictions.isNull(searchField);
      }
      if (property) {
        return Restrictions.eqProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.eq(searchField, searchValue);
      }
    } else if ("ne".equals(searchType)) {
      if (searchValue == null) {
        return Restrictions.isNotNull(searchField);
      }
      if (property) {
        return Restrictions.neProperty(searchField, (String)searchValue);
      } else {
        return Restrictions.ne(searchField, searchValue);
      }
    } else if ("in".equals(searchType)) {
      if (searchValue instanceof DetachedCriteria) {
        return org.hibernate.criterion.Property.forName(searchField).in((DetachedCriteria)searchValue);
      } else if (searchValue instanceof HibernateQuerySet<?>) {       
        DetachedCriteria newC = ((HibernateQuerySet<?>)searchValue).getRawCriteria();
        newC.setProjection(Projections.id());
        return org.hibernate.criterion.Property.forName(searchField).in(newC);
      } else if (searchValue instanceof Collection<?>) {
        Collection<?> collection = (Collection<?>)searchValue;
        return Restrictions.in(searchField, collection);
      } else {
        return Restrictions.in(searchField, (Object[])searchValue);
      }
    } else if ("notin".equals(searchType)) {
      return Restrictions.not(Restrictions.in(searchField, (Object[])searchValue));
    } else if ("date".equals(searchType)) {
      if (!(searchValue instanceof Date) || searchValue == null) {
        throw new ManagerException ("__date search requires a non-null instance of java.util.Date");
      }
      Date date = (Date)searchValue;
     
      Calendar from = new GregorianCalendar();
      from.setTime(date);
      from.set(Calendar.HOUR_OF_DAY, 0);
      from.set(Calendar.MINUTE, 0);
      from.set(Calendar.SECOND, 0);
      from.set(Calendar.MILLISECOND, 0);

      Calendar to = new GregorianCalendar();
      to.setTime(date);
      to.set(Calendar.HOUR_OF_DAY, 23);
      to.set(Calendar.MINUTE, 59);
      to.set(Calendar.SECOND, 59);
      to.set(Calendar.MILLISECOND, 0);
     
      return Restrictions.between(searchField, from.getTime(), to.getTime());
    }
    return null;
   
  }
 
  protected Object[] resolveJoins(String[] parts, int count) throws ManagerException {
    DetachedCriteria c = criteria; // start with the main criteria,  if we have joins this will eventually be the criteria for the join we want.
    int part = 0; // the part we are looking at.  process util we get through them all.
    Class searchClass = this.modelClass;
    String joinPath = null; // this gets built to the full path for the joins map's key   
    if (count > 0) {
      // we got some joins..  resolve them     
      while (part < count) { // get all but the last two which may be a searchProperty and searchType
        String joinProperty = parts[part];
        joinPath = joinPath == null ? joinProperty : joinPath + "__" + joinProperty;
        DetachedCriteria subC = joins.get(joinPath);
        if (subC == null) {
          subC = c.createCriteria(joinProperty, joinPath, Criteria.LEFT_JOIN);
          joins.put(joinPath, subC);
        }
        ClassMetadata metadata = hibernateUtil.getSessionFactory().getClassMetadata(searchClass);
        Type type = metadata.getPropertyType(joinProperty);
        if (type instanceof CollectionType) {
          log.info("Expiremental CollectionType join: " + joinPath);
          subC.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
          Type newtype = ((CollectionType)type).getElementType((SessionFactoryImplementor)hibernateUtil.getSessionFactory());
          searchClass = newtype.getReturnedClass();
        } else {
          searchClass = type.getReturnedClass();
        }
        c = subC;
        part++;
       

      }
    }
    return new Object[]{searchClass, c};
  }
 
  public void processField(String fieldName, Object value, boolean property) throws ManagerException {   
    String[] parts = fieldName.split("__");
    if (parts.length == 1) { // no __ found in the string,  default to simple equals match
      Object[] o = resolveJoins(parts, 0);
      Class searchClass = (Class)o[0];
      Object searchValue = property ? value : correctType(fieldName, value, searchClass);        
      criteria.add(getCriterion(searchClass, "eq", fieldName, searchValue, property));
      return;
    }
   
    String searchType = parts[parts.length-1];
    String searchField = parts[parts.length-2];
   
    Object[] o = resolveJoins(parts, parts.length-2);
    Class searchClass = (Class)o[0];
    DetachedCriteria c = (DetachedCriteria)o[1];
    Object searchValue = property ? value : correctType(searchField, value, searchClass);        
    Criterion criterion = getCriterion(searchClass, searchType, searchField, searchValue, property);
   
    if (criterion == null) { // humm no match on the search type..  assume equals
      searchField = searchType;
      // searchType = "eq"; // not really needed
      o = resolveJoins(parts, parts.length-1);
      searchClass = (Class)o[0];
      c = (DetachedCriteria)o[1];   
     
      if (property) {
        criterion = Restrictions.eqProperty(searchField, (String)searchValue);
      } else {
        criterion = Restrictions.eq(searchField, correctType(searchField, value, searchClass));
      }
    }
   
    c.add(criterion);
  }
 
  /**
   * Update the property values from the map,  to preserve backwards compat null values in the map are ignored.
   *
   * @param params
   * @throws ManagerException
   */
  public void updateCriteriaFromMap(Map<String, Object> params) throws ManagerException {
    for(Entry<String, Object> entry : params.entrySet()) {
        processField(entry.getKey(), entry.getValue(), false);
    }
  }
 
 
  public void updateCriteriaFromPropertyMap(Map<String, String> params) throws ManagerException {
    if (params == null) return;
   
    for(Entry<String, String> entry : params.entrySet()) {
      processField(entry.getKey(), entry.getValue(), true);
    }
  }
 
  @SuppressWarnings("unchecked")
  public void updateCriteria(Object params) throws ManagerException {
   
    if (params == null) return;
   
    if (params instanceof Map) {
      updateCriteriaFromMap((Map)params);
      return;     
    }
   
    try {
      Class c = params.getClass();
      java.lang.reflect.Field[] fields = c.getDeclaredFields();
      for (int i=0; i<fields.length; i++) {
        String fieldName = fields[i].getName();
        Object value = PropertyUtils.getProperty(params, fieldName);
        processField(fieldName, value, false);
      }     
    } catch (IllegalAccessException e) {
      log.error(e,e);
    } catch (InvocationTargetException e) {
      log.error(e,e);
    } catch (NoSuchMethodException e) {
      log.error(e,e);
   
  }
 
  /**
   * Returns a the keys Class[]
   * @return
   * @throws DaoException
   */
  public String getPkProperty() throws ManagerException {
    Configuration cfg = hibernateUtil.getConfiguration();
    PersistentClass pclass = cfg.getClassMapping(modelClass.getName());

    if (pclass == null) {
      throw new ManagerException("Unable to find class : "
          + modelClass.toString());
    }

    Property componentProperty = pclass.getIdentifierProperty();
    if (componentProperty == null) {
      throw new UnsupportedOperationException("Multiple primary keys not supported");
//      Component component = pclass.getIdentifierMapper();
//      if (component == null) {
//        throw new DaoException("Unable to get pk mapping");
//      }
//      if (log.isDebugEnabled()) log.debug(String.format("Found %d keys for model %s", component.getPropertySpan(), modelClass.getName()));
//
//      Class<?>[] classArray = new Class[component.getColumnSpan()];
//      Iterator<Property> ite = component.getPropertyIterator();
//      int i = 0;
//      while (ite.hasNext()) {
//        Property p = ite.next();
//        if (log.isDebugEnabled()) log.debug("property name: " + p.getName());
//        classArray[i++] = p.getType().getReturnedClass();
//      }
//      return classArray;
    } else {
      return componentProperty.getName();
    }
  }
 
  public void addOrderBy(String orderBy) throws ManagerException {
    boolean desc = orderBy.startsWith("-");
    if (desc) {
      orderBy = orderBy.substring(1);
    }
   
    DetachedCriteria c = criteria;
    String[] parts = orderBy.split("__");
    if (parts.length > 1) {
      Object[] o = resolveJoins(parts, parts.length-1);
      // Class searchClass = (Class)o[0];
      c = (DetachedCriteria)o[1];
      orderBy = parts[parts.length-1];
    }
   
   
    if (desc) {
      c.addOrder(Order.desc(orderBy));
    } else {
      c.addOrder(Order.asc(orderBy));
    }
  }
}
TOP

Related Classes of javango.contrib.hibernate.HibernateQuerySetHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.