net.mlw.vlh.adapter.hibernate3.HibernateAdapter.java Source code

Java tutorial

Introduction

Here is the source code for net.mlw.vlh.adapter.hibernate3.HibernateAdapter.java

Source

/**
 * Copyright (c) 2003 held jointly by the individual authors.            
 *                                                                          
 * 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.                                            
 *                                                                            
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; with out 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.              
 *                                                                            
 * > http://www.gnu.org/copyleft/lesser.html                                  
 * > http://www.opensource.org/licenses/lgpl-license.php
 */
package net.mlw.vlh.adapter.hibernate3;

import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import net.mlw.vlh.DefaultListBackedValueList;
import net.mlw.vlh.ValueList;
import net.mlw.vlh.ValueListInfo;
import net.mlw.vlh.adapter.AbstractValueListAdapter;
import net.mlw.vlh.adapter.hibernate3.util.ScrollableResultsDecorator;
import net.mlw.vlh.adapter.hibernate3.util.StatementBuilder;
import net.mlw.vlh.adapter.util.ObjectValidator;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.SessionFactoryUtils;

/** 
 *  This adapter wraps the functionality of Hibernate.
 *  Add extra functionality such as paging, focusing
 *  and validating of current result set.
 * <i>
 *   "Hibernate is a powerful, ultra-high performance 
 *   object/relational persistence and query service 
 *   for Java. Hibernate lets you develop persistent 
 *   classes following common Java idiom - including 
 *   association, inheritance, polymorphism, composition 
 *   and the Java collections framework. The Hibernate 
 *   Query Language, designed as a "minimal" 
 *   object-oriented extension to SQL, provides an 
 *   elegant bridge between the object and relational 
 *   worlds. Hibernate also allows you to express queries 
 *   using native SQL or Java-based Criteria and Example 
 *   queries. Hibernate is now the most popular 
 *   object/relational mapping solution for Java."
 * </i> -http://www.hibernate.org/
 * 
 * @author Matthew L. Wilson, Andrej Zachar
 * @version $Revision: 1.2 $ $Date: 2006/03/29 19:47:49 $
 */
public class HibernateAdapter extends AbstractValueListAdapter {
    /** The Hibernate SessionFactory. */
    private SessionFactory sessionFactory;

    /**
     * <p>
     * If is set, it use special ScrollableResultsDecorator, that enable or
     * disable to add object in final list.
     * </p>
     * <h4>NOTE:</h4>
     * <p>
     * Also, it respects the total count of entries that overlap your paged
     * list.
     * </p>
     */
    private ObjectValidator _validator = null;

    /** Commons logger. */
    private static final Log LOGGER = LogFactory.getLog(HibernateAdapter.class);

    /** If a new Session should be created if no thread-bound found. */
    private boolean allowCreate = true;

    /** The hibernate query. */
    private String hql;

    private String namedQuery;

    /** The max rows in ResulSet to doFocus 
     *  @author Andrej Zachar
     */
    private long maxRowsForFocus = Long.MAX_VALUE;

    /** The name of object use to get focus property in hibernate sql syntax 
     * SELECT defaultFocusPropertyObjectAlias.getFocusProperty ...   
     * 
     * @author Andrej Zachar
     */
    private String defaultFocusPropertyObjectAlias = "";

    /**
     * Enable or Disable String length checking of given filters values. If
     * filter value is null or empty is removed from query.
     * @author Andrej Zachar
     */
    private boolean _isRemoveEmptyStrings = false;

    private StatementBuilder statementBuilder;

    /**
     * Enable or disable optimalization of the query for focus property.
     */
    private boolean _focusOptimalization = true;

    /**
     * @return Returns the focusOptimalization.
     */
    public boolean isFocusOptimalization() {
        return _focusOptimalization;
    }

    /**
     * Enable or disable optimalization of the query for focus property.
     * @param focusOptimalization true - enable query with short select, false - query with full select
     */
    public void setFocusOptimalization(boolean focusOptimalization) {
        _focusOptimalization = focusOptimalization;
    }

    /**
     * <p>
     * If is set, it use special ScrollableResultsDecorator, that enable or
     * disable to add object in final list.
     * </p>
     * <h4>NOTE:</h4>
     * <p>
     * Also, it respects the total count of entries that overlap your paged
     * list.
     * </p>
     * @param validator The validator to set.
     */
    public void setValidator(ObjectValidator validator) {
        _validator = validator;
    }

    /**
     * @return Returns the isPrefilterEmpty.
     */
    public boolean isRemoveEmptyStrings() {
        return _isRemoveEmptyStrings;
    }

    /**
     * Enable or Disable String length checking of given filters values. If
     * filter value is null or empty is removed from query.
     * 
     * @param isPrefilterEmpty
     *            true-remove null and empty, false - remove only null filters.
     */
    public void setRemoveEmptyStrings(boolean isPrefilterEmpty) {
        _isRemoveEmptyStrings = isPrefilterEmpty;
    }

    /**
     * @see net.mlw.vlh.ValueListAdapter#getValueList(java.lang.String,
     *      net.mlw.vlh.ValueListInfo)
     */
    public ValueList getValueList(String name, ValueListInfo info) {

        LOGGER.debug("getValueList(String, ValueListInfo) - start");

        if (info.getSortingColumn() == null) {
            info.setPrimarySortColumn(getDefaultSortColumn());
            info.setPrimarySortDirection(getDefaultSortDirectionInteger());
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("The default sort column '" + getDefaultSortColumn() + "' with direction '"
                        + getDefaultSortDirectionInteger() + "' was  set.");
            }
        }

        int numberPerPage = info.getPagingNumberPer();

        if (numberPerPage == Integer.MAX_VALUE) {
            numberPerPage = getDefaultNumberPerPage();
            info.setPagingNumberPer(numberPerPage);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("The paging number per page '" + numberPerPage + "' was  set.");
            }
        }

        Session session = SessionFactoryUtils.getSession(getSessionFactory(), allowCreate);
        try {
            Query query;

            boolean doFocus = ((getAdapterType() & DO_FOCUS) == 0) && info.isFocusEnabled() && info.isDoFocus()
                    && (namedQuery == null);

            if (doFocus) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(
                            "Start to focusing adapterName '" + name + "', ValueListInfo info = " + info + "'");
                }
                ScrollableResults results = getScrollableResults(getQueryForFocus(info, session), info);
                results.beforeFirst();
                doFocusFor(info, results);

                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(
                            "Focusing finished for adapterName '" + name + "', ValueListInfo info '" + info + "'");
                }
            }

            query = getQuery(info, session);

            boolean doPaging = ((getAdapterType() & DO_PAGE) == 0);

            List list;

            if (doPaging) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("getValueList(String adapterName = " + name + ", ValueListInfo info = " + info
                            + ") - Start to paging result set");
                }

                list = new ArrayList(numberPerPage);
                ScrollableResults results = getScrollableResults(query, info);

                results.last();
                int lastRowNumber = results.getRowNumber();
                info.setTotalNumberOfEntries(lastRowNumber + 1);

                if (numberPerPage == 0) {
                    numberPerPage = getDefaultNumberPerPage();
                }

                int pageNumber = info.getPagingPage();
                boolean isResult;
                if (pageNumber > 1) {
                    if ((pageNumber - 1) * numberPerPage > lastRowNumber) {
                        pageNumber = (lastRowNumber / numberPerPage) + 1;
                        info.setPagingPage(pageNumber);
                    }
                }
                // fixed by liujuan 2008.6.5
                isResult = results.first();

                if (pageNumber > 1) {
                    // isResult = results.scroll((pageNumber - 1) * numberPerPage - lastRowNumber);
                    isResult = results.scroll((pageNumber - 1) * numberPerPage);
                }
                /*else
                {
                   isResult = results.first();
                }*/

                for (int i = 0; i < numberPerPage && isResult; i++) {
                    list.add(results.get(0));
                    isResult = results.next();
                }

                LOGGER.debug("Sorting finished.");

            } else {

                LOGGER.debug("Retrieving a list directly from the query.");

                list = query.list();
                info.setTotalNumberOfEntries(list.size());
            }

            ValueList returnValueList = getListBackedValueList(info, list);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Retrieved list was wrapped in valuelist, info=" + info);
            }
            return returnValueList;
        } catch (HibernateException e) {
            LOGGER.error("Error getting data in adapater '" + name + "' with info = '" + info + "'", e);
            throw SessionFactoryUtils.convertHibernateAccessException(e);
        } catch (Exception e) {
            LOGGER.fatal("Fatal error getting data in adapater '" + name + "' with info = '" + info + "'", e);
            return null;
        } finally {
            SessionFactoryUtils.releaseSession(session, getSessionFactory());
        }
    }

    /**     
     * @param info
     * @param list
     * @return DefaultListBackValueList instance
     */
    protected ValueList getListBackedValueList(ValueListInfo info, List list) {
        return new DefaultListBackedValueList(list, info);
    }

    /**
     * @param info
     * @param results
     * @throws HibernateException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private void doFocusFor(ValueListInfo info, ScrollableResults results) throws HibernateException {
        info.setFocusStatus(ValueListInfo.FOCUS_NOT_FOUND);

        int currentRow;
        if (isFocusOptimalization()) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Focusing only property '" + info.getFocusProperty() + "' == '" + info.getFocusValue()
                        + "'.");
            }
            for (currentRow = 0; ((results.next()) && (currentRow < maxRowsForFocus)); currentRow++) {
                String value = results.get(0).toString();
                if (value.equalsIgnoreCase(info.getFocusValue())) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info(
                                "Focus property '" + info.getFocusProperty() + "' in row '" + currentRow + "'.");
                    }
                    info.setPagingPageFromRowNumber(results.getRowNumber());
                    info.setFocusedRowNumberInTable(results.getRowNumber());
                    info.setFocusStatus(ValueListInfo.FOCUS_FOUND);
                    break;
                }
            }
        } else {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Focusing object with the property '" + info.getFocusProperty() + "' == '"
                        + info.getFocusValue() + "'.");
            }
            for (currentRow = 0; ((results.next()) && (currentRow < maxRowsForFocus)); currentRow++) {

                Object value;
                try {
                    value = PropertyUtils.getProperty(results.get(0), info.getFocusProperty());
                } catch (HibernateException e) {
                    LOGGER.error("Error getting focus property '" + info.getFocusProperty() + "'", e);
                    throw e;
                } catch (Exception e) {
                    LOGGER.warn("Ingoring error while getting focus property '" + info.getFocusProperty() + "'", e);
                    continue;
                }

                if (value.toString().equalsIgnoreCase(info.getFocusValue())) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Focus object's property '" + info.getFocusProperty()
                                + "' was found in the row '" + currentRow + "'.");
                    }
                    info.setPagingPageFromRowNumber(results.getRowNumber());
                    info.setFocusedRowNumberInTable(results.getRowNumber());
                    info.setFocusStatus(ValueListInfo.FOCUS_FOUND);
                    break;
                }
            }
        }
        if (currentRow == maxRowsForFocus) {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("Focus for property '" + info.getFocusProperty() + "' exceded maximum rows for focus '"
                        + maxRowsForFocus + "'.");
            }
            info.setFocusStatus(ValueListInfo.FOCUS_TOO_MANY_ITEMS);
        }
    }

    /**
     * @param query
     * @param info ValueListInfo This info will be set to validator. 
     * @return ScrollableResults, if is set non null _validator, it returns the
     *         ScrollableResultsDecorator.
     * @throws HibernateException
     */
    private ScrollableResults getScrollableResults(Query query, ValueListInfo info) throws HibernateException {
        ScrollableResults results;

        if (_validator == null) {
            LOGGER.debug("Validator is null, using normal ScrollableResults");
            results = query.scroll();

        } else {
            LOGGER.info("Using decorator of the ScrollableResults with your validator.");
            _validator.setValueListInfo(info);
            results = new ScrollableResultsDecorator(query.scroll(), _validator);
        }

        return results;
    }

    /**
     * @param info
     * @param session
     * @return @throws
     *         HibernateException
     */
    private Query getQuery(ValueListInfo info, Session session) throws HibernateException, ParseException {

        if (getHql() != null) {
            return getStatementBuilder().generate(session, new StringBuffer(getHql()), info.getFilters(),
                    _isRemoveEmptyStrings);
        } else {
            if (namedQuery != null) {
                return session.getNamedQuery(getNamedQuery());
            } else {
                throw new HibernateException("Please define any QUERY in value list retrieve adpater!");
            }
        }
    }

    /**
     * If focus optimalization is true, it select only focus property. For
     * validator is recommended to set it to false, while you want to validate
     * properties of retrieved objects.
     * 
     * @param info
     * @param session
     * @return
     * @throws HibernateException
     */
    private Query getQueryForFocus(ValueListInfo info, Session session) throws HibernateException, ParseException {
        if (isFocusOptimalization()) {
            LOGGER.info("Focus will use optimalizated query.");
            return getOptimizedQuery(info, session);
        } else {
            LOGGER.info("Focus will use normal (full) query.");
            return getQuery(info, session);
        }
    }

    /**
     * 
     * @param info
     * @param session
     * @return query that select only focus property.
     * @throws HibernateException
     * @throws ParseException
     */
    private Query getOptimizedQuery(ValueListInfo info, Session session) throws HibernateException, ParseException {
        if (getHql() != null) {
            return getStatementBuilder().generateForFocus(session, new StringBuffer(getHql()), info.getFilters(),
                    _isRemoveEmptyStrings, defaultFocusPropertyObjectAlias, info.getFocusProperty());

        } else {
            throw new HibernateException(
                    "Please define any HQL QUERY in value list retrieve adpater, function is not implemented for NamedQuery!");
        }
    }

    /** Set the Hibernate SessionFactory to be used by this DAO.
     * 
     * @param sessionFactory The Hibernate SessionFactory to be used by this DAO.
     */
    public final void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /** Return the Hibernate SessionFactory used by this DAO.
     * 
     * @return The Hibernate SessionFactory used by this DAO.
     */
    protected final SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    /** Sets the hql used to retrieve the data.
     * @param hql The hql to set.
     * @deprecated use setHql(String)
     */
    public void setHsql(String hql) {
        this.hql = hql;
    }

    /** Sets the hql used to retrieve the data.
     * @param hql The hql to set.
     */
    public void setHql(String hql) {
        this.hql = hql;
    }

    /** Returns the namedQuery.
     * @return Returns the namedQuery.
     */
    public String getNamedQuery() {
        return namedQuery;
    }

    /** Sets the namedQuery.  
     * <p>
     *   NOTE: by using this you can not enable sorting, filtering,
     *   paging of the data, and  focusing of rows.
     * </p>
     * @param namedQuery
     *            The namedQuery to set.
     */
    public void setNamedQuery(String namedQuery) {
        this.namedQuery = namedQuery;
    }

    /** Gets the hql used to retrieve the data.
     * @return Returns the hql.
     */
    public String getHql() {
        return hql;
    }

    /** Sets: If a new Session should be created if no thread-bound found.
     * 
     * @param allowCreate
     *            The allowCreate to set.
     */
    public void setAllowCreate(boolean allowCreate) {
        this.allowCreate = allowCreate;
    }

    /**
     * Maximum rows to search with Focus
     * 
     * @return Returns the maxRowsForFocus.
     */
    public long getMaxRowsForFocus() {
        return maxRowsForFocus;
    }

    /**
     * Maximum rows to search with Focus
     * 
     * @param maxRowsForFocus
     *            The maxRowsForFocus to set.
     */
    public void setMaxRowsForFocus(long maxRowsForFocus) {
        this.maxRowsForFocus = maxRowsForFocus;
    }

    /**
     * @return Returns the defaultFocusPropertyObject.
     */
    public String getDefaultFocusPropertyObjectAlias() {
        return defaultFocusPropertyObjectAlias;
    }

    /** 
     * The name of object use to get focus property in hibernate hql syntax 
     * SELECT defaultFocusPropertyObjectAlias.getFocusProperty ...  
     * 
     * @param defaultFocusPropertyObjectAlias
     *            The defaultFocusPropertyObjectAlias to set.
     */
    public void setDefaultFocusPropertyObjectAlias(String defaultFocusPropertyObjectAlias) {
        this.defaultFocusPropertyObjectAlias = defaultFocusPropertyObjectAlias + ".";
    }

    /**
     * @return Returns the statementBuilder.
     */
    public StatementBuilder getStatementBuilder() {
        if (statementBuilder == null) {
            statementBuilder = new StatementBuilder();
        }
        return statementBuilder;
    }

    /**
     * @param statementBuilder The statementBuilder to set.
     */
    public void setStatementBuilder(StatementBuilder statementBuilder) {
        this.statementBuilder = statementBuilder;
    }
}