Matthias Wessendorf wrote:
Hi,

I just started on looking at Hibernate and I want to
use Hibernate from backing beans of my MyFaces application.

Good idea, although lots of work.


I'd like to introduce the Hibernate "Session" for the *whole*
application.

Not a good idea, better go for the prefabricated solutions which
do the session management for you (see below)

The better way is to use a sessionfactory class which automates the session handling, or go directly to spring which does it either but
also adds automated transaction handling there.
The usual way is, that most session factory classes I have seen so far
bind the sessions to a single thread and do session pooling.



I'd like to create a managed bean (application scope) that uses
Hibernate's SessionFactory for creating/getting a Session.

As I said no need, go for the Spring framework, there you can have
 a session management which is rather automated.
(I already married xdoclet, spring, hibernate and JSF on many levels
and they complement each other very well)


The main problem with hibernate and JSF you will run into is basically that you need some kind of DataModel for the datatable and data iterators because you dont want to load an entire table or want to keep the session scope open all the time to to lazy fetching (keeping the session open is a bad idea because you keep the connections basically open)


I attach a model there, you just have to add your hibernate code for the query and alter it a little bit.

As I said, to my knowledge, the ideal solution, although very steep learning curve involved, is to use hibernate in combination with spring for session and transaction management and other goodies (like various services you might need later on)
and have your own or someone elses hibernate data model involved (which neither spring nor jsf delivers for you)


Later you can combine those efforts with xdoclet to get automated standard forms for most parts of your application.
But have in mind, this is very steep learning wise, it took me a month to get everything together and working very well.


I attached a set of classes which should give you a clou on how things are interwoven together, feel free to use them (or add them to myfaces)

those dont use spring... I use spring basically in different layers but have not moved spring yet into this layer where those objects are located.

What happens basically is, that I have a query object which basically encapsules the query and that one is passed into the data model, the data model does some internal caching so that the connections dont have to be kept open. The model is bound to the data table itself for a master view with a table overview (works also with the integrated JSF paging).

In the detail view only the dataset itself or the respective hibernate object is bound to the controls (not covered by this code) with DAO code for the new update and delete operations.
The traversal of the data between the form and the hibernate object basically is done semi automatically thanks to JSF.


The whole thing sounds rather messy, and it is, but this is JSF where you have to handle at least 3 files simultaneously per page, unfortunately.


The classes wont work ootb, because they have dependencies into other code of my project, but they should give you a headstart and a clue on how to glue things together hopefully.


/*
 * Created on 05.01.2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package jsf.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.faces.model.DataModel;
import jsf.common.Constants;
import misc.BaseDatabaseObject;
import misc.JSFUtil;
import misc.NavigationBean;
import framework.cache.ICacheObject;

/**
 * @author Werner Punz MediaData A simple data model which marries hibernate
 *         with JSF
 */
public class HibernateDataModel extends DataModel implements ICacheObject {

        // define a cachingWindow to keep the number of
        // connections/accessno at a sane level
        // from time to time an isolation level error
        // can occur since we seal the objects off
        // and then close the connection
        // so no real data integrity can be performed that way
        // but it should be good enough for the average webapp
        int                             _cacheWindowSize        = 500;
        // array list due to the fact that this one has the fastes
        // absolute access which is necessary for paging
        List                    _cacheWindow            = new 
ArrayList(_cacheWindowSize);
        // helper idcache for faster access
        Map                             _idCache                        = new 
TreeMap();
        // the cache window Position relative to the 0 absolute
        int                             _cacheWindowPos         = 0;
        boolean                 _cacheInvalidated       = true;
        // the standard variables which are defined by the system
        int                             _rowCount                       = -1;
        int                             _rowIndex                       = -1;
        // the associated query accessor
        IDataAccessor   _queryDelegate          = null;

        public void resetModel() {
                _rowCount = -1;
                _rowIndex = -1;
                invalidateCache();
                refillCache();
        }

        /**
         * 
         */
        public HibernateDataModel(IDataAccessor queryDelegate) {
                super();
                setQueryDelegate(queryDelegate);
                // refillCache();
        }

        public HibernateDataModel() {
                super();
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.faces.model.DataModel#getRowCount()
         * 
         * Return the number of rows of data objects represented by this 
DataModel.
         * If the number of rows is unknown, or no wrappedData is available, 
return
         * -1.
         * 
         */
        public int getRowCount() {
                if (_rowCount == 0) {
                        return -1;
                }
                return _rowCount;
        }

        /**
         * setter accessed by the query object
         * 
         * @param rowCount
         */
        public void setRowCount(int rowCount) {
                this._rowCount = rowCount;
                // if(_rowIndex >= _rowCount-1)
                // _rowIndex = -1;
        }

        // returns true if the dataset is within
        boolean isCached() {
                if (_cacheWindow == null || _cacheWindow.size() == 0)
                        return false;
                else
                        return ((_cacheWindowPos <= getRowIndex()) && 
(getRowIndex() < (_cacheWindowPos + _cacheWindow.size())));
        }

        /**
         * refills the cache window upon the given row index this one in the 
long
         * term will possible be called from outside also
         */
        public void refillCache() {
                // calculate a decent new cache window pos, if possible with 
the current
                // row index
                // in the middle
                _cacheWindowPos = Math.max(0, getRowIndex() - (_cacheWindowSize 
/ 2));
                // refill the cache with the query
                if (_cacheWindowSize > 0) {
                        _cacheWindow = 
_queryDelegate.queryDatasets(_cacheWindowPos, _cacheWindowSize);
                        _idCache = new TreeMap();
                        for (Object elem : _cacheWindow) {
                                _idCache.put(((BaseDatabaseObject) 
elem).getId(), elem);
                        }
                        if (_cacheWindow.size() == 0) {
                                setRowCount(0);
                                setRowIndex(-1);
                        }
                        // store the current displayed datasets in the 
navigatinal bean
                        // to allow compound ops
                        NavigationBean navBean = (NavigationBean) 
JSFUtil.getManagedBean(Constants.MBEAN_NAVBEAN);
                        navBean.setCurrentNavSelection(_cacheWindow);
                }
                _cacheInvalidated = false;
        }

        /*
         * (non-Javadoc)
         * 
         * @see jsf.common.ICacheObject#invalidateCache()
         */
        public void invalidateCache() {
                _cacheInvalidated = true;
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.faces.model.DataModel#getRowData()
         * 
         * Return an object representing the data for the currenty selected row
         * index. If no wrappedData is available, return null.
         */
        public Object getRowData() {
                // synchronize this just in case we implemnt
                // an internal cache dumping mechanism
                // for hit fault reduction
                try {
                        synchronized (_cacheWindow) {
                                // fetch a cached object
                                if ((!_cacheInvalidated) && isCached()) {
                                        return getObjectFromCache();
                                }
                                // reload the cache and get the object
                                refillCache();
                                return getObjectFromCache();
                        }
                } catch (RuntimeException ex) {
                        invalidateCache();
                        throw ex;
                }
        }

        /**
         * @return
         */
        private Object getObjectFromCache() {
                if (_cacheWindow.size() == 0)
                        return null;
                return _cacheWindow.get(Math.min(_cacheWindow.size(), 
Math.max(0, getRowIndex() - _cacheWindowPos)));
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.faces.model.DataModel#getRowIndex()
         * 
         * Return the zero-relative index of the currently selected row. If we 
are
         * not currently positioned on a row, or no wrappedData is available, 
return
         * -1.
         */
        public int getRowIndex() {
                return _rowIndex;
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.faces.model.DataModel#getWrappedData() Return the object
         *      representing the data wrapped by this DataModel, if any.
         */
        public Object getWrappedData() {
                // TODO Auto-generated method stub
                return null;
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.faces.model.DataModel#isRowAvailable()
         * 
         * Return a flag indicating whether there is rowData available at the
         * current rowIndex. If no wrappedData is available, return false.
         * 
         */
        public boolean isRowAvailable() {
                return getRowIndex() < getRowCount();
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.faces.model.DataModel#setRowIndex(int)
         * 
         * Set the zero-relative index of the currently selected row, or -1 to
         * indicate that we are not positioned on a row. It is possible to set 
the
         * row index at a value for which the underlying data collection does 
not
         * contain any row data. Therefore, callers may use the isRowAvailable()
         * method to detect whether row data will be available for use by the
         * getRowData() method. If there is no wrappedData available when this
         * method is called, the specified rowIndex is stored (and may be 
retrieved
         * by a subsequent call to getRowData()), but no event is sent. 
Otherwise,
         * if the currently selected row index is changed by this call, a
         * DataModelEvent will be sent to the rowSelected() method of all 
registered
         * DataModelListeners.
         */
        public void setRowIndex(int arg0) {
                _rowIndex = arg0;
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.faces.model.DataModel#setWrappedData(java.lang.Object)
         * 
         * Set the object representing the data collection wrapped by this
         * DataModel. If the specified data is null, detach this DataModel from 
any
         * previously wrapped data collection instead. If data is non-null, the
         * currently selected row index must be set to zero, and a 
DataModelEvent
         * must be sent to the rowSelected() method of all registered
         * DataModelListeners indicating that this row is now selected.
         */
        public void setWrappedData(Object arg0) {
                // TODO Auto-generated method stub
        }

        /**
         * sets a query delegate, use a cached one if wanted/needed
         * 
         * @param queryDelegate
         * @param useCached
         */
        public void setQueryDelegate(IDataAccessor queryDelegate, boolean 
useCached) {
                Object tmpQueryDelegate = null;
                if (useCached) {
                        tmpQueryDelegate = 
JSFUtil.getSessionMap().get(createQueryKey(queryDelegate));
                        if (tmpQueryDelegate == null) {
                                
JSFUtil.getSessionMap().put(createQueryKey(queryDelegate), queryDelegate);
                        } else {
                                queryDelegate = (IDataAccessor) 
tmpQueryDelegate;
                        }
                }
                setQueryDelegate(queryDelegate);
        }

        public IDataAccessor getQueryDelegate() {
                return _queryDelegate;
        }

        /**
         * @param queryDelegate
         * @return
         */
        private String createQueryKey(IDataAccessor queryDelegate) {
                return "QUERY" + this.getClass().getName() + 
queryDelegate.getClass().getName();
        }

        /**
         * query delegate setter
         * 
         * @param queryDelegate
         */
        public void setQueryDelegate(IDataAccessor queryDelegate) {
                _queryDelegate = queryDelegate;
                _queryDelegate.setDataModel(this);
        }

        /**
         * @param mode
         */
        public void setOrderMode(String mode) {
                _queryDelegate.setOrderMode(mode);
        }

        /**
         * returns an object from the page cache just to be sure
         * 
         * @param id
         * @return
         */
        public BaseDatabaseObject getPageObjectFromId(Integer id) {
                return (BaseDatabaseObject) _idCache.get(id);
        }

        /**
         * @return Returns the _cacheWindow.
         */
        public List get_cacheWindow() {
                return _cacheWindow;
        }

        /**
         * @param window
         *            The _cacheWindow to set.
         */
        public void set_cacheWindow(List window) {
                _cacheWindow = window;
        }
}
/*
 * Created on 01.12.2004
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package misc;

/**
 * @author Werner Punz MediaData
 *
 * Base database object which allows the object to be selected upon a given 
 * display
 */
public class BaseDatabaseObject {
        
        /**
         * this is true, if an operation has to be done upon it
         */
        boolean selectedForOperation = false;
        
        //m:n relational assigmend
        boolean assigned                         = false;
        
        //true if a query on this object is allowed
        boolean queryAllowed                     = true; 
        
        /**
         * this is currently not in use but will be used
         * later by combined form/lists
         */
        boolean isAltered = false;
        
        /** The composite primary key value. */
    private Integer id = 1;
        
        
        /**
         * @return Returns the selectedForOperation.
         */
        public boolean isSelectedForOperation() {
                return selectedForOperation;
        }
        /**
         * @param selectedForOperation The selectedForOperation to set.
         */
        public void setSelectedForOperation(boolean selectedForOperation) {
                this.selectedForOperation = selectedForOperation;
        }
        /**
         * @return Returns the isAltered.
         */
        public boolean isAltered() {
                return isAltered;
        }
        /**
         * @param isAltered The isAltered to set.
         */
        public void setAltered(boolean isAltered) {
                this.isAltered = isAltered;
        }
        /**
         * @return true if the object is relationally 
         * assigned to a parent
         */
        public boolean isAssigned() {
                return assigned;
        }
        /**
         * @param assigned 
         * internally used but public
         */
        public void setAssigned(boolean assigned) {
                this.assigned = assigned;
        }
        /**
         * @return Returns the id.
         */
        public Integer getId() {
                return id;
        }
        /**
         * @param id The id to set.
         */
        public void setId(java.lang.Integer id) {
                this.id = id;
        }
        /**
         * @return Returns the queryAllowed.
         */
        public boolean isQueryAllowed() {
                return queryAllowed;
        }
        /**
         * @param queryAllowed The queryAllowed to set.
         */
        public void setQueryAllowed(boolean queryAllowed) {
                this.queryAllowed = queryAllowed;
        }
}
package jsf.codegen.model;

import jsf.model.HibernateDataModel;

/**
 * @author Media Data Code Generator    
 * Do not edit this file
 *
 * Standard Data model Class class
 */
public class DiffrecipientsDataModel extends HibernateDataModel {

        /**
         * 
         */
        public DiffrecipientsDataModel() {
                super();
                DiffrecipientsQuery query = new DiffrecipientsQuery();
                super.setQueryDelegate(query, true);
                super.refillCache();
        }

}
/*
 * Created on 05.01.2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package jsf.model;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.model.DataModel;
import javax.servlet.http.HttpServletRequest;
import jsf.common.Constants;
import org.springframework.orm.hibernate.HibernateCallback;
import org.springframework.orm.hibernate.HibernateTemplate;
import misc.BaseDatabaseObject;
import misc.DatabaseHelpers;
import misc.JSFUtil;
import misc.NavigationBean;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;

/**
 * @author werpu
 * 
 * TODO To change the template for this generated type comment go to Window -
 * Preferences - Java - Code Style - Code Templates
 */
public abstract class BaseDataAccessor implements IDataAccessor {

        DataModel                       _dataModel      = null;
        /**
         * reference to a possible parent object
         */
        BaseDatabaseObject      _parent         = null;

        /*
         * (non-Javadoc)
         * 
         * @see jsf.model.IDataAccessor#getOrderMode()
         */
        public String getOrderMode() {
                // TODO Auto-generated method stub
                return null;
        }

        /**
         * 
         */
        public BaseDataAccessor() {
                super();
                // TODO Auto-generated constructor stub
        }

        /*
         * (non-Javadoc)
         * 
         * @see jsf.model.IDataAccessor#queryDatasets(int, int)
         */
        public List queryDatasets(final int from,final int pageSize) {
                HibernateTemplate template = new 
HibernateTemplate((SessionFactory) DatabaseHelpers.getHibernateService());
                List retVal = (List) template.execute(new HibernateCallback() {
                        // let Spring do the transaction handling for this case
                        public Object doInHibernate(Session sess) throws 
HibernateException {
                                

                try {
                        // DateHolder data = (DateHolder)
                        // JSFUtil.getManagedBean("calendar");
                        Integer pageCount = (Integer) 
JSFUtil.getManagedBean("pagecount");
                        HttpServletRequest request = JSFUtil.getRequest();
                        // String pagePos = request.getParameter("pagePos");
                        NavigationBean navBean = (NavigationBean) 
JSFUtil.getManagedBean("navBean");
                        
                        Integer size = new Integer(0);
                        try {
                                size = (Integer) 
(sess.iterate(getQueryString(sess, "", "", true))).next();
                        } catch (HibernateException ex) {
                                System.out.println(ex.toString());
                                // no datasets found unfortunately an exception 
is thrown in
                                // this case
                                return new LinkedList();
                        }
                        // setMaxElements(size.intValue());
                        ((HibernateDataModel) 
_dataModel).setRowCount(size.intValue());
                        Query query = createQuery(sess, "", "", false);
                        
                        //Iterator i = query.iterate();
                        query.setMaxResults(pageSize);
                        query.setFirstResult(from);
                        return query.list();
                        
                } catch (HibernateException e) {
                        JSFUtil.addMessage(FacesMessage.SEVERITY_ERROR, 
"Interner Fehler", e.getMessage());
                        throw e;
                } finally {
                }
        }
});
                if(retVal != null)
                        return retVal;
                return new ArrayList();
        }

        /*
         * (non-Javadoc)
         * 
         * @see jsf.model.IDataAccessor#getDataModel()
         */
        public DataModel getDataModel() {
                return _dataModel;
        }

        /*
         * (non-Javadoc)
         * 
         * @see 
jsf.model.IDataAccessor#setDataModel(javax.faces.model.DataModel)
         */
        public void setDataModel(DataModel model) {
                _dataModel = model;
        }

        protected abstract Query createQuery(Session sess, String from, String 
to, boolean count) throws HibernateException;

        protected abstract String getQueryString(Session ses, String from, 
String to, boolean count);

        public abstract void setOrderMode(String mode);

        /**
         * @return Returns the parent.
         */
        public BaseDatabaseObject getParent() {
                return _parent;
        }

        /**
         * @param parent
         *            The parent to set.
         */
        public void setParent(BaseDatabaseObject parent) {
                this._parent = parent;
        }
}
package jsf.codegen.model;

import jsf.model.BaseDataAccessor;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;

import util.Util;

/**
 * @author Media Data Code Generator    
 * Do not edit this file
 * <pre>
 * Standard Query delegator class
 * which is used as delegate by the corresponding
 * data model class
 *
 *
 * Note this class currently neither currently really
 * handles soft updates nor is the spring framework
 * for better binding error and transaction control
 * integrated yet
 * all this stuff will be added in a 2.0 version
 * of the generator
 *</pre>
 */
 public class DiffrecipientsQuery extends BaseDataAccessor {
    String queryString = "";
    String orderMode = "id";

                                                java.lang.String _searchVname = 
new java.lang.String();
                                                java.lang.String _searchNname = 
new java.lang.String();
                                                java.lang.String _searchEmail = 
new java.lang.String();

    /**
     *
     */
    public DiffrecipientsQuery() {
        super();

        // TODO Auto-generated constructor stub
    }

    /**
     * gets a query String
     * to change the query behavior override this method
     * in an inherited class
     */
    protected String getQueryString(Session ses, String from, String to,
        boolean count) {
        StringBuffer queryBuf = new StringBuffer(60);

        if (count) {
            queryBuf.append("select count(*) ");
        }

        queryBuf.append("from Diffrecipients as tes where 1=1 ");
                //not currently implemented
                //do a like on a field
                queryBuf.append(" and tes.vname like '");
                queryBuf.append(getVname());
                queryBuf.append("%'"); 
                //do a like on a field
                queryBuf.append(" and tes.nname like '");
                queryBuf.append(getNname());
                queryBuf.append("%'"); 
                //do a like on a field
                queryBuf.append(" and tes.email like '");
                queryBuf.append(getEmail());
                queryBuf.append("%'"); 
                //n:1 relation to the id in the query
                if(getParent() != null) {
                        queryBuf.append(" and tes.");
                        queryBuf.append("Diffsysnotificator".toLowerCase());    
                        
                        queryBuf.append("=");
                        queryBuf.append(getParent().getId());
                }       

        if (!Util.isEmpty(getOrderMode()) && !count) {
            queryBuf.append(" order by tes.");
            queryBuf.append(getOrderMode());
            queryBuf.append(" asc ");
        }

        return queryBuf.toString();
    }

    /**
     * creates the query upon the given form parameters
     * @param sess
     * @param from
     * @param to
     * @return
     * @throws HibernateException
     */
    protected Query createQuery(Session sess, String from, String to,
        boolean count) throws HibernateException {
        String queryStr = getQueryString(sess, from, to, count);
        Query query = sess.createQuery(queryStr);

        return query;
    }

    /**
     * @return Returns the queryString.
     */
    public String getQueryString() {
        return queryString;
    }

    /**
     * @param queryString The queryString to set.
     */
    public void setQueryString(String queryString) {
        this.queryString = queryString;
    }

    /**
     * @return Returns the orderMode.
     */
    public String getOrderMode() {
        return orderMode;
    }

    /**
     * @param orderMode The orderMode to set.
     */
    public void setOrderMode(String orderMode) {
        this.orderMode = orderMode;
    }
   //search part getters and setters
                                /**
                                 * setter for _searchVname
                                 * @param val the new value for _searchVname
                                 */     
                                public void setVname(java.lang.String val) {
                                        _searchVname = val;
                                }

                                /**
                                 * getter for _searchVname
                                 *
                                 */     
                                public java.lang.String getVname() {
                                        return _searchVname;
                                }
                                /**
                                 * setter for _searchNname
                                 * @param val the new value for _searchNname
                                 */     
                                public void setNname(java.lang.String val) {
                                        _searchNname = val;
                                }

                                /**
                                 * getter for _searchNname
                                 *
                                 */     
                                public java.lang.String getNname() {
                                        return _searchNname;
                                }
                                /**
                                 * setter for _searchEmail
                                 * @param val the new value for _searchEmail
                                 */     
                                public void setEmail(java.lang.String val) {
                                        _searchEmail = val;
                                }

                                /**
                                 * getter for _searchEmail
                                 *
                                 */     
                                public java.lang.String getEmail() {
                                        return _searchEmail;
                                }
}

Reply via email to