View Javadoc

1   package org.weda.hibernate;
2   
3   import java.io.FileInputStream;
4   import java.io.IOException;
5   import java.io.InputStream;
6   import java.io.Serializable;
7   import java.sql.Blob;
8   import java.sql.Connection;
9   import java.sql.DatabaseMetaData;
10  import java.sql.Savepoint;
11  import java.util.ArrayList;
12  import java.util.Collection;
13  import java.util.HashMap;
14  import java.util.Iterator;
15  import java.util.List;
16  import java.util.Map;
17  import java.util.Properties;
18  import java.util.Set;
19  import javax.servlet.ServletContext;
20  import org.apache.commons.lang.ObjectUtils;
21  import org.apache.commons.logging.Log;
22  import org.hibernate.EntityMode;
23  import org.hibernate.Hibernate;
24  import org.hibernate.HibernateException;
25  import org.hibernate.LockMode;
26  import org.hibernate.Session;
27  import org.hibernate.SessionFactory;
28  import org.hibernate.StaleStateException;
29  import org.hibernate.Transaction;
30  import org.hibernate.cfg.AnnotationConfiguration;
31  import org.hibernate.event.PostDeleteEvent;
32  import org.hibernate.event.PostDeleteEventListener;
33  import org.hibernate.event.PostInsertEvent;
34  import org.hibernate.event.PostInsertEventListener;
35  import org.hibernate.event.PostUpdateEvent;
36  import org.hibernate.event.PostUpdateEventListener;
37  import org.hibernate.event.PreInsertEvent;
38  import org.hibernate.event.PreUpdateEvent;
39  import org.hibernate.event.PreUpdateEventListener;
40  import org.hibernate.metadata.ClassMetadata;
41  import org.hibernate.persister.entity.EntityPersister;
42  import org.weda.converter.ValueTypeConverter;
43  import org.weda.domain.ObjectModification;
44  import org.weda.domain.ObjectModificationPk;
45  import org.weda.domain.ObjectModificationType;
46  import org.weda.domain.PropertyModification;
47  import org.weda.property.ObjectDescriptorRegistry;
48  import org.weda.property.PropertyGetOperationListener;
49  import org.weda.property.PropertyListenerException;
50  import org.weda.property.PropertyListenerResult;
51  import org.weda.property.PropertyValue;
52  import org.weda.property.PropertyValueException;
53  import org.weda.store.AuditOperation;
54  import org.weda.store.AuditRuntimeException;
55  import org.weda.store.Auditable;
56  import org.weda.store.AuditableObjectRegistry;
57  import org.weda.store.ObjectStoreException;
58  import org.weda.store.Query;
59  import org.weda.store.QueryFilterElement;
60  import org.weda.cache.CacheManager;
61  import org.weda.store.ObjectSource;
62  import org.weda.store.ObjectStore;
63  import org.weda.store.QueryFilterElement.ExpressionType;
64  import org.weda.store.QueryFilterElement.OperatorType;
65  
66  
67  /**
68   *
69   * @author tim
70   */
71  public class HibernateObjectStore 
72          implements 
73              ObjectStore, PropertyGetOperationListener
74              , PostInsertEventListener, PreUpdateEventListener
75              , PostDeleteEventListener
76  {
77      private final static String ID = 
78              HibernateObjectStore.class.getName();
79      private final static String PARAM_PREFIX="param";
80      private final static long LOCK_TIMEOUT = 10000;
81      
82      private AuditableObjectRegistry auditReg;
83      private ValueTypeConverter converter;
84      private ObjectDescriptorRegistry descriptorRegistry;
85      
86      private SessionFactory sessionFactory;
87      private AnnotationConfiguration config;
88      private Log log;
89      private CacheManager cacheManager;
90      private ServletContext servletContext;
91      private PropertyValue propertyValue;
92      private Map<String, PropertyMapping[]> propertyMappings;
93      private ThreadLocal<List> auditObjectsToSave = 
94              new ThreadLocal<List>(){
95                  protected List initialValue() {
96                      return new ArrayList();
97                  }                
98              };
99      private boolean autoCommit = true;
100 
101             
102     /** Creates a new instance of HibernateProvider */
103     public HibernateObjectStore() {
104         config = new AnnotationConfiguration();
105     }
106     
107     public void init() throws ObjectStoreException {
108         try{
109 //            initAudit();
110             sessionFactory=config.buildSessionFactory();
111             for (Object obj: sessionFactory.getAllClassMetadata().values()){
112                 ClassMetadata classMeta = (ClassMetadata)obj;
113                 if (classMeta.hasProxy()){
114                     Class entityClass = 
115                             classMeta.getMappedClass(EntityMode.POJO);
116                     boolean[] lazyProps = classMeta.getPropertyLaziness();
117                     for (int i=0; i<lazyProps.length; i++)
118                         if (lazyProps[i]){
119                             propertyValue.addGetOperationListener(
120                                     entityClass
121                                     , classMeta.getPropertyNames()[i]
122                                     , this);
123                         }
124                 }
125             }
126         }catch(PropertyValueException e){
127             throw new ObjectStoreException(
128                     "Can't initialize persistent service", e);
129         }
130     }
131     
132     private void initAudit() {
133         for (AuditOperation operation: AuditOperation.values()){
134             Set<Class> auditableClasses = 
135                     auditReg.getAuditaleObjectsClasses(operation);            
136             if      (operation == AuditOperation.ADD)
137                 config.getEventListeners().setPostInsertEventListeners(
138                         new PostInsertEventListener[]{this});
139             else if (operation == AuditOperation.UPDATE)
140                 config.getEventListeners().setPreUpdateEventListeners(
141                         new PreUpdateEventListener[]{this});
142             else if (operation == AuditOperation.REMOVE)
143                 config.getEventListeners().setPostDeleteEventListeners(
144                         new PostDeleteEventListener[]{this});
145         }
146     }
147     
148     public void setLog(Log log){
149         this.log=log;
150     }
151     
152     public void setConfiguration(String path){
153         config.configure(path);
154     }
155     
156     public void setConfig(List<Class> classes) throws Exception {
157         for (Class entityClass: classes) 
158             config.addAnnotatedClass(entityClass);
159     }
160     
161     public void setServletContext(List<ServletContext> list){
162         servletContext = list.get(0);
163     }
164     
165     public void setProperties(Map<String, String> locations) throws Exception {
166         String path=null;
167         String pathType=null;
168         for (Map.Entry entry: locations.entrySet()){
169             path=(String)entry.getKey();
170             pathType=(String)entry.getValue();
171         }
172         log.debug("seting properties. path: "+path+", pathType: "+pathType);
173         if (     "file".equals(pathType))
174             loadPropertiesFromFile(path);
175         else if ("resource".equals(pathType))
176             loadPropertiesFromResource(path);
177         else if ("web-resource".equals(pathType))
178             loadPropertiesFromServletContext(path);
179     }
180     
181     private void loadPropertiesFromFile(String path) throws Exception {
182         InputStream is = new FileInputStream(path);
183         loadPropertiesFromStream(is);
184     }
185     
186     private void loadPropertiesFromResource(String path) throws Exception{
187         InputStream is = 
188                 this.getClass().getClassLoader().getResourceAsStream(path);
189         loadPropertiesFromStream(is);
190     }
191     
192     private void loadPropertiesFromServletContext(String path) throws Exception{
193         InputStream is=servletContext.getResourceAsStream(path);
194         loadPropertiesFromStream(is);
195     }
196     
197     private void loadPropertiesFromStream(InputStream is) throws Exception{
198         try{
199             Properties props = new Properties();
200             props.load(is);
201             config.addProperties(props);
202         }finally{
203             is.close();
204         }
205     }
206     
207     public void save(Object obj) throws ObjectStoreException {
208         if (log.isDebugEnabled())
209             log.debug(obj);
210         try{
211             beginTransaction();
212             Session sess = getSession();
213             saveObjectState(obj);
214             sess.saveOrUpdate(obj);
215             if (auditObjectsToSave.get().size()>0){
216                 for (Object auditObj: auditObjectsToSave.get())
217                     sess.saveOrUpdate(auditObj);
218                 auditObjectsToSave.get().clear();
219             }
220             commit();
221         }catch(Exception e){            
222             rollback();
223             throw new ObjectStoreException(
224                 String.format(
225                     "Can't save object (%s) of class (%s)"
226                     , obj.toString(), obj.getClass().getName())
227                 , e);
228         }
229     }
230     
231     private void saveObjectState(Object obj){
232         Set<String> props = 
233                 auditReg.getAuditableObjectProperties(
234                     AuditOperation.UPDATE, obj.getClass());
235         if (props!=null){
236             
237         }
238         
239     }
240     
241     public Object load(Class clazz, Serializable id) 
242         throws ObjectStoreException 
243     {
244         Object res=null;
245         try{
246             beginTransaction();
247             Session sess = getSession();
248             res=sess.get(clazz, id);
249             commit();
250         }catch(Exception e){
251             rollback();
252             throw new ObjectStoreException(
253                 String.format(
254                     "Can't load object whith id (%s) of class (%s)"
255                     , id.toString(), clazz.getName())
256                 , e);
257         }
258         return res;
259     }
260     
261     public void refresh(Object obj) throws ObjectStoreException{
262         try{
263             beginTransaction();
264             Session session = getSession();
265             session.refresh(obj);
266             commit();
267         }catch(Exception e){
268             rollback();
269             throw new ObjectStoreException(
270                     "Can't refresh object state", e);
271         }
272     }
273     
274     public Serializable getObjectId(Object obj) throws ObjectStoreException {
275         try {
276             beginTransaction();
277             try{
278                 Session session = getSession();
279                 session.refresh(obj);
280                 return session.getIdentifier(obj);
281             }finally{
282                 commit();
283             }
284         } catch (Exception e) {
285             throw new ObjectStoreException(
286                     "Error getting object identificator", e);
287         }
288     }    
289     
290     protected HibernateCacheEntity getCacheEntity() 
291         throws ObjectStoreException
292     {
293         HibernateCacheEntity state=
294                 (HibernateCacheEntity)cacheManager.getCacheService().get(ID);
295         if (state==null){
296             state = new HibernateCacheEntity();
297             cacheManager.getCacheService().setCacheEntity(ID, state);
298         }
299         return state;
300     }
301     
302     protected Session getSession() throws ObjectStoreException {        
303         return getCacheEntity().getSession();
304     }
305     
306     public String toString(){
307         return "Hibernate persitent service";
308     }
309 
310     public CacheManager getCacheManager() {
311         return cacheManager;
312     }
313 
314     public void setCacheManager(CacheManager cacheManager) {
315         this.cacheManager = cacheManager;
316     }
317     
318     private void formQueryString (
319             StringBuffer queryString
320             , Map<String, Object> paramValues
321             , ParameterNameConstructor nameConstructor
322             , Collection<QueryFilterElement>... elementsList)
323     {
324         for (Collection<QueryFilterElement> elements: elementsList)
325             for (QueryFilterElement element: elements){
326                 if (!element.isEnabled() || element.getParameterName()!=null)
327                     continue;
328                 if (element.getExpressionType()!=ExpressionType.EMPTY){
329                     queryString.append("  AND "+element.getObjectAlias());
330                     if (!element.isUseAliasAsProperty())
331                         queryString.append("."+element.getProperty());
332                     if      (element.getExpressionType()
333                                 == ExpressionType.COMPLETE)
334                     {
335                         queryString.append(" "+element.getValue());
336                     }else if (element.getExpressionType()
337                                 == ExpressionType.OPERATOR)
338                     {                   
339                         OperatorType type = element.getOperatorType();
340                         if (   type==OperatorType.SIMPLE 
341                             || type==OperatorType.LIKE)
342                         {
343                             String paramName=nameConstructor.getNextName();
344                             String operator = 
345                                     type==OperatorType.LIKE? 
346                                         "LIKE":element.getOperator();
347                             queryString.append(" "+operator+" "+":"+paramName);
348                             paramValues.put(
349                                     paramName, element.getParameterValue());
350                         }else{
351                             Object[] vals = (Object[])element.getValue();
352                             if (type==OperatorType.BETWEEN){
353                                 String param1 = nameConstructor.getNextName();
354                                 String param2 = nameConstructor.getNextName();
355                                 queryString.append(
356                                     " BETWEEN "+":"+param1+" AND "+":"+param2);
357                                 paramValues.put(param1, vals[0]);
358                                 paramValues.put(param2, vals[1]);
359                             }else{
360                                 queryString.append(" IN (");
361                                 boolean firstVal = true;
362                                 for (Object val: vals){
363                                     String param = 
364                                             nameConstructor.getNextName();
365                                     if (firstVal)
366                                         firstVal = false;
367                                     else
368                                         queryString.append(',');
369                                     queryString.append(":"+param);
370                                     paramValues.put(param, val);
371                                 }
372                                 queryString.append(")");
373                             }
374                         }
375                     }
376                     queryString.append("\n");
377                 }
378             }
379     }
380     
381     private org.hibernate.Query constructQuery(ObjectSource dataSource) 
382         throws ObjectStoreException
383     {
384         org.hibernate.Query hquery=null;
385         try{
386             Query query = dataSource.getQuery();
387 
388             Map<String, Object> paramValues=new HashMap<String, Object>();
389             Collection<QueryFilterElement> staticElements=
390                 dataSource.getQueryFilter().getStaticFilterElements();
391             Collection<QueryFilterElement> elements=
392                 dataSource.getQueryFilter().getFilterElements();
393             
394             Map<String, Object> reservedParameters = 
395                     new HashMap<String, Object>();
396             extractReservedParameterNames(
397                     reservedParameters, staticElements, elements);
398 
399             StringBuffer whereClause = new StringBuffer();
400             ParameterNameConstructor nameConstructor = 
401                     new ParameterNameConstructor(reservedParameters.keySet());
402             formQueryString(
403                     whereClause, paramValues, nameConstructor
404                     , staticElements, elements);
405             String queryString = query.getQuery();
406             int insertMarkerPos = 
407                     queryString.indexOf(FILTER_INSERT_POSITION_MARKER);
408             if (insertMarkerPos>0) {
409                 queryString = 
410                         queryString.replace(
411                             FILTER_INSERT_POSITION_MARKER, whereClause);
412             }else
413                 queryString = queryString + "\nWHERE 1=1\n"+whereClause;
414             if (log.isDebugEnabled())
415                 log.debug("QUERY: "+queryString);
416             hquery=getSession().createQuery(queryString);
417             hquery.setMaxResults(query.getMaxRows());
418             hquery.setFetchSize(query.getFetchSize());
419             hquery.setTimeout(query.getTimeout());
420             setParameterValues(hquery, paramValues, reservedParameters);
421         }catch(HibernateException e){
422             throw new ObjectStoreException(String.format(
423                 "Can't construct select query for dataSource (%s)"
424                     , dataSource.getName())
425               , e);
426         }
427         return hquery;
428         
429     }
430     
431     private void extractReservedParameterNames(
432             Map<String, Object> reservedParameters
433             , Collection<QueryFilterElement>... elementsList)
434     {
435         for (Collection<QueryFilterElement> elements: elementsList)
436             for (QueryFilterElement element: elements)
437                 if (element.getParameterName()!=null)
438                     reservedParameters.put(
439                             element.getParameterName()
440                             , element.getParameterValue());
441     }
442     
443     private void setParameterValues(
444             org.hibernate.Query hquery, Map<String, Object>... valuesList)
445     {
446         for (Map<String, Object> paramValues: valuesList)
447             for (Map.Entry<String, Object> entry: paramValues.entrySet())
448                 hquery.setParameter(entry.getKey(), entry.getValue());
449     }
450     
451     public boolean isPropertyValueNull(Object obj, String propertyName) 
452         throws ObjectStoreException 
453     {
454         try{
455             beginTransaction();
456             String query = 
457                     "select count(*) from "+obj.getClass().getName()+" as obj "
458                     +"where obj = :param and "+propertyName+" is null";
459             org.hibernate.Query hquery = getSession().createQuery(query);
460             hquery.setParameter("param", obj);
461             int count = ((Number)hquery.list().get(0)).intValue();
462             return  count != 0;
463         }finally{
464             commit();
465         }
466     }
467     
468 
469     public List<Object[]> queryAllRows(ObjectSource dataSource) 
470         throws ObjectStoreException 
471     {
472         List<Object[]> res=null;
473         try{
474             beginTransaction();
475             Session session=getSession();
476             //session.clear();
477             org.hibernate.Query hquery=constructQuery(dataSource);
478             List rows=hquery.list();
479             if (rows.size()==0 || !(rows.get(0) instanceof Object[])){
480                 res=new ArrayList<Object[]>();
481                 for (Object obj: rows)
482                     res.add(new Object[]{obj});
483             }else
484                 res=(List<Object[]>)rows;
485         }finally{
486             commit();
487         }
488         return res;
489     }
490 
491     public Iterator query(ObjectSource dataSource) {
492         return null;
493     }
494 
495     public void delete(Object obj) throws ObjectStoreException {
496         beginTransaction();
497         try{
498             Session sess = getSession();
499             sess.delete(obj);
500             commit();
501         }catch(Exception e){
502             rollback();
503             throw new ObjectStoreException(
504                 String.format(
505                     "Can't delete object (%s) of class (%s)"
506                     , obj.toString(), obj.getClass().getName())
507                 , e);
508         }
509     }
510 
511     public void deleteAll(Class objectClass) throws ObjectStoreException{
512         try{
513             beginTransaction();
514             Session sess = getSession();
515             org.hibernate.Query query = 
516                 sess.createQuery("delete from "+objectClass.getName());
517             query.executeUpdate();
518             commit();
519         }catch(Exception e){
520             rollback();
521             throw new ObjectStoreException(
522                 String.format(
523                     "Can't delete all objects of class (%s)"
524                     , objectClass.getName())
525                 , e);
526         }
527     }
528 
529 //    public void rollback() throws PersistentServiceException {
530 //        try{
531 //            Transaction tx = getCacheEntity().getTransaction();
532 //            if (tx==null || !tx.isActive())
533 //                throw new PersistentServiceException(
534 //                    "Can't rollback transaction, because of no active " +
535 //                    "transaction");
536 //            tx.rollback();
537 //            getCacheEntity().setTransaction(null);
538 //        }catch(HibernateException e){
539 //            throw new PersistentServiceException(
540 //                "Can't rollback hibernate transaction", e);
541 //        }
542 //    }
543     
544     public void commit() throws ObjectStoreException, HibernateException{
545         endTransaction(true);
546     }
547 
548     public void rollback() 
549         throws ObjectStoreException, HibernateException
550     {
551         endTransaction(false);
552     }
553 
554     private void endTransaction(boolean commit) 
555         throws ObjectStoreException, HibernateException     
556     {
557         String operation = commit ? "commit" : "rollback";
558         HibernateCacheEntity sessionState = getCacheEntity();
559         try{
560             int callCounter = sessionState.getCallCounter();
561             if (callCounter==1){
562                 Transaction tx = getCacheEntity().getSession().getTransaction();
563                 if (tx==null || !tx.isActive()){
564                     sessionState.setEndTransactionError(true);
565                     throw new ObjectStoreException(
566                         String.format(
567                             "Can't %s transaction, because of no active " +
568                             "transaction"
569                             , operation));
570                 }
571                 if (commit)
572                     tx.commit();
573                 else
574                     tx.rollback();
575                 if (log.isDebugEnabled())
576                     log.debug("Transaction " + operation + " operation done");
577                 reset();
578             }else if (callCounter>1){
579                 sessionState.setCallCounter(callCounter-1);
580                 sessionState.setEndTransactionError(false);
581                 if (sessionState.isSupportsSavepoint()){
582                     Connection con = sessionState.getSession().connection();
583                     Savepoint savepoint = sessionState.getSavepoints().pop();
584                     if (commit){
585                         if (sessionState.isSupportsReleaseSavepoint())
586                             con.releaseSavepoint(savepoint);
587                     }else
588                         con.rollback(savepoint);
589                 }
590                 
591             }else
592                 throw new ObjectStoreException(
593                     String.format(
594                         "Can't %s transaction, because of no active " +
595                         "transaction"
596                         , operation));
597         }catch(Exception e){
598             sessionState.setEndTransactionError(true);
599             if (e instanceof StaleStateException)
600                 throw (StaleStateException)e;
601             throw new ObjectStoreException(
602                 String.format("Can't %s hibernate transaction", operation)
603                 , e);
604         }
605     }
606 
607     public void beginTransaction() throws ObjectStoreException{
608         try{
609             HibernateCacheEntity sessionState = getCacheEntity();
610             int callCounter = sessionState.getCallCounter();
611             Session session = sessionState.getSession();
612             if (callCounter == 0){
613                 session = sessionFactory.openSession();
614                 session.beginTransaction();
615                 sessionState.setSession(session);
616                 DatabaseMetaData meta = session.connection().getMetaData();
617                 sessionState.setSupportsSavepoint(meta.supportsSavepoints());
618                 sessionState.setSupportsReleaseSavepoint(
619                         !"Oracle".equals(meta.getDatabaseProductName()));
620                 if (log.isWarnEnabled() && !sessionState.isSupportsSavepoint())
621                     log.warn("Database not supports savepoints");
622                 if (log.isDebugEnabled())
623                     log.debug("Transaction started");
624             }
625             if (!sessionState.isEndTransactionError()){
626                 if (callCounter!=0 && sessionState.isSupportsSavepoint())
627                     sessionState.getSavepoints().push(
628                             session.connection().setSavepoint());
629                 sessionState.setCallCounter(callCounter+1);
630             }
631         }catch(Exception e){
632             throw new ObjectStoreException(
633                 "Can't start hibernate transaction", e);
634         }
635     }
636     
637     private void showTransactionStatus() throws ObjectStoreException {
638         if (log.isDebugEnabled()){
639             HibernateCacheEntity sessionState = getCacheEntity();
640             Session session = sessionState.getSession();
641             //if (session == )
642         }
643     }
644 
645 //    public boolean isTransactionActive() 
646 //        throws HibernateException, PersistentServiceException 
647 //    {
648 //        Transaction tx = getCacheEntity().getTransaction();
649 //        return tx!=null && tx.isActive();
650 //    }
651 
652     public boolean isAutoCommit() {
653         return autoCommit;
654     }
655 
656     public void setAutoCommit(boolean autoCommit) {
657         this.autoCommit = autoCommit;
658     }
659 
660     public void reset() {
661         cacheManager.getCacheService().release(ID);
662     }
663 
664 //    public void lock(Object obj) throws PersistentServiceException {
665 //        try{
666 //            Session session = getSession();
667 //            org.hibernate.Query query = session.createQuery(
668 //                    "from "+obj.getClass().getName()+" as obj "+
669 //                    "where obj = ?");
670 //            query.setLockMode("obj", LockMode.UPGRADE_NOWAIT);
671 //            query.setTimeout(10);
672 //            query.setParameter(0, obj);
673 //            query.list();
674 //        }catch(Exception e){
675 //            if (!(e instanceof PersistentServiceException))
676 //                throw new PersistentServiceException(
677 //                    "Object locked for update by other session", e);                
678 //            else throw (PersistentServiceException)e;
679 //        }
680 //    }
681         
682     public void lock(Object obj) throws ObjectStoreException {
683         try{
684             Session session = getSession();
685             LockerThread locker = new LockerThread(session, obj);
686             locker.start();
687             locker.join(LOCK_TIMEOUT);
688             boolean lockError = false;
689             if (locker.isAlive()){
690                 session.cancelQuery();
691                 locker.join();
692                 lockError = true;
693             }
694             if (locker.getException()!=null)
695                 throw locker.getException();
696             if (locker.isInterrupted())
697                 lockError = true;
698             if (lockError)
699                 throw new ObjectStoreException(
700                     "Object locked for update by other session");                
701         }catch(Exception e){
702             if (!(e instanceof ObjectStoreException))
703                 throw new ObjectStoreException(
704                     "Object locked for update by other session", e);                
705             else throw (ObjectStoreException)e;
706         }
707     }
708 
709     public void flushUpdates() throws ObjectStoreException {
710         try{
711             getSession().flush();
712         }catch(HibernateException e){
713             throw new ObjectStoreException(
714                     "Can't flush the session updates", e);
715         }
716     }
717 
718     private class LockerThread extends Thread {
719         private Session session;
720         private Object object;
721         private HibernateException exception;
722 
723         public LockerThread(Session session, Object obj){
724             this.session = session;
725             this.object = obj;
726         }
727         
728 //        public void run(){
729 //            try{
730 //                session.lock(object, LockMode.UPGRADE_NOWAIT);
731 //            }catch(HibernateException e){
732 //                exception = e;
733 //            }
734 //        }
735         public void run() {
736             try{
737                 session.refresh(object, LockMode.UPGRADE_NOWAIT);
738 //                session.evict(object);
739 //                org.hibernate.Query query = session.createQuery(
740 //                        "from "+object.getClass().getName()+" as obj "+
741 //                        "where obj = ?");
742 //                query.setLockMode("obj", LockMode.UPGRADE_NOWAIT);
743 //                //query.setTimeout(10);
744 //                query.setParameter(0, object);
745 //                List<Object> rows = (List<Object>)query.list();
746 //                session.evict(rows.get(0));
747             }catch(HibernateException e){
748                 exception = e;
749             }            
750         }
751 
752         public HibernateException getException() {
753             return exception;
754         }
755     }
756 
757     public void setPropertyValue(PropertyValue propertyValue) {
758         this.propertyValue = propertyValue;
759     }
760 
761     public PropertyListenerResult beforeGet(Object propOwner, String propName) 
762         throws PropertyListenerException 
763     {
764         try{
765             beginTransaction();
766             refresh(propOwner);
767             return null;
768         }catch(ObjectStoreException e){
769             throw new PropertyListenerException("", e);            
770         }
771     }
772 
773     public PropertyListenerResult afterGet(
774             Object propOwner, String propName, Object propValue) 
775         throws PropertyListenerException 
776     {
777         try{
778             commit();
779             return null;
780         }catch(ObjectStoreException e){
781             throw new PropertyListenerException("", e);
782         }
783     }
784 
785     public Blob createBlob(InputStream inStream) throws ObjectStoreException {
786         try {
787             return Hibernate.createBlob(inStream);
788         } catch (IOException ex) {
789             throw new ObjectStoreException("Error while creating BLOB", ex);
790         }
791     }
792 
793     public void onPostInsert(PostInsertEvent event) {
794         try{
795             Set<String> props = 
796                     auditReg.getAuditableObjectProperties(
797                         AuditOperation.ADD, event.getEntity().getClass());
798             if (props!=null){
799                 ObjectModificationType objModType = 
800                         getObjectModificationType(
801                             AuditOperation.ADD, event.getEntity());
802                 PropertyMapping[] mappings = 
803                         getPropertiesMapping(
804                             props
805                             , AuditOperation.ADD
806                             , event.getPersister()
807                             , event.getEntity().getClass());
808                 for (int i=0; i<mappings.length; ++i){
809                     String value = 
810                             (String)converter.convert(
811                                 String.class
812                                 , event.getState()[
813                                     mappings[i].positionInPersistor]
814                                 , mappings[i].pattern);
815                     PropertyModification propMod = 
816                             new PropertyModification(
817                                 objModType
818                                 , mappings[i].propertyName
819                                 , value);
820                     auditObjectsToSave.get().add(propMod);
821                 }
822             }
823         }catch(Exception e){
824             throw new AuditRuntimeException(
825                     "Error while processing audit operation", e);
826         }
827     }
828     
829     public void onPostDelete(PostDeleteEvent event) {
830         try{
831             Set<String> props = 
832                     auditReg.getAuditableObjectProperties(
833                         AuditOperation.REMOVE, event.getEntity().getClass());
834             if (props!=null){
835                 ObjectModificationType objModType = 
836                         getObjectModificationType(
837                             AuditOperation.REMOVE, event.getEntity());
838                 PropertyMapping[] mappings = 
839                         getPropertiesMapping(
840                             props
841                             , AuditOperation.REMOVE
842                             , event.getPersister()
843                             , event.getEntity().getClass());
844                 for (int i=0; i<mappings.length; ++i){
845                     String value = 
846                             (String)converter.convert(
847                                 String.class
848                                 , event.getDeletedState()[
849                                     mappings[i].positionInPersistor]
850                                 , mappings[i].pattern);
851                     PropertyModification propMod = 
852                             new PropertyModification(
853                                 objModType
854                                 , mappings[i].propertyName
855                                 , value);
856                     auditObjectsToSave.get().add(propMod);
857                 }
858             }
859         }catch(Exception e){
860             throw new AuditRuntimeException(
861                     "Error while processing audit operation", e);
862         }
863     }
864 
865     public boolean onPreUpdate(PreUpdateEvent event) {
866         try{
867             Set<String> props = 
868                     auditReg.getAuditableObjectProperties(
869                         AuditOperation.UPDATE, event.getEntity().getClass());
870             if (props!=null){
871                 ObjectModificationType objModType = 
872                         getObjectModificationType(
873                             AuditOperation.UPDATE, event.getEntity());
874                 PropertyMapping[] mappings = 
875                         getPropertiesMapping(
876                             props
877                             , AuditOperation.UPDATE
878                             , event.getPersister()
879                             , event.getEntity().getClass());
880                 for (int i=0; i<mappings.length; ++i){
881                     int entityPos = mappings[i].positionInPersistor;
882                     if (!ObjectUtils.equals(
883                             event.getState()[entityPos]
884                             , event.getOldState()[entityPos]))
885                     {
886                         String value = 
887                                 (String)converter.convert(
888                                     String.class
889                                     , event.getState()[entityPos]
890                                     , mappings[i].pattern);
891                         PropertyModification propMod = 
892                                 new PropertyModification(
893                                     objModType
894                                     , mappings[i].propertyName
895                                     , value);
896                         auditObjectsToSave.get().add(propMod);
897                     }
898                 }
899             }
900             return true;
901         }catch(Exception e){
902             throw new AuditRuntimeException(
903                     "Error while processing audit operation", e);
904         }
905     }
906 
907     
908     private ObjectModificationType getObjectModificationType(
909             AuditOperation operation, Object entity) throws Exception
910     {
911         Auditable audObj = (Auditable)entity;
912         ObjectModificationPk pk = 
913                 new ObjectModificationPk(
914                     audObj.getId(), audObj.getClass().getName());
915         ObjectModification objMod = 
916                 (ObjectModification)load(ObjectModification.class, pk);
917         boolean newObjMod=objMod==null;
918         if (objMod==null){
919             objMod = new ObjectModification(pk);
920             auditObjectsToSave.get().add(objMod);
921         }
922         ObjectModificationType objModType = 
923                 new ObjectModificationType(objMod, operation);
924         auditObjectsToSave.get().add(objModType);
925         return objModType;
926     }
927     
928     private synchronized PropertyMapping[] getPropertiesMapping(
929             Set<String> props
930             , AuditOperation operation
931             , EntityPersister persister
932             , Class entityClass)
933         throws Exception
934     {
935         if (propertyMappings==null)
936             propertyMappings = new HashMap<String, PropertyMapping[]>();
937         String id = entityClass.getName()+"."+operation;
938         PropertyMapping[] mappings = propertyMappings.get(id);
939         if (mappings==null){
940             int i=0;
941             mappings = new PropertyMapping[props.size()];
942             String[] entityPropertyNames = persister.getPropertyNames();
943             for (String propertyName: props)
944                 for (int j=0; j<entityPropertyNames.length; ++j)
945                     if (propertyName.equals(entityPropertyNames[j])){
946                         PropertyMapping mapping = new PropertyMapping();
947                         mapping.propertyName=propertyName;
948                         mapping.positionInPersistor=j;
949                         mapping.pattern=
950                                 descriptorRegistry.getPropertyDescriptor(
951                                     entityClass, propertyName).getPattern();
952                         mappings[i++]=mapping;
953                         break;
954                     }
955             propertyMappings.put(id, mappings);
956         }
957         return mappings;
958     }
959 
960     public void setAuditReg(AuditableObjectRegistry auditReg) {
961         this.auditReg = auditReg;
962     }
963     
964     public void setConverter(ValueTypeConverter converter) {
965         this.converter = converter;
966     }
967 
968     public void setDescriptorRegistry(ObjectDescriptorRegistry descriptorRegistry) {
969         this.descriptorRegistry = descriptorRegistry;
970     }
971 
972     private static class ParameterNameConstructor {
973         private Set<String> reservedNames;
974         private int parameterNumber = 1;
975         
976         public ParameterNameConstructor(Set<String> reservedNames){
977             this.reservedNames = reservedNames;
978         }
979         
980         public String getNextName(){
981             String nextName=null;
982             do{
983                 nextName = PARAM_PREFIX+(parameterNumber++);
984             }while (reservedNames.contains(nextName));
985             return nextName;
986         }
987     }
988     
989     private static class PropertyMapping {
990         public String propertyName;
991         public int positionInPersistor;
992         public String pattern;
993     }
994 
995 }