Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » engine » query » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.engine.query;
   26   
   27   import org.hibernate.util.SimpleMRUCache;
   28   import org.hibernate.util.SoftLimitMRUCache;
   29   import org.hibernate.engine.SessionFactoryImplementor;
   30   import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
   31   import org.hibernate.QueryException;
   32   import org.hibernate.MappingException;
   33   import org.slf4j.Logger;
   34   import org.slf4j.LoggerFactory;
   35   
   36   import java.io.Serializable;
   37   import java.util.Map;
   38   import java.util.HashMap;
   39   import java.util.Iterator;
   40   import java.util.Set;
   41   import java.util.HashSet;
   42   import java.util.Collections;
   43   
   44   /**
   45    * Acts as a cache for compiled query plans, as well as query-parameter metadata.
   46    *
   47    * @author Steve Ebersole
   48    */
   49   public class QueryPlanCache implements Serializable {
   50   
   51   	private static final Logger log = LoggerFactory.getLogger( QueryPlanCache.class );
   52   
   53   	private SessionFactoryImplementor factory;
   54   
   55   	public QueryPlanCache(SessionFactoryImplementor factory) {
   56   		this.factory = factory;
   57   	}
   58   
   59   	// simple cache of param metadata based on query string.  Ideally, the
   60   	// original "user-supplied query" string should be used to retreive this
   61   	// metadata (i.e., not the para-list-expanded query string) to avoid
   62   	// unnecessary cache entries.
   63   	// Used solely for caching param metadata for native-sql queries, see
   64   	// getSQLParameterMetadata() for a discussion as to why...
   65   	private final SimpleMRUCache sqlParamMetadataCache = new SimpleMRUCache();
   66   
   67   	// the cache of the actual plans...
   68   	private final SoftLimitMRUCache planCache = new SoftLimitMRUCache( 128 );
   69   
   70   
   71   	public ParameterMetadata getSQLParameterMetadata(String query) {
   72   		ParameterMetadata metadata = ( ParameterMetadata ) sqlParamMetadataCache.get( query );
   73   		if ( metadata == null ) {
   74   			// for native-sql queries, the param metadata is determined outside
   75   			// any relation to a query plan, because query plan creation and/or
   76   			// retreival for a native-sql query depends on all of the return
   77   			// types having been set, which might not be the case up-front when
   78   			// param metadata would be most useful
   79   			metadata = buildNativeSQLParameterMetadata( query );
   80   			sqlParamMetadataCache.put( query, metadata );
   81   		}
   82   		return metadata;
   83   	}
   84   
   85   	public HQLQueryPlan getHQLQueryPlan(String queryString, boolean shallow, Map enabledFilters)
   86   			throws QueryException, MappingException {
   87   		HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
   88   		HQLQueryPlan plan = ( HQLQueryPlan ) planCache.get ( key );
   89   
   90   		if ( plan == null ) {
   91   			if ( log.isTraceEnabled() ) {
   92   				log.trace( "unable to locate HQL query plan in cache; generating (" + queryString + ")" );
   93   			}
   94   			plan = new HQLQueryPlan(queryString, shallow, enabledFilters, factory );
   95   		}
   96   		else {
   97   			if ( log.isTraceEnabled() ) {
   98   				log.trace( "located HQL query plan in cache (" + queryString + ")" );
   99   			}
  100   		}
  101   
  102   		planCache.put( key, plan );
  103   
  104   		return plan;
  105   	}
  106   
  107   	public FilterQueryPlan getFilterQueryPlan(String filterString, String collectionRole, boolean shallow, Map enabledFilters)
  108   			throws QueryException, MappingException {
  109   		FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters );
  110   		FilterQueryPlan plan = ( FilterQueryPlan ) planCache.get ( key );
  111   
  112   		if ( plan == null ) {
  113   			if ( log.isTraceEnabled() ) {
  114   				log.trace( "unable to locate collection-filter query plan in cache; generating (" + collectionRole + " : " + filterString + ")" );
  115   			}
  116   			plan = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters, factory );
  117   		}
  118   		else {
  119   			if ( log.isTraceEnabled() ) {
  120   				log.trace( "located collection-filter query plan in cache (" + collectionRole + " : " + filterString + ")" );
  121   			}
  122   		}
  123   
  124   		planCache.put( key, plan );
  125   
  126   		return plan;
  127   	}
  128   
  129   	public NativeSQLQueryPlan getNativeSQLQueryPlan(NativeSQLQuerySpecification spec) {
  130   		NativeSQLQueryPlan plan = ( NativeSQLQueryPlan ) planCache.get( spec );
  131   
  132   		if ( plan == null ) {
  133   			if ( log.isTraceEnabled() ) {
  134   				log.trace( "unable to locate native-sql query plan in cache; generating (" + spec.getQueryString() + ")" );
  135   			}
  136   			plan = new NativeSQLQueryPlan( spec, factory );
  137   		}
  138   		else {
  139   			if ( log.isTraceEnabled() ) {
  140   				log.trace( "located native-sql query plan in cache (" + spec.getQueryString() + ")" );
  141   			}
  142   		}
  143   
  144   		planCache.put( spec, plan );
  145   		return plan;
  146   	}
  147   
  148   	private ParameterMetadata buildNativeSQLParameterMetadata(String sqlString) {
  149   		ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( sqlString );
  150   
  151   		OrdinalParameterDescriptor[] ordinalDescriptors =
  152   				new OrdinalParameterDescriptor[ recognizer.getOrdinalParameterLocationList().size() ];
  153   		for ( int i = 0; i < recognizer.getOrdinalParameterLocationList().size(); i++ ) {
  154   			final Integer position = ( Integer ) recognizer.getOrdinalParameterLocationList().get( i );
  155   			ordinalDescriptors[i] = new OrdinalParameterDescriptor( i, null, position.intValue() );
  156   		}
  157   
  158   		Iterator itr = recognizer.getNamedParameterDescriptionMap().entrySet().iterator();
  159   		Map namedParamDescriptorMap = new HashMap();
  160   		while( itr.hasNext() ) {
  161   			final Map.Entry entry = ( Map.Entry ) itr.next();
  162   			final String name = ( String ) entry.getKey();
  163   			final ParamLocationRecognizer.NamedParameterDescription description =
  164   					( ParamLocationRecognizer.NamedParameterDescription ) entry.getValue();
  165   			namedParamDescriptorMap.put(
  166   					name ,
  167   			        new NamedParameterDescriptor( name, null, description.buildPositionsArray(), description.isJpaStyle() )
  168   			);
  169   		}
  170   
  171   		return new ParameterMetadata( ordinalDescriptors, namedParamDescriptorMap );
  172   	}
  173   
  174   	private static class HQLQueryPlanKey implements Serializable {
  175   		private final String query;
  176   		private final boolean shallow;
  177   		private final Set filterNames;
  178   		private final int hashCode;
  179   
  180   		public HQLQueryPlanKey(String query, boolean shallow, Map enabledFilters) {
  181   			this.query = query;
  182   			this.shallow = shallow;
  183   
  184   			if ( enabledFilters == null || enabledFilters.isEmpty() ) {
  185   				filterNames = Collections.EMPTY_SET;
  186   			}
  187   			else {
  188   				Set tmp = new HashSet();
  189   				tmp.addAll( enabledFilters.keySet() );
  190   				this.filterNames = Collections.unmodifiableSet( tmp );
  191   			}
  192   
  193   			int hash = query.hashCode();
  194   			hash = 29 * hash + ( shallow ? 1 : 0 );
  195   			hash = 29 * hash + filterNames.hashCode();
  196   			this.hashCode = hash;
  197   		}
  198   
  199   		public boolean equals(Object o) {
  200   			if ( this == o ) {
  201   				return true;
  202   			}
  203   			if ( o == null || getClass() != o.getClass() ) {
  204   				return false;
  205   			}
  206   
  207   			final HQLQueryPlanKey that = ( HQLQueryPlanKey ) o;
  208   
  209   			if ( shallow != that.shallow ) {
  210   				return false;
  211   			}
  212   			if ( !filterNames.equals( that.filterNames ) ) {
  213   				return false;
  214   			}
  215   			if ( !query.equals( that.query ) ) {
  216   				return false;
  217   			}
  218   
  219   			return true;
  220   		}
  221   
  222   		public int hashCode() {
  223   			return hashCode;
  224   		}
  225   	}
  226   
  227   	private static class FilterQueryPlanKey implements Serializable {
  228   		private final String query;
  229   		private final String collectionRole;
  230   		private final boolean shallow;
  231   		private final Set filterNames;
  232   		private final int hashCode;
  233   
  234   		public FilterQueryPlanKey(String query, String collectionRole, boolean shallow, Map enabledFilters) {
  235   			this.query = query;
  236   			this.collectionRole = collectionRole;
  237   			this.shallow = shallow;
  238   
  239   			if ( enabledFilters == null || enabledFilters.isEmpty() ) {
  240   				filterNames = Collections.EMPTY_SET;
  241   			}
  242   			else {
  243   				Set tmp = new HashSet();
  244   				tmp.addAll( enabledFilters.keySet() );
  245   				this.filterNames = Collections.unmodifiableSet( tmp );
  246   			}
  247   
  248   			int hash = query.hashCode();
  249   			hash = 29 * hash + collectionRole.hashCode();
  250   			hash = 29 * hash + ( shallow ? 1 : 0 );
  251   			hash = 29 * hash + filterNames.hashCode();
  252   			this.hashCode = hash;
  253   		}
  254   
  255   		public boolean equals(Object o) {
  256   			if ( this == o ) {
  257   				return true;
  258   			}
  259   			if ( o == null || getClass() != o.getClass() ) {
  260   				return false;
  261   			}
  262   
  263   			final FilterQueryPlanKey that = ( FilterQueryPlanKey ) o;
  264   
  265   			if ( shallow != that.shallow ) {
  266   				return false;
  267   			}
  268   			if ( !filterNames.equals( that.filterNames ) ) {
  269   				return false;
  270   			}
  271   			if ( !query.equals( that.query ) ) {
  272   				return false;
  273   			}
  274   			if ( !collectionRole.equals( that.collectionRole ) ) {
  275   				return false;
  276   			}
  277   
  278   			return true;
  279   		}
  280   
  281   		public int hashCode() {
  282   			return hashCode;
  283   		}
  284   	}
  285   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » engine » query » [javadoc | source]