Coverage Report - org.trails.hibernate.HibernatePersistenceServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
HibernatePersistenceServiceImpl
83% 
94% 
0
 
 1  1
 /*
 2  
  * Copyright 2004 Chris Nelson
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 7  
  * Unless required by applicable law or agreed to in writing,
 8  
  * software distributed under the License is distributed on an "AS IS" BASIS,
 9  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 10  
  * See the License for the specific language governing permissions and limitations under the License.
 11  
  */
 12  
 package org.trails.hibernate;
 13  
 
 14  
 import java.io.Serializable;
 15  
 import java.sql.SQLException;
 16  
 import java.util.ArrayList;
 17  
 import java.util.Collection;
 18  
 import java.util.List;
 19  
 
 20  
 import ognl.Ognl;
 21  
 import ognl.OgnlException;
 22  
 import org.hibernate.Criteria;
 23  
 import org.hibernate.EntityMode;
 24  
 import org.hibernate.HibernateException;
 25  
 import org.hibernate.LockMode;
 26  
 import org.hibernate.Session;
 27  
 import org.hibernate.TransientObjectException;
 28  
 import org.hibernate.criterion.CriteriaSpecification;
 29  
 import org.hibernate.criterion.DetachedCriteria;
 30  
 import org.hibernate.criterion.Expression;
 31  
 import org.hibernate.criterion.MatchMode;
 32  
 import org.hibernate.criterion.Projections;
 33  
 import org.hibernate.criterion.Restrictions;
 34  
 import org.hibernate.metadata.ClassMetadata;
 35  
 import org.springframework.beans.BeansException;
 36  
 import org.springframework.context.ApplicationContext;
 37  
 import org.springframework.context.ApplicationContextAware;
 38  
 import org.springframework.dao.DataAccessException;
 39  
 import org.springframework.orm.hibernate3.HibernateCallback;
 40  
 import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
 41  
 import org.springframework.transaction.annotation.Transactional;
 42  
 import org.trails.component.Utils;
 43  
 import org.trails.descriptor.CollectionDescriptor;
 44  
 import org.trails.descriptor.DescriptorService;
 45  
 import org.trails.descriptor.IClassDescriptor;
 46  
 import org.trails.descriptor.IPropertyDescriptor;
 47  
 import org.trails.persistence.HibernatePersistenceService;
 48  
 import org.trails.persistence.PersistenceException;
 49  
 import org.trails.validation.ValidationException;
 50  
 
 51  24
 public class HibernatePersistenceServiceImpl extends HibernateDaoSupport implements
 52  
         HibernatePersistenceService, ApplicationContextAware
 53  
 {
 54  
 
 55  12
         ApplicationContext appContext = null;
 56  12
         private DescriptorService _descriptorService = null;
 57  
 
 58  
         /**
 59  
          * We need this because cylcic reference between HibernatePersistenceServiceImpl and TrailsDescriptorService
 60  
          */
 61  
         public DescriptorService getDescriptorService()
 62  
         {
 63  37
                 if (_descriptorService == null)
 64  
                 {
 65  2
                         _descriptorService = (DescriptorService) appContext.getBean("descriptorService");
 66  
                 }
 67  37
                 return _descriptorService;
 68  
         }
 69  
 
 70  
         @Transactional
 71  
         public <T> T getInstance(final Class<T> type, DetachedCriteria detachedCriteria) {
 72  9
                 final DetachedCriteria criteria = alterCriteria(type, detachedCriteria);
 73  
                 
 74  9
                 return (T) getHibernateTemplate().execute(new HibernateCallback()
 75  
                 {
 76  
                         public Object doInHibernate(Session session) throws HibernateException, SQLException
 77  
                         {
 78  9
                                 return criteria.getExecutableCriteria(session).uniqueResult();
 79  
                         }
 80  
                 });
 81  
         }
 82  
 
 83  
         /**
 84  
          * (non-Javadoc)
 85  
          *
 86  
          * @see org.trails.persistence.PersistenceService#getInstance(Class,Serializable)
 87  
          */
 88  
         @Transactional
 89  
         public <T> T getInstance(final Class<T> type, final Serializable id)
 90  
         {
 91  5
                 DetachedCriteria criteria = DetachedCriteria.forClass(Utils.checkForCGLIB(type)).add(Expression.idEq(id));
 92  5
                 return getInstance(type, criteria);
 93  
         }
 94  
 
 95  
         public <T> T loadInstance(final Class<T> type, Serializable id)
 96  
         {
 97  0
                 return (T) getHibernateTemplate().load(type, id);
 98  
         }
 99  
         
 100  
         public List find(String queryString) {
 101  0
                 return getHibernateTemplate().find(queryString);
 102  
         }
 103  
         public List find(String queryString, Object value) {
 104  11
                 return getHibernateTemplate().find(queryString, value);
 105  
         }
 106  
         public List find(String queryString, Object[] values) {
 107  2
                 return getHibernateTemplate().find(queryString, values);
 108  
         }
 109  
 
 110  
         
 111  
         /*
 112  
                  * (non-Javadoc)
 113  
                  *
 114  
                  * @see org.blah.service.IPersistenceService#getAllInstances(java.lang.Class)
 115  
                  */
 116  
         @Transactional
 117  
         public <T> List<T> getAllInstances(final Class<T> type)
 118  
         {
 119  1
                 DetachedCriteria criteria = DetachedCriteria.forClass(Utils.checkForCGLIB(type));
 120  1
                 return getInstances(type, criteria);
 121  
         }
 122  
 
 123  
         public <T> List<T> getInstances(final Class<T> type, int startIndex, int maxResults)
 124  
         {
 125  0
                 return getInstances(type, DetachedCriteria.forClass(type), startIndex, maxResults);
 126  
         }
 127  
 
 128  
         /*
 129  
                  * (non-Javadoc)
 130  
                  *
 131  
                  * @see org.blah.service.IPersistenceService#save(java.lang.Object)
 132  
                  */
 133  
         @Transactional
 134  
         public <T> T save(T instance) throws ValidationException
 135  
         {
 136  
                 try
 137  
                 {
 138  29
                         IClassDescriptor iClassDescriptor = getDescriptorService().getClassDescriptor(instance.getClass());
 139  
                         /* check isTransient to avoid merging on entities not persisted yet. TRAILS-33 */
 140  29
                         if (!iClassDescriptor.getHasCyclicRelationships() || isTransient(instance, iClassDescriptor))
 141  
                         {
 142  21
                                 getHibernateTemplate().saveOrUpdate(instance);
 143  
                         } else
 144  
                         {
 145  8
                                 instance = (T) getHibernateTemplate().merge(instance);
 146  
                         }
 147  28
                         return instance;
 148  
                 }
 149  1
                 catch (DataAccessException dex)
 150  
                 {
 151  1
                         throw new PersistenceException(dex);
 152  
                 }
 153  
         }
 154  
 
 155  
         @Transactional
 156  
         public void removeAll(Collection collection)
 157  
         {
 158  0
                 getHibernateTemplate().deleteAll(collection);
 159  0
         }
 160  
 
 161  
         @Transactional
 162  
         public void remove(Object instance)
 163  
         {
 164  
                 // merge first to avoid NonUniqueObjectException
 165  1
                 getHibernateTemplate().delete(getHibernateTemplate().merge(instance));
 166  1
         }
 167  
 
 168  
         @Transactional
 169  
         public <T> List<T> getInstances(Class<T> type, DetachedCriteria criteria) {
 170  4
                 criteria = alterCriteria(type, criteria);
 171  4
                 criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
 172  4
                 return getHibernateTemplate().findByCriteria(criteria);
 173  
         }
 174  
         
 175  
         public List<Class> getAllTypes()
 176  
         {
 177  13
                 ArrayList<Class> allTypes = new ArrayList<Class>();
 178  169
                 for (Object classMetadata : getSessionFactory().getAllClassMetadata().values())
 179  
                 {
 180  143
                         allTypes.add(((ClassMetadata) classMetadata).getMappedClass(EntityMode.POJO));
 181  
                 }
 182  13
                 return allTypes;
 183  
         }
 184  
 
 185  
         @Transactional
 186  
         public void reattach(Object model)
 187  
         {
 188  0
                 getSession().lock(model, LockMode.NONE);
 189  0
         }
 190  
 
 191  
 
 192  
         /**
 193  
          * (non-Javadoc)
 194  
          *
 195  
          * @see org.trails.persistence.PersistenceService#getInstance(Class<T>)
 196  
          */
 197  
         @Transactional
 198  
         public <T> T getInstance(final Class<T> type)
 199  
         {
 200  0
                 return (T) getInstance(type, DetachedCriteria.forClass(type));
 201  
         }
 202  
 
 203  
         public Serializable getIdentifier(final Object data, final IClassDescriptor classDescriptor)
 204  
         {
 205  
                 try
 206  
                 {
 207  
                         /** This is only until I figure out where are the Callbacks persisting its properties **/
 208  
 
 209  11
                         return (Serializable) Ognl.getValue(classDescriptor.getIdentifierDescriptor().getName(), data);
 210  
 
 211  0
                 } catch (OgnlException e)
 212  
                 {
 213  0
                         return null;
 214  
                 }
 215  
         }
 216  
 
 217  
 
 218  
         private Serializable getIdentifier(final Object data)
 219  
         {
 220  0
                 return (Serializable) getHibernateTemplate().execute(new HibernateCallback()
 221  
                 {
 222  
                         public Object doInHibernate(Session session) throws HibernateException, SQLException
 223  
                         {
 224  0
                                 return session.getIdentifier(data);
 225  
                         }
 226  
                 });
 227  
         }
 228  
 
 229  
         public boolean isTransient(Object data, IClassDescriptor classDescriptor)
 230  
         {
 231  
                 try
 232  
                 {
 233  9
                         return getIdentifier(data, classDescriptor) == null;
 234  0
                 } catch (TransientObjectException e)
 235  
                 {
 236  0
                         return true;
 237  
                 }
 238  
         }
 239  
 
 240  
         @Transactional
 241  
         public List getInstances(final Object example, final IClassDescriptor classDescriptor)
 242  
         {
 243  14
                 return (List) getHibernateTemplate().execute(new HibernateCallback()
 244  
                 {
 245  
                         public Object doInHibernate(Session session) throws HibernateException, SQLException
 246  
                         {
 247  
                                 //create Criteria instance
 248  7
                                 DetachedCriteria searchCriteria = DetachedCriteria.forClass(Utils.checkForCGLIB(example.getClass()));
 249  7
                                 searchCriteria = alterCriteria(example.getClass(), searchCriteria);
 250  
 
 251  
                                 //loop over the example object's PropertyDescriptors
 252  65
                                 for (IPropertyDescriptor propertyDescriptor : classDescriptor.getPropertyDescriptors())
 253  
                                 {
 254  
                                         //only add a Criterion to the Criteria instance if this property is searchable
 255  51
                                         if (propertyDescriptor.isSearchable())
 256  
                                         {
 257  38
                                                 String propertyName = propertyDescriptor.getName();
 258  38
                                                 Class propertyClass = propertyDescriptor.getPropertyType();
 259  38
                                                 Object value = null;
 260  
                                                 try
 261  
                                                 {
 262  38
                                                         value = Ognl.getValue(propertyName, example);
 263  0
                                                 } catch (OgnlException e)
 264  
                                                 { /* do nothing! */ }
 265  
 
 266  
                                                 //only add a Criterion to the Criteria instance if the value for this property is non-null
 267  38
                                                 if (value != null)
 268  
                                                 {
 269  17
                                                         if (String.class.isAssignableFrom(propertyClass) && ((String) value).length() > 0)
 270  
                                                         {
 271  6
                                                                 searchCriteria
 272  6
                                                                         .add(Restrictions.like(propertyName, value.toString(), MatchMode.ANYWHERE));
 273  
                                                         }
 274  
                                                         /**
 275  
                                                          * 'one'-end of many-to-one, one-to-one
 276  
                                                          *
 277  
                                                          * Just match the identifier
 278  
                                                          */
 279  11
                                                         else if (propertyDescriptor.isObjectReference())
 280  
                                                         {
 281  6
                                                                 Serializable identifierValue = getIdentifier(value,
 282  2
                                                                         getDescriptorService().getClassDescriptor(propertyDescriptor.getBeanType()));
 283  2
                                                                 searchCriteria.createCriteria(propertyName).add(Restrictions.idEq(identifierValue));
 284  9
                                                         } else if (propertyClass.isPrimitive())
 285  
                                                         {
 286  
                                                                 //primitive types: ignore zeroes in case of numeric types, ignore booleans anyway (TODO come up with something...)
 287  3
                                                                 if (!propertyClass.equals(boolean.class) && ((Number) value).longValue() != 0)
 288  
                                                                 {
 289  0
                                                                         searchCriteria.add(Restrictions.eq(propertyName, value));
 290  
                                                                 }
 291  6
                                                         } else if (propertyDescriptor.isCollection())
 292  
                                                         {
 293  
                                                                 //one-to-many or many-to-many
 294  6
                                                                 CollectionDescriptor collectionDescriptor =
 295  6
                                                                         (CollectionDescriptor) propertyDescriptor;
 296  6
                                                                 IClassDescriptor classDescriptor = getDescriptorService().getClassDescriptor(collectionDescriptor.getElementType());
 297  6
                                                                 String identifierName = classDescriptor.getIdentifierDescriptor().getName();
 298  6
                                                                 Collection<Serializable> identifierValues = new ArrayList<Serializable>();
 299  6
                                                                 Collection associatedItems = (Collection) value;
 300  6
                                                                 if (associatedItems != null && associatedItems.size() > 0)
 301  
                                                                 {
 302  0
                                                                         for (Object o : associatedItems)
 303  
                                                                         {
 304  0
                                                                                 identifierValues.add(getIdentifier(o, classDescriptor));
 305  
                                                                         }
 306  
                                                                         //add a 'value IN collection' restriction
 307  0
                                                                         searchCriteria.createCriteria(propertyName)
 308  0
                                                                                 .add(Restrictions.in(identifierName, identifierValues));
 309  
                                                                 }
 310  
                                                         }
 311  
                                                 }
 312  
                                         }
 313  
                                 }
 314  7
                                 searchCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
 315  7
                                 return searchCriteria.getExecutableCriteria(session).list();
 316  
                         }
 317  7
                 }, true);
 318  
         }
 319  
 
 320  
 
 321  
         public void setApplicationContext(ApplicationContext arg0) throws BeansException
 322  
         {
 323  12
                 this.appContext = arg0;
 324  
 
 325  12
         }
 326  
 
 327  
 
 328  
         public int count(Class type, DetachedCriteria detachedCriteria)
 329  
         {
 330  
                 // todo hacking useNative is a result of SPR-2499 and will be removed soon
 331  1
                 boolean useNative = getHibernateTemplate().isExposeNativeSession();
 332  1
                 getHibernateTemplate().setExposeNativeSession(true);
 333  1
                 detachedCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
 334  1
                 final DetachedCriteria criteria = alterCriteria(type, detachedCriteria);
 335  1
                 Integer result = (Integer) getHibernateTemplate().execute(new HibernateCallback()
 336  
                 {
 337  
                         public Object doInHibernate(Session session) throws HibernateException, SQLException
 338  
                         {
 339  1
                                 Criteria executableCriteria =
 340  1
                                         criteria.getExecutableCriteria(session).setProjection(Projections.rowCount());
 341  1
                                 return executableCriteria.uniqueResult();
 342  
                         }
 343  
                 });
 344  1
                 getHibernateTemplate().setExposeNativeSession(useNative);
 345  1
                 return result;
 346  
         }
 347  
 
 348  
         public <T> List<T> getInstances(Class<T> type, final DetachedCriteria detachedCriteria, final int startIndex, final int maxResults)
 349  
         {
 350  1
                 return getInstances(alterCriteria(type, detachedCriteria), startIndex, maxResults);
 351  
                 
 352  
         }
 353  
         
 354  
         
 355  
         public List getInstances(final DetachedCriteria detachedCriteria, final int startIndex, final int maxResults)
 356  
         {
 357  1
                 detachedCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
 358  
                 // todo hacking useNative is a result of SPR-2499 and will be removed soon
 359  1
                 boolean useNative = getHibernateTemplate().isExposeNativeSession();
 360  1
                 getHibernateTemplate().setExposeNativeSession(true);
 361  1
                 List result = (List) getHibernateTemplate().execute(new HibernateCallback()
 362  
                 {
 363  
                         public Object doInHibernate(Session session) throws HibernateException, SQLException
 364  
                         {
 365  1
                                 Criteria executableCriteria = detachedCriteria.getExecutableCriteria(session);
 366  1
                                 if (startIndex >= 0)
 367  
                                 {
 368  1
                                         executableCriteria.setFirstResult(startIndex);
 369  
                                 }
 370  1
                                 if (maxResults > 0)
 371  
                                 {
 372  1
                                         executableCriteria.setMaxResults(maxResults);
 373  
                                 }
 374  1
                                 return executableCriteria.list();
 375  
                         }
 376  
                 });
 377  1
                 getHibernateTemplate().setExposeNativeSession(useNative);
 378  1
                 return result;
 379  
         }
 380  
 
 381  
         /**
 382  
          * This hook allows subclasses to modify the query criteria, such as for security
 383  
          *
 384  
          * @param detachedCriteria The original Criteria query
 385  
          * @return The modified Criteria query for execution
 386  
          */
 387  
         protected DetachedCriteria alterCriteria(Class type, DetachedCriteria detachedCriteria)
 388  
         {
 389  22
                 return detachedCriteria;
 390  
         }
 391  
 
 392  
         /**
 393  
          * @see org.trails.persistence.HibernatePersistenceService#saveOrUpdate(java.lang.Object)
 394  
          */
 395  
         @Transactional
 396  
         public <T> T merge(T instance)
 397  
         {
 398  
                 try
 399  
                 {
 400  2
                         return (T) getHibernateTemplate().merge(instance);
 401  
                 }
 402  1
                 catch (DataAccessException dex)
 403  
                 {
 404  1
                         throw new PersistenceException(dex);
 405  
                 }
 406  
         }
 407  
 
 408  
         /**
 409  
          * @see org.trails.persistence.HibernatePersistenceService#saveOrUpdate(java.lang.Object)
 410  
          */
 411  
         @Transactional
 412  
         public <T> T saveOrUpdate(T instance) throws ValidationException
 413  
         {
 414  
                 try
 415  
                 {
 416  8
                         getHibernateTemplate().saveOrUpdate(instance);
 417  7
                         return instance;
 418  
                 }
 419  1
                 catch (DataAccessException dex)
 420  
                 {
 421  1
                         throw new PersistenceException(dex);
 422  
                 }
 423  
         }
 424  
 }