Package org.hibernate.ejb.criteria

Source Code of org.hibernate.ejb.criteria.CriteriaQueryCompiler$RenderedCriteriaQuery

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @author tags or express
* copyright attribution statements applied by the authors.  All
* third-party contributions are distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.ejb.criteria;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Parameter;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;

import org.hibernate.ejb.internal.EntityManagerMessageLogger;
import org.hibernate.ejb.HibernateEntityManagerImplementor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;

/**
* Compiles a JPA criteria query into an executable {@link TypedQuery}.  Its single contract is the {@link #compile}
* method.
* <p/>
* NOTE : This is a temporary implementation which simply translates the criteria query into a JPAQL query string.  A
* better, long-term solution is being implemented as part of refactoring the JPAQL/HQL translator.
*
* @author Steve Ebersole
*/
public class CriteriaQueryCompiler implements Serializable {

    private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
                                                                           CriteriaQueryCompiler.class.getName());

  /**
   * Used to describe implicit (not defined in criteria query) parameters.
   */
  public static interface ImplicitParameterBinding {
    /**
     * Retrieve the generated name of the implicit parameter.
     *
     * @return The parameter name.
     */
    public String getParameterName();

    /**
     * Get the java type of the "thing" that led to the implicit parameter.  Used from
     * {@link org.hibernate.ejb.HibernateEntityManagerImplementor.Options#getNamedParameterExplicitTypes()}
     * in determining "guessed type" overriding.
     *
     * @return The java type
     */
    public Class getJavaType();

    /**
     * Bind the implicit parameter's value to the JPA query.
     *
     * @param typedQuery The JPA query.
     */
    public void bind(TypedQuery typedQuery);
  }

  /**
   * Used to provide a context and services to the rendering.
   */
  public static interface RenderingContext {
    /**
     * Generate a correlation name.
     *
     * @return The generated correlation name
     */
    public String generateAlias();

    /**
     * Register parameters explicitly encountered in the criteria query.
     *
     * @param criteriaQueryParameter The parameter expression
     *
     * @return The JPA-QL parameter name
     */
    public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter);

    /**
     * Register a parameter that was not part of the criteria query (at least not as a parameter).
     *
     * @param literal The literal value
     * @param javaType The java type as whcih to handle the literal value.
     *
     * @return The JPA-QL parameter name
     */
    public String registerLiteralParameterBinding(Object literal, Class javaType);

    /**
     * Given a java type, determine the proper cast type name.
     *
     * @param javaType The java type.
     *
     * @return The cast type name.
     */
    public String getCastType(Class javaType);
  }

  public static interface RenderedCriteriaQuery {
    public String getQueryString();
    public List<ValueHandlerFactory.ValueHandler> getValueHandlers();
    public HibernateEntityManagerImplementor.Options.ResultMetadataValidator getResultMetadataValidator();
  }

  private final HibernateEntityManagerImplementor entityManager;

  public CriteriaQueryCompiler(HibernateEntityManagerImplementor entityManager) {
    this.entityManager = entityManager;
  }

  public <T> TypedQuery<T> compile(CriteriaQuery<T> criteriaQuery) {
    CriteriaQueryImpl<T> criteriaQueryImpl = ( CriteriaQueryImpl<T> ) criteriaQuery;
    criteriaQueryImpl.validate();

    final Map<ParameterExpression<?>,String> explicitParameterMapping = new HashMap<ParameterExpression<?>,String>();
    final Map<String,ParameterExpression<?>> explicitParameterNameMapping = new HashMap<String,ParameterExpression<?>>();
    final List<ImplicitParameterBinding> implicitParameterBindings = new ArrayList<ImplicitParameterBinding>();
    final Map<String,Class> implicitParameterTypes = new HashMap<String, Class>();

    RenderingContext renderingContext = new RenderingContext() {
      private int aliasCount = 0;
      private int explicitParameterCount = 0;

      public String generateAlias() {
        return "generatedAlias" + aliasCount++;
      }

      public String generateParameterName() {
        return "param" + explicitParameterCount++;
      }

      public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter) {
        final String jpaqlParameterName;
        if ( explicitParameterMapping.containsKey( criteriaQueryParameter ) ) {
          jpaqlParameterName = explicitParameterMapping.get( criteriaQueryParameter );
        }
        else {
          jpaqlParameterName = generateParameterName();
          explicitParameterMapping.put( criteriaQueryParameter, jpaqlParameterName );
        }
        if ( StringHelper.isNotEmpty( criteriaQueryParameter.getName() ) ) {
          explicitParameterNameMapping.put(
              criteriaQueryParameter.getName(),
              criteriaQueryParameter
          );
        }
        return jpaqlParameterName;
      }

      public String registerLiteralParameterBinding(final Object literal, final Class javaType) {
        final String parameterName = generateParameterName();
        final ImplicitParameterBinding binding = new CriteriaQueryCompiler.ImplicitParameterBinding() {
          public String getParameterName() {
            return parameterName;
          }

          public Class getJavaType() {
            return javaType;
          }

          public void bind(TypedQuery typedQuery) {
            typedQuery.setParameter( parameterName, literal );
          }
        };

        implicitParameterBindings.add( binding );
        implicitParameterTypes.put( parameterName, javaType );
        return parameterName;
      }

      public String getCastType(Class javaType) {
        SessionFactoryImplementor factory =
            ( SessionFactoryImplementor ) entityManager.getFactory().getSessionFactory();
        Type hibernateType = factory.getTypeResolver().heuristicType( javaType.getName() );
        if ( hibernateType == null ) {
          throw new IllegalArgumentException(
              "Could not convert java type [" + javaType.getName() + "] to Hibernate type"
          );
        }
        int[] sqlTypeCodes = hibernateType.sqlTypes( factory );
        if ( sqlTypeCodes.length != 1 ) {
          throw new IllegalArgumentException(
              "Invalid Hibernate Type [" + hibernateType.getName() +
                  "] for cast : more than one column spanned"
          );
        }
        return factory.getDialect().getCastTypeName( sqlTypeCodes[0] );
      }
    };

    final RenderedCriteriaQuery renderedCriteriaQuery = criteriaQueryImpl.render( renderingContext );

        LOG.debugf("Rendered criteria query -> %s", renderedCriteriaQuery.getQueryString());

    TypedQuery<T> jpaqlQuery = entityManager.createQuery(
        renderedCriteriaQuery.getQueryString(),
        criteriaQuery.getResultType(),
        criteriaQuery.getSelection(),
        new HibernateEntityManagerImplementor.Options() {
          public List<ValueHandlerFactory.ValueHandler> getValueHandlers() {
            return renderedCriteriaQuery.getValueHandlers();
          }

          public Map<String, Class> getNamedParameterExplicitTypes() {
            return implicitParameterTypes;
          }

          public ResultMetadataValidator getResultMetadataValidator() {
            return renderedCriteriaQuery.getResultMetadataValidator();
          }
        }
    );

    for ( ImplicitParameterBinding implicitParameterBinding : implicitParameterBindings ) {
      implicitParameterBinding.bind( jpaqlQuery );
    }

    return wrap( jpaqlQuery, explicitParameterMapping, explicitParameterNameMapping );
  }

  private <X> TypedQuery<X> wrap(
      final TypedQuery<X> jpaqlQuery,
      final Map<ParameterExpression<?>, String> explicitParameterMapping,
      final Map<String, ParameterExpression<?>> explicitParameterNameMapping) {
    return new TypedQuery<X>() {

      public List<X> getResultList() {
        return jpaqlQuery.getResultList();
      }

      public X getSingleResult() {
        return jpaqlQuery.getSingleResult();
      }

      public int getMaxResults() {
        return jpaqlQuery.getMaxResults();
      }

      public TypedQuery<X> setMaxResults(int i) {
        jpaqlQuery.setMaxResults( i );
        return this;
      }

      public int getFirstResult() {
        return jpaqlQuery.getFirstResult();
      }

      public TypedQuery<X> setFirstResult(int i) {
        jpaqlQuery.setFirstResult( i );
        return this;
      }

      public Map<String, Object> getHints() {
        return jpaqlQuery.getHints();
      }

      public TypedQuery<X> setHint(String name, Object value) {
        jpaqlQuery.setHint( name, value);
        return this;
      }

      public FlushModeType getFlushMode() {
        return jpaqlQuery.getFlushMode();
      }

      public TypedQuery<X> setFlushMode(FlushModeType flushModeType) {
        jpaqlQuery.setFlushMode( flushModeType );
        return this;
      }

      public LockModeType getLockMode() {
        return jpaqlQuery.getLockMode();
      }

      public TypedQuery<X> setLockMode(LockModeType lockModeType) {
        jpaqlQuery.setLockMode( lockModeType );
        return this;
      }

      @SuppressWarnings({ "unchecked" })
      public Set getParameters() {
        return explicitParameterMapping.keySet();
      }

      public boolean isBound(Parameter<?> param) {
        return jpaqlQuery.isBound( param );
      }

      @SuppressWarnings({ "unchecked" })
      public <T> T getParameterValue(Parameter<T> param) {
        return ( T ) jpaqlQuery.getParameterValue( mapToNamedParameter( param ) );
      }

      @SuppressWarnings({ "unchecked" })
      public <T> TypedQuery<X> setParameter(Parameter<T> param, T t) {
        jpaqlQuery.setParameter( mapToNamedParameter( param ), t );
        return this;
      }

      @SuppressWarnings({ "RedundantCast" })
      private Parameter mapToNamedParameter(Parameter criteriaParameter) {
        return jpaqlQuery.getParameter(
            explicitParameterMapping.get( criteriaParameter )
        );
      }

      @SuppressWarnings({ "unchecked" })
      public TypedQuery<X> setParameter(Parameter<Calendar> param, Calendar calendar, TemporalType temporalType) {
        jpaqlQuery.setParameter( mapToNamedParameter( param ), calendar, temporalType );
        return this;
      }

      @SuppressWarnings({ "unchecked" })
      public TypedQuery<X> setParameter(Parameter<Date> param, Date date, TemporalType temporalType) {
        jpaqlQuery.setParameter( mapToNamedParameter( param ), date, temporalType );
        return this;
      }

      public <T> T unwrap(Class<T> cls) {
        return jpaqlQuery.unwrap( cls );
      }

      @SuppressWarnings({ "unchecked" })
      public Object getParameterValue(String name) {
        return getParameterValue( resolveExplicitCriteriaParameterName( name ) );
      }

      private Parameter resolveExplicitCriteriaParameterName(String name) {
        Parameter parameter = explicitParameterNameMapping.get( name );
        if ( parameter == null ) {
          throw new IllegalArgumentException( "Named parameter [" + name + "] not encountered" );
        }
        return parameter;
      }

      public Parameter<?> getParameter(String name) {
        return mapToNamedParameter( resolveExplicitCriteriaParameterName( name ) );
      }

      @SuppressWarnings({ "unchecked" })
      public <T> Parameter<T> getParameter(String name, Class<T> type) {
        Parameter parameter = resolveExplicitCriteriaParameterName( name );
        if ( type.isAssignableFrom( parameter.getParameterType() ) ) {
          return parameter;
        }
        throw new IllegalArgumentException(
            "Named parameter [" + name + "] type is not assignanle to request type ["
                + type.getName() + "]"
        );
      }

      @SuppressWarnings({ "unchecked" })
      public TypedQuery<X> setParameter(String name, Object value) {
        setParameter(
            resolveExplicitCriteriaParameterName( name, value ),
            value
        );
        return this;
      }

      private Parameter resolveExplicitCriteriaParameterName(String name, Object value) {
        Parameter parameter = resolveExplicitCriteriaParameterName( name );
        // todo : is null valid?
        if ( value != null ) {
          if ( ! parameter.getParameterType().isInstance( value ) ) {
            throw new IllegalArgumentException(
                "Named parameter [" + name + "] type mismatch; expecting ["
                    + parameter.getParameterType().getName() + "], found ["
                    + value.getClass().getName() + "]"
            );
          }
        }
        return parameter;
      }

      @SuppressWarnings({ "unchecked" })
      public TypedQuery<X> setParameter(String name, Calendar calendar, TemporalType temporalType) {
        Parameter parameter = resolveExplicitCriteriaParameterName( name );
        if ( ! Calendar.class.isAssignableFrom( parameter.getParameterType() ) ) {
          throw new IllegalArgumentException(
              "Named parameter [" + name + "] type mismatch; expecting ["
                  + Calendar.class.getName() + "], found ["
                  + parameter.getParameterType().getName() + "]"
          );
        }
        setParameter( parameter, calendar, temporalType );
        return this;
      }

      @SuppressWarnings({ "unchecked" })
      public TypedQuery<X> setParameter(String name, Date date, TemporalType temporalType) {
        Parameter parameter = resolveExplicitCriteriaParameterName( name );
        if ( ! Date.class.isAssignableFrom( parameter.getParameterType() ) ) {
          throw new IllegalArgumentException(
              "Named parameter [" + name + "] type mismatch; expecting ["
                  + Date.class.getName() + "], found ["
                  + parameter.getParameterType().getName() + "]"
          );
        }
        setParameter( parameter, date, temporalType );
        return this;
      }


      // unsupported stuff ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      public int executeUpdate() {
        throw new IllegalArgumentException( "Criteria queries do not support update queries" );
      }

      public TypedQuery<X> setParameter(int i, Object o) {
        throw new IllegalArgumentException( "Criteria queries do not support positioned parameters" );
      }

      public TypedQuery<X> setParameter(int i, Calendar calendar, TemporalType temporalType) {
        throw new IllegalArgumentException( "Criteria queries do not support positioned parameters" );
      }

      public TypedQuery<X> setParameter(int i, Date date, TemporalType temporalType) {
        throw new IllegalArgumentException( "Criteria queries do not support positioned parameters" );
      }

      public Object getParameterValue(int position) {
        throw new IllegalArgumentException( "Criteria queries do not support positioned parameters" );
      }

      public Parameter<?> getParameter(int position) {
        throw new IllegalArgumentException( "Criteria queries do not support positioned parameters" );
      }

      public <T> Parameter<T> getParameter(int position, Class<T> type) {
        throw new IllegalArgumentException( "Criteria queries do not support positioned parameters" );
      }
    };
  }
}
TOP

Related Classes of org.hibernate.ejb.criteria.CriteriaQueryCompiler$RenderedCriteriaQuery

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.