Package com.cloud.bridge.persist

Source Code of com.cloud.bridge.persist.PersistContext

/*
* Copyright (C) 2011 Citrix Systems, Inc.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloud.bridge.persist;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.cloud.bridge.util.CloudSessionFactory;
import com.cloud.bridge.util.Tuple;

/**
* @author Kelven Yang
*
* We use Per-thread based hibernate session and transaction pattern. Transaction will be
* started implicitly by EntityDao instances and be committed implicitly in the end of
* request-process cycle. All requests are guarded by a dynamic proxy.
*
* We will try to keep transaction management as implicit as we can, so that
* most of service layer implementation contains business-logic only, all business logic are
* built on top of domain object model, and all persistent layer handling lie within persist layer
* in Dao classes.
* PersistContext class also provides per-thread based registry service and global named-lock service
*/
public class PersistContext {
    protected final static Logger logger = Logger.getLogger(PersistContext.class);
 
  private static final CloudSessionFactory sessionFactory;
 
  private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>();
  private static final ThreadLocal<Transaction> threadTransaction = new ThreadLocal<Transaction>();
  private static final ThreadLocal<Map<String, Object>> threadStore = new ThreadLocal<Map<String, Object>>();
 
  static {
    try {
      sessionFactory = CloudSessionFactory.getInstance();
    } catch(HibernateException e) {
      logger.error("Exception " + e.getMessage(), e);
      throw new PersistException(e);
    }
  }
 
  public static Session getSession() {
    Session s = threadSession.get();
    try {
      if(s == null) {
        s = sessionFactory.openSession();
        threadSession.set(s);
      }
    } catch(HibernateException e) {
      logger.error("Exception " + e.getMessage(), e);
      throw new PersistException(e);
    }
    return s;
  }
 
  public static void closeSession() {
    try {
      Session s = (Session) threadSession.get();
      threadSession.set(null);
     
      if (s != null && s.isOpen())
        s.close();
    } catch(HibernateException e) {
      logger.error("Exception " + e.getMessage(), e);
      throw new PersistException(e);
    }   
  }
 
  public static void beginTransaction() {
    Transaction tx = threadTransaction.get();
    try {
      if (tx == null) {
        tx = getSession().beginTransaction();
        threadTransaction.set(tx);
      }
    } catch(HibernateException e) {
      logger.error("Exception " + e.getMessage(), e);
      throw new PersistException(e);
    }   
  }
 
  public static void commitTransaction() {
    Transaction tx = threadTransaction.get();
    try {
      if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() )
        tx.commit();
      threadTransaction.set(null);
    } catch (HibernateException e) {
      logger.error("Exception " + e.getMessage(), e);
     
      rollbackTransaction();
      throw new PersistException(e);
    }   
  }
 
  public static void rollbackTransaction() {
    Transaction tx = (Transaction) threadTransaction.get();
    try {
      threadTransaction.set(null);
      if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) {
        tx.rollback();
      }
    } catch (HibernateException e) {
      logger.error("Exception " + e.getMessage(), e);
      throw new PersistException(e);
    } finally {
      closeSession();
    }
  }
 
    public static void flush() {
      commitTransaction();
      beginTransaction();
  }

    /**
     * acquireNamedLock/releaseNamedLock must be called in pairs and within the same thread
     * they can not be called recursively neither
     *
     * @param name
     * @param timeoutSeconds
     * @return
     */
    public static boolean acquireNamedLock(String name, int timeoutSeconds) {
      Connection conn = getJDBCConnection(name, true);
      if(conn == null) {
        logger.warn("Unable to acquire named lock connection for named lock: " + name);
        return false;
      }
     
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement("SELECT COALESCE(GET_LOCK(?, ?),0)");

            pstmt.setString(1, name);
            pstmt.setInt(2, timeoutSeconds);
           
            ResultSet rs = pstmt.executeQuery();
            if (rs != null && rs.first()) {
               if(rs.getInt(1) > 0) {
                 return true;
               } else {
                     logger.error("GET_LOCK() timed out on lock : " + name);
               }
            }
        } catch (SQLException e) {
            logger.error("GET_LOCK() throws exception ", e);
        } catch (Throwable e) {
            logger.error("GET_LOCK() throws exception ", e);
        } finally {
          if (pstmt != null) {
            try {
              pstmt.close();
            } catch (SQLException e) {
              logger.error("Unexpected exception " + e.getMessage(), e);
            }
          }
        }
       
        releaseJDBCConnection(name);
        return false;
    }
   
    public static boolean releaseNamedLock(String name) {
        Connection conn = getJDBCConnection(name, false);
        if(conn == null) {
            logger.error("Unable to acquire DB connection for global lock system");
          return false;
        }
       
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement("SELECT COALESCE(RELEASE_LOCK(?), 0)");
            pstmt.setString(1, name);
            ResultSet rs = pstmt.executeQuery();
            if(rs != null && rs.first())
              return rs.getInt(1) > 0;
            logger.error("RELEASE_LOCK() returns unexpected result : " + rs.getInt(1));
        } catch (SQLException e) {
            logger.error("RELEASE_LOCK() throws exception ", e);
        } catch (Throwable e) {
            logger.error("RELEASE_LOCK() throws exception ", e);
        } finally {
          releaseJDBCConnection(name);
        }
        return false;
    }
   
    @SuppressWarnings("deprecation")
  private static Connection getJDBCConnection(String name, boolean allocNew) {
      String registryKey = "JDBC-Connection." + name;
      Tuple<Session, Connection> info = (Tuple<Session, Connection>)getThreadStoreObject(registryKey);
      if(info == null && allocNew) {
        Session session = sessionFactory.openSession();
        Connection connection = session.connection();
        if(connection == null) {
          session.close();
          return null;
        }
         
        try {
          connection.setAutoCommit(true);
        } catch(SQLException e) {
          logger.warn("Unexpected exception " + e.getMessage(), e);
        try {
          connection.close();
          session.close();
        } catch(Throwable ex) {
            logger.warn("Unexpected exception " + e.getMessage(), e);
        }
        return null;
        }
       
        registerThreadStoreObject(registryKey, new Tuple<Session, Connection>(session, connection));
        return connection;
      }
     
      if(info != null)
        return info.getSecond();
     
      return null;
    }
   
    private static void releaseJDBCConnection(String name) {
      String registryKey = "JDBC-Connection." + name;
      Tuple<Session, Connection> info = (Tuple<Session, Connection>)unregisterThreadStoreObject(registryKey);
      if(info != null) {
        try {
          info.getSecond().close();
          info.getFirst().close();
        } catch(Throwable e) {
          logger.warn("Unexpected exception " + e.getMessage(), e);
        }
      }
    }
   
    public static void registerThreadStoreObject(String name, Object object) {
      Map<String, Object> store = getThreadStore();
      store.put(name, object);
    }
   
    public static Object getThreadStoreObject(String name) {
      Map<String, Object> store = getThreadStore();
      return store.get(name);
    }
   
    public static Object unregisterThreadStoreObject(String name) {
      Map<String, Object> store = getThreadStore();
      if(store.containsKey(name)) {
        Object value = store.get(name);
        store.remove(name);
        return value;
      }
      return null;
    }
   
    private static Map<String, Object> getThreadStore() {
      Map<String, Object> store = threadStore.get();
      if(store == null) {
        store = new HashMap<String, Object>();
        threadStore.set(store);
      }
      return store;
    }
}
TOP

Related Classes of com.cloud.bridge.persist.PersistContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.