Save This Page
Home » Groovy-1.7.0 » org.codehaus.groovy.grails.orm » hibernate » cfg » [javadoc | source]
    1   /* Copyright 2004-2005 Graeme Rocher
    2    *
    3    * Licensed under the Apache License, Version 2.0 (the "License");
    4    * you may not use this file except in compliance with the License.
    5    * You may obtain a copy of the License at
    6    *
    7    *      http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    * Unless required by applicable law or agreed to in writing, software
   10    * distributed under the License is distributed on an "AS IS" BASIS,
   11    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    * See the License for the specific language governing permissions and
   13    * limitations under the License.
   14    */
   15   package org.codehaus.groovy.grails.orm.hibernate.cfg;
   16   
   17   import groovy.lang.GroovyObject;
   18   import groovy.lang.GroovySystem;
   19   import groovy.lang.MetaClass;
   20   import org.apache.commons.beanutils.PropertyUtils;
   21   import org.apache.commons.lang.StringUtils;
   22   import org.apache.commons.logging.Log;
   23   import org.apache.commons.logging.LogFactory;
   24   import org.codehaus.groovy.grails.commons;
   25   import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateDomainClass;
   26   import org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistProxyFactory;
   27   import org.hibernate;
   28   import org.hibernate.criterion.Order;
   29   import org.hibernate.engine.EntityEntry;
   30   import org.hibernate.engine.SessionImplementor;
   31   import org.hibernate.engine.Status;
   32   import org.hibernate.mapping.PersistentClass;
   33   import org.hibernate.mapping.Property;
   34   import org.hibernate.metadata.ClassMetadata;
   35   import org.hibernate.property.Getter;
   36   import org.hibernate.property.Setter;
   37   import org.hibernate.proxy.HibernateProxy;
   38   import org.hibernate.proxy.LazyInitializer;
   39   import org.hibernate.type.AbstractComponentType;
   40   import org.springframework.beans.SimpleTypeConverter;
   41   import org.springframework.orm.hibernate3.HibernateCallback;
   42   import org.springframework.orm.hibernate3.HibernateTemplate;
   43   
   44   import java.lang.reflect.InvocationTargetException;
   45   import java.lang.reflect.Modifier;
   46   import java.sql.SQLException;
   47   import java.util.HashMap;
   48   import java.util.HashSet;
   49   import java.util.Map;
   50   import java.util.Set;
   51   
   52   /**
   53    * A class containing utility methods for configuring Hibernate inside Grails
   54    *
   55    * @author Graeme Rocher
   56    * @since 0.4
   57    *        <p/>
   58    *        Created: Jan 19, 2007
   59    *        Time: 6:21:01 PM
   60    */
   61   public class GrailsHibernateUtil {
   62       private static final Log LOG = LogFactory.getLog(GrailsHibernateUtil.class);
   63       public static SimpleTypeConverter converter = new SimpleTypeConverter();
   64       public static final String ARGUMENT_MAX = "max";
   65       public static final String ARGUMENT_OFFSET = "offset";
   66       public static final String ARGUMENT_ORDER = "order";
   67       public static final String ARGUMENT_SORT = "sort";
   68       public static final String ORDER_DESC = "desc";
   69       public static final String ORDER_ASC = "asc";
   70       public static final String ARGUMENT_FETCH = "fetch";
   71       public static final String ARGUMENT_IGNORE_CASE = "ignoreCase";
   72       public static final String ARGUMENT_CACHE = "cache";
   73       public static final String ARGUMENT_LOCK = "lock";
   74       public static final String CONFIG_PROPERTY_CACHE_QUERIES="grails.hibernate.cache.queries";
   75       public static final Class[] EMPTY_CLASS_ARRAY=new Class[0];
   76   
   77   
   78       public static void configureHibernateDomainClasses(SessionFactory sessionFactory, GrailsApplication application) {
   79           Map hibernateDomainClassMap = new HashMap();
   80           for (Object o : sessionFactory.getAllClassMetadata().values()) {
   81               ClassMetadata classMetadata = (ClassMetadata) o;
   82               configureDomainClass(sessionFactory, application, classMetadata, classMetadata.getMappedClass(EntityMode.POJO), hibernateDomainClassMap);
   83           }
   84           configureInheritanceMappings(hibernateDomainClassMap);
   85       }
   86   
   87       public static void configureInheritanceMappings(Map hibernateDomainClassMap) {
   88           // now get through all domainclasses, and add all subclasses to root class
   89           for (Object o : hibernateDomainClassMap.values()) {
   90               GrailsDomainClass baseClass = (GrailsDomainClass) o;
   91               if (!baseClass.isRoot()) {
   92                   Class superClass = baseClass
   93                           .getClazz().getSuperclass();
   94   
   95   
   96                   while (!superClass.equals(Object.class) && !superClass.equals(GroovyObject.class)) {
   97                       GrailsDomainClass gdc = (GrailsDomainClass) hibernateDomainClassMap.get(superClass.getName());
   98   
   99                       if (gdc == null || gdc.getSubClasses() == null) {
  100                           LOG.debug("did not find superclass names when mapping inheritance....");
  101                           break;
  102                       }
  103                       gdc.getSubClasses().add(baseClass);
  104                       superClass = superClass.getSuperclass();
  105                   }
  106               }
  107           }
  108       }
  109   
  110       private static void configureDomainClass(SessionFactory sessionFactory, GrailsApplication application, ClassMetadata cmd, Class persistentClass, Map hibernateDomainClassMap) {
  111           if (!Modifier.isAbstract(persistentClass.getModifiers())) {
  112               LOG.trace("Configuring domain class [" + persistentClass + "]");
  113               GrailsDomainClass dc = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE, persistentClass.getName());
  114               if (dc == null) {
  115                   // a patch to add inheritance to this system
  116                   GrailsHibernateDomainClass ghdc = new
  117                           GrailsHibernateDomainClass(persistentClass, sessionFactory, cmd);
  118   
  119                   hibernateDomainClassMap.put(persistentClass.getName(),
  120                           ghdc);
  121   
  122                   dc = (GrailsDomainClass) application.addArtefact(DomainClassArtefactHandler.TYPE, ghdc);
  123               }
  124           }
  125       }
  126   
  127       public static void populateArgumentsForCriteria(Class targetClass, Criteria c, Map argMap) {
  128          Integer maxParam = null;
  129           Integer offsetParam = null;
  130           if(argMap.containsKey(ARGUMENT_MAX)) {
  131               maxParam = (Integer)converter.convertIfNecessary(argMap.get(ARGUMENT_MAX),Integer.class);
  132           }
  133           if(argMap.containsKey(ARGUMENT_OFFSET)) {
  134               offsetParam = (Integer)converter.convertIfNecessary(argMap.get(ARGUMENT_OFFSET),Integer.class);
  135           }
  136           String orderParam = (String)argMap.get(ARGUMENT_ORDER);
  137           Object fetchObj = argMap.get(ARGUMENT_FETCH);
  138           if(fetchObj instanceof Map) {
  139               Map fetch = (Map)fetchObj;
  140               for (Object o : fetch.keySet()) {
  141                   String associationName = (String) o;
  142                   c.setFetchMode(associationName, getFetchMode(fetch.get(associationName)));
  143               }
  144           }
  145   
  146           final String sort = (String)argMap.get(ARGUMENT_SORT);
  147           final String order = ORDER_DESC.equalsIgnoreCase(orderParam) ? ORDER_DESC : ORDER_ASC;
  148           final int max = maxParam == null ? -1 : maxParam;
  149           final int offset = offsetParam == null ? -1 : offsetParam;
  150           if(max > -1)
  151               c.setMaxResults(max);
  152           if(offset > -1)
  153               c.setFirstResult(offset);
  154           if(GrailsClassUtils.getBooleanFromMap(ARGUMENT_CACHE, argMap)) {
  155               c.setCacheable(true);
  156           }
  157           if(GrailsClassUtils.getBooleanFromMap(ARGUMENT_LOCK, argMap)) {
  158               c.setLockMode(LockMode.UPGRADE);
  159           }
  160           else {
  161               if(argMap.get(ARGUMENT_CACHE) == null) {
  162                   cacheCriteriaByMapping(targetClass, c);
  163               }
  164           }
  165           if(sort != null) {
  166               boolean ignoreCase = true;
  167               Object caseArg = argMap.get(ARGUMENT_IGNORE_CASE);
  168               if(caseArg instanceof Boolean) {
  169                   ignoreCase = (Boolean) caseArg;
  170               }
  171               if(ORDER_DESC.equals(order)) {
  172                   c.addOrder( ignoreCase ? Order.desc(sort).ignoreCase() : Order.desc(sort));
  173               }
  174               else {
  175                   c.addOrder( ignoreCase ? Order.asc(sort).ignoreCase() : Order.asc(sort) );
  176               }
  177           }
  178           else {
  179               Mapping m = GrailsDomainBinder.getMapping(targetClass);
  180               if(m!=null&&!StringUtils.isBlank(m.getSort())) {
  181                   if(ORDER_DESC.equalsIgnoreCase(m.getOrder())) {
  182                       c.addOrder(Order.desc(m.getSort()));
  183                   }
  184                   else {
  185                       c.addOrder(Order.asc(m.getSort()));
  186                   }
  187               }
  188           }
  189   
  190       }
  191   
  192       /**
  193        * Configures the criteria instance to cache based on the configured mapping
  194        *
  195        * @param targetClass The target class
  196        * @param criteria The criteria
  197        */
  198       public static void cacheCriteriaByMapping(Class targetClass, Criteria criteria) {
  199           Mapping m = GrailsDomainBinder.getMapping(targetClass);
  200           if(m!=null && m.getCache()!=null) {
  201               if(m.getCache().getEnabled()) {
  202                   criteria.setCacheable(true);
  203               }
  204           }
  205       }
  206   
  207       public static void populateArgumentsForCriteria(Criteria c, Map argMap) {
  208           populateArgumentsForCriteria(null,c, argMap);
  209       }
  210   
  211       /**
  212   	 * Will retrieve the fetch mode for the specified instance other wise return the
  213        * default FetchMode
  214        *
  215        * @param object The object, converted to a string
  216        * @return The FetchMode
  217        */
  218       public static FetchMode getFetchMode(Object object) {
  219           String name = object != null ? object.toString() : "default";
  220           if(name.equalsIgnoreCase(FetchMode.JOIN.toString()) || name.equalsIgnoreCase("eager")) {
  221               return FetchMode.JOIN;
  222           }
  223           else if(name.equalsIgnoreCase(FetchMode.SELECT.toString()) || name.equalsIgnoreCase("lazy")) {
  224               return FetchMode.SELECT;
  225           }
  226           return FetchMode.DEFAULT;
  227       }
  228   
  229       /**
  230        * Sets the target object to read-only using the given SessionFactory instance. This
  231        * avoids Hibernate performing any dirty checking on the object
  232        *
  233        * @see #setObjectToReadWrite(Object, org.hibernate.SessionFactory)
  234        *
  235        * @param target The target object
  236        * @param sessionFactory The SessionFactory instance
  237        */
  238       public static void setObjectToReadyOnly(Object target, SessionFactory sessionFactory) {
  239           Session session = sessionFactory.getCurrentSession();
  240           if(canModifyReadWriteState(session, target)) {
  241                if(target instanceof HibernateProxy) {
  242                    target = ((HibernateProxy)target).getHibernateLazyInitializer().getImplementation();
  243                }
  244                session.setReadOnly(target, true);
  245                session.setFlushMode(FlushMode.MANUAL);
  246           }
  247       }
  248   
  249       private static boolean canModifyReadWriteState(Session session, Object target) {
  250           return session.contains(target) && Hibernate.isInitialized(target);
  251       }
  252   
  253       /**
  254        * Sets the target object to read-write, allowing Hibernate to dirty check it and auto-flush
  255        * changes
  256        *
  257        * @see #setObjectToReadyOnly(Object, org.hibernate.SessionFactory)
  258        *
  259        * @param target The target object
  260        * @param sessionFactory The SessionFactory instance
  261        */
  262       public static void setObjectToReadWrite(final Object target, SessionFactory sessionFactory) {
  263           HibernateTemplate template = new HibernateTemplate(sessionFactory);
  264           template.setExposeNativeSession(true);
  265           template.execute(new HibernateCallback() {
  266   
  267               public Object doInHibernate(Session session) throws HibernateException, SQLException {
  268                   if(canModifyReadWriteState(session, target)) {
  269                       SessionImplementor sessionImpl = (SessionImplementor) session;
  270                       EntityEntry ee = sessionImpl.getPersistenceContext().getEntry(target);
  271   
  272                       if(ee != null && ee.getStatus() == Status.READ_ONLY) {
  273                           Object actualTarget = target;
  274                           if(target instanceof HibernateProxy) {
  275                               actualTarget = ((HibernateProxy)target).getHibernateLazyInitializer().getImplementation();
  276                           }
  277   
  278                           session.setReadOnly(actualTarget, false);
  279                           session.setFlushMode(FlushMode.AUTO);
  280                           incrementVersion(target);
  281                       }
  282                   }
  283                   return null;
  284   
  285               }
  286           });
  287   
  288       }
  289   
  290       /**
  291        * Increments the entities version number in order to force an update
  292        * @param target The target entity
  293        */
  294       public static void incrementVersion(Object target) {
  295           MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass());
  296           if(metaClass.hasProperty(target, GrailsDomainClassProperty.VERSION)!=null) {
  297               Object version = metaClass.getProperty(target, GrailsDomainClassProperty.VERSION);
  298               if(version instanceof Long) {
  299                   Long newVersion = (Long) version + 1;
  300                   metaClass.setProperty(target, GrailsDomainClassProperty.VERSION, newVersion);
  301               }
  302           }
  303       }
  304   
  305       /**
  306        * Unwraps and initializes a HibernateProxy
  307        * @param proxy The proxy
  308        */
  309       public static Object unwrapProxy(HibernateProxy proxy) {
  310           LazyInitializer lazyInitializer = proxy.getHibernateLazyInitializer();
  311           if(lazyInitializer.isUninitialized()) {
  312               lazyInitializer.initialize();
  313           }
  314           return lazyInitializer.getImplementation();
  315       }
  316   
  317   
  318       /**
  319        * Returns the proxy for a given association or null if it is not proxied
  320        *
  321        * @param obj The object
  322        * @param associationName The named assoication
  323        * @return A proxy
  324        */
  325       public static HibernateProxy getAssociationProxy(Object obj, String associationName) {
  326           try {
  327               Object proxy = PropertyUtils.getProperty(obj, associationName);
  328               if(proxy instanceof HibernateProxy) return (HibernateProxy) proxy;
  329               else return null;
  330           }
  331           catch (IllegalAccessException e) {
  332               return null;
  333           }
  334           catch (InvocationTargetException e) {
  335               return null;
  336           }
  337           catch (NoSuchMethodException e) {
  338               return null;
  339           }
  340       }
  341   
  342       /**
  343        * Checks whether an associated property is initialized and returns true if it is
  344        *
  345        * @param obj The name of the object
  346        * @param associationName The name of the association
  347        * @return True if is initialized
  348        */
  349       public static boolean isInitialized(Object obj, String associationName) {
  350           try {
  351               Object proxy = PropertyUtils.getProperty(obj, associationName);
  352               return Hibernate.isInitialized(proxy);
  353           }
  354           catch (IllegalAccessException e) {
  355               return false;
  356           }
  357           catch (InvocationTargetException e) {
  358               return false;
  359           }
  360           catch (NoSuchMethodException e) {
  361               return false;
  362           }
  363       }
  364   
  365       public static boolean isCacheQueriesByDefault() {
  366           Object o = ConfigurationHolder.getFlatConfig().get(CONFIG_PROPERTY_CACHE_QUERIES);
  367           return (o != null && o instanceof Boolean)?((Boolean)o).booleanValue():false;
  368       }
  369   
  370       public static GroovyAwareJavassistProxyFactory buildProxyFactory(PersistentClass persistentClass) {
  371           GroovyAwareJavassistProxyFactory proxyFactory = new GroovyAwareJavassistProxyFactory();
  372   
  373   
  374           Set<Class> proxyInterfaces = new HashSet<Class>() {{
  375               add(HibernateProxy.class);
  376             }
  377           };
  378   
  379   
  380           final Class javaClass = persistentClass.getMappedClass();
  381           final Property identifierProperty = persistentClass.getIdentifierProperty();
  382           final Getter idGetter = identifierProperty!=null?  identifierProperty.getGetter(javaClass) : null;
  383           final Setter idSetter =identifierProperty!=null? identifierProperty.getSetter(javaClass) : null;
  384   
  385           if(idGetter == null ||  idSetter==null) return null;
  386           try {
  387               proxyFactory.postInstantiate(persistentClass.getEntityName(),
  388                                       javaClass,
  389                                        proxyInterfaces,
  390                                        idGetter.getMethod(),
  391                                        idSetter.getMethod(),
  392                                        persistentClass.hasEmbeddedIdentifier() ?
  393                                                    (AbstractComponentType) persistentClass.getIdentifier().getType() :
  394                                                           null
  395                                               );
  396           }
  397           catch (HibernateException e) {
  398   
  399               LOG.warn("Cannot instantiate proxy factory: " + e.getMessage());
  400               return null;
  401           }
  402   
  403           return proxyFactory;
  404       }
  405   }

Save This Page
Home » Groovy-1.7.0 » org.codehaus.groovy.grails.orm » hibernate » cfg » [javadoc | source]