All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avaje.ebeaninternal.server.query.CQueryEngine Maven / Gradle / Ivy

There is a newer version: 2.8.1
Show newest version
/**
 * Copyright (C) 2006  Robin Bygrave
 * 
 * This file is part of Ebean.
 * 
 * Ebean 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.
 *  
 * Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA  
 */
package com.avaje.ebeaninternal.server.query;

import java.sql.SQLException;
import java.util.concurrent.FutureTask;
import java.util.logging.Logger;

import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionTouched;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebeaninternal.api.BeanIdList;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.jmx.MAdminLogging;
import com.avaje.ebeaninternal.server.lucene.LuceneIndexManager;
import com.avaje.ebeaninternal.server.persist.Binder;

/**
 * Handles the Object Relational fetching.
 */
public class CQueryEngine {

	private static final Logger logger = Logger.getLogger(CQueryEngine.class.getName());
	
	private final CQueryBuilder queryBuilder;

	private final MAdminLogging logControl;

	private final BackgroundExecutor backgroundExecutor;

	private final int defaultSecondaryQueryBatchSize = 100;

	public CQueryEngine(DatabasePlatform dbPlatform, MAdminLogging logControl, Binder binder, 
	        BackgroundExecutor backgroundExecutor, LuceneIndexManager luceneIndexManager) {

		this.logControl = logControl;
		this.backgroundExecutor = backgroundExecutor;
		this.queryBuilder = new CQueryBuilder(backgroundExecutor, dbPlatform, binder, luceneIndexManager);
	}

	public  CQuery buildQuery(OrmQueryRequest request) {
		return queryBuilder.buildQuery(request);
	}

	/**
	 * Build and execute the find Id's query.
	 */
	public  BeanIdList findIds(OrmQueryRequest request) {


		CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request);
		try {

			String sql = rcQuery.getGeneratedSql();
			sql = sql.replace(Constants.NEW_LINE, ' ');

			if (logControl.isDebugGeneratedSql()) {
				System.out.println(sql);
			}
			request.logSql(sql);
			

			BeanIdList list = rcQuery.findIds();

			if (request.isLogSummary()) {
				request.getTransaction().logInternal(rcQuery.getSummary());
			}

			if (!list.isFetchingInBackground() && request.getQuery().isFutureFetch()){
				// end the transaction for futureFindIds (it had it's own one)
				logger.fine("Future findIds completed!");
				request.getTransaction().end();
			}
			
			return list;

		} catch (SQLException e) {
		    throw CQuery.createPersistenceException(e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql());
		}
	}
	
	/**
	 * Build and execute the row count query.
	 */
	public  int findRowCount(OrmQueryRequest request) {


		CQueryRowCount rcQuery = queryBuilder.buildRowCountQuery(request);
		try {

			String sql = rcQuery.getGeneratedSql();
			sql = sql.replace(Constants.NEW_LINE, ' ');

			if (logControl.isDebugGeneratedSql()) {
				System.out.println(sql);
			}
			request.logSql(sql);

			int rowCount = rcQuery.findRowCount();

			if (request.isLogSummary()) {
				request.getTransaction().logInternal(rcQuery.getSummary());
			}
			
			if (request.getQuery().isFutureFetch()){
				logger.fine("Future findRowCount completed!");
				request.getTransaction().end();
			}
			
			return rowCount;

		} catch (SQLException e) {
		    throw CQuery.createPersistenceException(e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql());
		} 
	}

    /**
     * Read many beans using an iterator (except you need to close() the iterator when you have finished).
     */
    public  QueryIterator findIterate(OrmQueryRequest request) {

        CQuery cquery = queryBuilder.buildQuery(request);
        request.setCancelableQuery(cquery);
        
        try {

            if (logControl.isDebugGeneratedSql()) {
                logSqlToConsole(cquery);
            }
            
            if (request.isLogSql()) {
                logSql(cquery);
            }

            if (!cquery.prepareBindExecuteQuery()) {
                // query has been cancelled already
                logger.finest("Future fetch already cancelled");
                return null;
            }

            int iterateBufferSize = request.getSecondaryQueriesMinBatchSize(defaultSecondaryQueryBatchSize);
            
            QueryIterator readIterate = cquery.readIterate(iterateBufferSize, request);
            
            if (request.isLogSummary()) {
                logFindManySummary(cquery);
            }
            
            return readIterate;

        } catch (SQLException e) {
            throw cquery.createPersistenceException(e);
        } 
    }
	
	/**
	 * Find a list/map/set of beans.
	 */
	public  BeanCollection findMany(OrmQueryRequest request) {

		// flag indicating whether we need to close the resources...
		boolean useBackgroundToContinueFetch = false;

		CQuery cquery = queryBuilder.buildQuery(request);
		request.setCancelableQuery(cquery);
		
		try {

			if (logControl.isDebugGeneratedSql()) {
				logSqlToConsole(cquery);
			}
			if (request.isLogSql()) {
				logSql(cquery);
			}

			if (!cquery.prepareBindExecuteQuery()) {
				// query has been cancelled already
				logger.finest("Future fetch already cancelled");
				return null;
			}

			BeanCollection beanCollection = cquery.readCollection();
			if (request.getParentState() != EntityBeanIntercept.DEFAULT){
				// effectively making the collection immutable
				beanCollection.setSharedInstance();
			}
			
			BeanCollectionTouched collectionTouched = request.getQuery().getBeanCollectionTouched();
			if (collectionTouched != null){
				// register a listener that wants to be notified when the
				// bean collection is first used
				beanCollection.setBeanCollectionTouched(collectionTouched);
			}

			if (cquery.useBackgroundToContinueFetch()) {
				// stop the request from putting connection back into pool
				// before background fetching is finished.
				request.setBackgroundFetching();
				useBackgroundToContinueFetch = true;
				BackgroundFetch fetch = new BackgroundFetch(cquery);

				FutureTask future = new FutureTask(fetch);
				beanCollection.setBackgroundFetch(future);
				backgroundExecutor.execute(future);
			}

			if (request.isLogSummary()) {
				logFindManySummary(cquery);
			}
			
			request.executeSecondaryQueries(defaultSecondaryQueryBatchSize);
	
			return beanCollection;

		} catch (SQLException e) {
            throw cquery.createPersistenceException(e);//request, e, cquery.getBindLog(), cquery.getGeneratedSql());

		} finally {
			if (useBackgroundToContinueFetch) {
				// left closing resources to BackgroundFetch...
			} else {
				if (cquery != null) {
					cquery.close();
				}
				if (request.getQuery().isFutureFetch()){
					// end the transaction for futureFindIds 
					// as it had it's own transaction
					logger.fine("Future fetch completed!");
					request.getTransaction().end();
				}
			}
		}
	}

	
	/**
	 * Find and return a single bean using its unique id.
	 */
	public  T find(OrmQueryRequest request) {

		T bean = null;

		CQuery cquery = queryBuilder.buildQuery(request);

		try {
			if (logControl.isDebugGeneratedSql()) {
				logSqlToConsole(cquery);
			}
			if (request.isLogSql()) {
				logSql(cquery);
			}

			cquery.prepareBindExecuteQuery();

			if (cquery.readBean()) {
				bean = cquery.getLoadedBean();
			}

			if (request.isLogSummary()) {
				logFindBeanSummary(cquery);
			}

			request.executeSecondaryQueries(defaultSecondaryQueryBatchSize);
			
			return bean;

		} catch (SQLException e) {
		    throw cquery.createPersistenceException(e);

		} finally {
			cquery.close();
		}
	}

    /**
	 * Log the generated SQL to the console.
	 */
	private void logSqlToConsole(CQuery cquery) {

		SpiQuery query = cquery.getQueryRequest().getQuery();
		String loadMode = query.getLoadMode();
		String loadDesc = query.getLoadDescription();
		
		String sql = cquery.getGeneratedSql();
		String summary = cquery.getSummary();

		StringBuilder sb = new StringBuilder(1000);
		sb.append("");
		sb.append(Constants.NEW_LINE);
		sb.append(sql);
		sb.append(Constants.NEW_LINE).append("");

		System.out.println(sb.toString());
	}

	/**
	 * Log the generated SQL to the transaction log.
	 */
	private void logSql(CQuery query) {

		String sql = query.getGeneratedSql();
		sql = sql.replace(Constants.NEW_LINE, ' ');
		query.getTransaction().logInternal(sql);
	}

	/**
	 * Log the FindById summary to the transaction log.
	 */
	private void logFindBeanSummary(CQuery q) {

        SpiQuery query = q.getQueryRequest().getQuery();
        String loadMode = query.getLoadMode();
        String loadDesc = query.getLoadDescription();
        String lazyLoadProp = query.getLazyLoadProperty();
        ObjectGraphNode node = query.getParentNode();
        String originKey = node == null ? null : node.getOriginQueryPoint().getKey();
        
        StringBuilder msg = new StringBuilder(200);
        msg.append("FindBean ");
        if (loadMode != null) {
            msg.append("mode[").append(loadMode).append("] ");
        }
        msg.append("type[").append(q.getBeanName()).append("] ");
        if (query.isAutofetchTuned()) {
            msg.append("tuned[true] ");
        }
        if (originKey != null) {
            msg.append("origin[").append(originKey).append("] ");
        }
        if (lazyLoadProp != null) {
            msg.append("lazyLoadProp[").append(lazyLoadProp).append("] ");
        }
        if (loadDesc != null) {
            msg.append("load[").append(loadDesc).append("] ");
        }
		msg.append("exeMicros[").append(q.getQueryExecutionTimeMicros());
		msg.append("] rows[").append(q.getLoadedRowDetail());
		msg.append("] bind[").append(q.getBindLog()).append("]");

		q.getTransaction().logInternal(msg.toString());
	}

	/**
	 * Log the FindMany to the transaction log.
	 */
	private void logFindManySummary(CQuery q) {

        SpiQuery query = q.getQueryRequest().getQuery();
        String loadMode = query.getLoadMode();
        String loadDesc = query.getLoadDescription();
        String lazyLoadProp = query.getLazyLoadProperty();
        ObjectGraphNode node = query.getParentNode();
        String originKey = node == null ? null : node.getOriginQueryPoint().getKey();
        
		StringBuilder msg = new StringBuilder(200);
        msg.append("FindMany ");
        if (loadMode != null) {
            msg.append("mode[").append(loadMode).append("] ");
        }
        msg.append("type[").append(q.getBeanName()).append("] ");
        if (query.isAutofetchTuned()) {
            msg.append("tuned[true] ");
        }
        if (originKey != null) {
            msg.append("origin[").append(originKey).append("] ");
        }
        if (lazyLoadProp != null){
            msg.append("lazyLoadProp[").append(lazyLoadProp).append("] ");
        }
        if (loadDesc != null) {
            msg.append("load[").append(loadDesc).append("] ");
        }
		msg.append("exeMicros[").append(q.getQueryExecutionTimeMicros());
		msg.append("] rows[").append(q.getLoadedRowDetail());
		msg.append("] name[").append(q.getName());
		msg.append("] predicates[").append(q.getLogWhereSql());
		msg.append("] bind[").append(q.getBindLog()).append("]");
		
		
		q.getTransaction().logInternal(msg.toString());
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy