package gr.ntua.ivml.mint.db; import gr.ntua.ivml.mint.persistent.Lock; import gr.ntua.ivml.mint.persistent.Lockable; import gr.ntua.ivml.mint.persistent.User; import java.io.PrintWriter; import java.io.StringWriter; import java.util.List; import org.apache.log4j.Logger; import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.StatelessSession; import org.hibernate.Transaction; import org.hibernate.criterion.Example; public class LockManager { static final Logger log = Logger.getLogger( LockManager.class ); static { // on load remove all logs long count = -1; StatelessSession s = DB.getStatelessSession(); Transaction tx = s.beginTransaction(); try { count = s.createQuery( "delete Lock") .executeUpdate(); tx.commit(); log.debug( "Removed " + count + " stale locks." ); } catch( HibernateException he ) { log.error( "locks not released" ); tx.rollback(); } finally { DB.closeStatelessSession(); } } public StatelessSession getSession() { return DB.getStatelessSession(); } /** * Like aquire lock only returns the lock, practical if you want to unlock after delete. * @param u * @param sessionId * @param item * @return */ public Lock directLock( User u, String sessionId, Lockable item ) { Lock result = null; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); if(( item==null ) || ( item.getDbID() == null)) throw new Error( "Unlockable item"); try { Lock lock = createLock(item); lock.setUserLogin(u.getLogin()); lock.setHttpSessionId(sessionId); log.debug( "Aquire Lock\n" + lock.toString()); List<Lock> l = s.createQuery("from Lock where objectId = :id and objectType = :type") .setLong("id", lock.getObjectId()) .setString("type", lock.getObjectType()) .list(); if( l.size() == 0 ) { s.insert(lock); tx.commit(); result = lock; } else { Lock lock2 = l.get(0); if( lock2.getUserLogin().equals(lock.getUserLogin()) && lock2.getHttpSessionId().equals(lock.getHttpSessionId()) ) result = l.get( 0 ); else result = null; tx.commit(); } } catch( HibernateException he ) { log.debug( "lock aquire failed" ); StringWriter sw = new StringWriter(); he.printStackTrace( new PrintWriter( sw )); log.error( sw.toString()); tx.rollback(); } return result; } /** * Aquire lock for given item or check that you still have it. * This should be done before database objects are updated, not just * before they are made persistent. It should not be done * (Cannot be done) with objects that don't have a dbID yet. * @param u * @param sessionId * @param item * @return */ public boolean aquireLock( User u, String sessionId, Lockable item ) { boolean result = false; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); if(( item==null ) || ( item.getDbID() == null)) throw new Error( "Unlockable item"); try { Lock lock = createLock(item); lock.setUserLogin(u.getLogin()); lock.setHttpSessionId(sessionId); log.debug( "Aquire Lock\n" + lock.toString()); List<Lock> l = s.createQuery("from Lock where objectId = :id and objectType = :type") .setLong("id", lock.getObjectId()) .setString("type", lock.getObjectType()) .list(); if( l.size() == 0 ) { s.insert(lock); tx.commit(); result = true; } else { Lock lock2 = l.get(0); if( lock2.getUserLogin().equals(lock.getUserLogin()) && lock2.getHttpSessionId().equals(lock.getHttpSessionId()) ) result = true; else result = false; tx.commit(); } } catch( HibernateException he ) { log.debug( "lock aquire failed" ); StringWriter sw = new StringWriter(); he.printStackTrace( new PrintWriter( sw )); log.error( sw.toString()); tx.rollback(); } return result; } /** * Releases the lock on the item (only for given user and session). * Returns false if the lock didn't exist (or was owned by somebody else) * @param u * @param sessionId * @param item * @return */ public boolean releaseLock( User u, String sessionId, Lockable item ) { boolean result = false; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); try { Lock example = createLock( item ); example.setHttpSessionId(sessionId); example.setUserLogin(u.getLogin()); Lock lock = (Lock) s.createCriteria(Lock.class) .add( Example.create( example ).excludeProperty("name")) .uniqueResult(); s.delete(lock); tx.commit(); result = true; } catch( HibernateException he ) { log.debug( "lock not released" ); tx.rollback(); } return result; } /** * Releases the lock. * That should always work if the lock exists. * @param u * @param sessionId * @param item * @return */ public boolean releaseLock( Lock lock ) { boolean result = false; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); try { s.delete(lock); tx.commit(); result = true; } catch( HibernateException he ) { log.debug( "lock not released" ); tx.rollback(); } return result; } /** * Release all locks for given session. * Give back how many. * @param sessionId */ public int releaseLocks( String sessionId ){ int count = -1; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); try { count = s.createQuery( "delete Lock where httpSessionId=:session") .setString( "session", sessionId) .executeUpdate(); tx.commit(); } catch( HibernateException he ) { log.debug( "locks not released" ); tx.rollback(); } return count; } /** * Need to find a specific lock. * @param dbID * @return */ public Lock getByDbID( Long dbID ) { Lock result = null; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); try { result = (Lock) s.createQuery("from Lock where dbID = :id") .setLong("id", dbID) .uniqueResult(); } catch( Exception e ) { log.error( "Cant retreive lock.", e ); tx.rollback(); } return result; } /** * Check if the item is locked. Return the Lock to check since when, what User etc. * Return null if there is no lock. * @param item * @return */ public Lock isLocked( Lockable item ) { Lock result = null; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); try { Lock example = createLock( item ); Lock lock = (Lock) s.createCriteria(Lock.class) .add( Example.create( example ).excludeProperty("httpSessionId") .excludeProperty("userLogin" ) .excludeProperty("name")) .uniqueResult(); tx.commit(); if( lock != null ) result = lock; } catch( HibernateException he ) { log.debug( "lock not released" ); tx.rollback(); } catch( Exception e ) { //this throws more than hibernate exception log.debug( "lock not released" ); tx.rollback(); } return result; } /** * Check if the item is accessible for the given User and session. * It is if there is no lock or the user owns the lock. * @param item * @return */ public boolean canAccess( User u, String sessionId, Lockable item ) { boolean result = true; StatelessSession s = getSession(); Transaction tx = s.beginTransaction(); try { Lock example = createLock( item ); Lock lock = (Lock) s.createCriteria(Lock.class) .add( Example.create( example ).excludeProperty("httpSessionId") .excludeProperty("userLogin" ) .excludeProperty("name")) .uniqueResult(); tx.commit(); if( lock != null ) { if(( lock.getUserLogin().equals( u.getLogin())) && ( lock.getHttpSessionId().equals( sessionId))) result = true; else result = false; } } catch( HibernateException he ) { log.debug( "Lock problem in canAccess" ); tx.rollback(); } return result; } /** * All the locks in the system. For the admin to play ... * @return */ public List<Lock> findAll() { StatelessSession s = getSession(); List<Lock> l = s.createQuery( "from Lock" ).list(); return l; } public List<Lock> findByUser( User u ) { StatelessSession s = getSession(); List<Lock> l = s.createQuery( "from Lock where userLogin = :login" ) .setString("login", u.getLogin()) .list(); return l; } public List<Lock> findBySession(String sessionId ) { StatelessSession s = getSession(); List<Lock> l = s.createQuery( "from Lock where httpSessionId = :sessionId" ) .setString("sessionId", sessionId ) .list(); return l; } private Lock createLock( Lockable l ) { Lock lock = new Lock(); String className = l.getClass().getCanonicalName(); try { className = Hibernate.getClass( l ).getCanonicalName(); } catch( HibernateException h ) { log.error( "Hibernate getClass() ", h ); } //log.debug( "Example log: "+l.getLockname()+" "+l.getClass().getCanonicalName()+"->"+className ); lock.setObjectId(l.getDbID()); lock.setObjectType( className ); lock.setName(l.getLockname()); return lock; } }