edu.nps.moves.mmowgli.hibernate.HSess.java Source code

Java tutorial

Introduction

Here is the source code for edu.nps.moves.mmowgli.hibernate.HSess.java

Source

/*
  Copyright (C) 2010-2014 Modeling Virtual Environments and Simulation
  (MOVES) Institute at the Naval Postgraduate School (NPS)
  http://www.MovesInstitute.org and http://www.nps.edu
     
  This file is part of Mmowgli.
      
  Mmowgli is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  any later version.
    
  Mmowgli is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
    
  You should have received a copy of the GNU General Public License
  along with Mmowgli in the form of a file named COPYING.  If not,
  see <http://www.gnu.org/licenses/>
*/

package edu.nps.moves.mmowgli.hibernate;

import static edu.nps.moves.mmowgli.MmowgliConstants.*;

import java.util.*;

import org.hibernate.*;

import com.vaadin.data.hbnutil.HbnContainer;

import edu.nps.moves.mmowgli.AppMaster;
import edu.nps.moves.mmowgli.messaging.MMessagePacket;
import edu.nps.moves.mmowgli.utility.MThreadManager;
import edu.nps.moves.mmowgli.utility.MiscellaneousMmowgliTimer.MSysOut;

/**
 * HSess.java
 * Created on Aug 11, 2014
 *
 * MOVES Institute
 * Naval Postgraduate School, Monterey, CA, USA
 * www.nps.edu
 *
 * @author Mike Bailey, jmbailey@nps.edu
 * @version $Id$
 */
public class HSess {
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private static final ThreadLocal<StackTraceElement[]> dbgThreadLocal = new ThreadLocal<StackTraceElement[]>();
    private static final ThreadLocal<ArrayList<MMessagePacket>> msgs = new ThreadLocal<ArrayList<MMessagePacket>>();

    // Debug 11 Sep 2015

    private static final ThreadLocal<HashSet<String>> setTL = new ThreadLocal<HashSet<String>>();

    private static void initSetDbugTL() {
        setTL.set(new HashSet<String>());
    }

    public static void addToDbugSetTL(String s, long id) {
        setTL.get().add(s + id);
    }

    public static void checkInDbugSetTL(String s, long id) {
        if (setTL.get().contains(s + id)) {
            System.out.println("*********** >>>>>>>>>>>> Found bug! " + s + " " + id + " <<<<<<<<<<< ************");
            StackTraceElement[] stes = Thread.currentThread().getStackTrace();
            for (StackTraceElement elem : stes)
                System.out.println(elem.toString());
            System.out.println("*********** end of bug trace **************");
        }
    }

    public static void clearDbugSet() {
        setTL.get().clear();
    }

    // End debug

    private static void set(Session sess) {
        initSetDbugTL(); //debug
        threadLocal.set(sess);
        dbgThreadLocal.set(Thread.currentThread().getStackTrace());
        msgs.set(new ArrayList<MMessagePacket>());
    }

    private static void unset() {
        clearDbugSet(); //debug
        threadLocal.remove();
        unsetDBEvents();
    }

    public static Session get() {
        return threadLocal.get();
    }

    public static void init() {
        if (get() != null) {
            dumpPreviousCallerTrace();
            repair(); // closes after dumping stack in sys out
        }

        Session s = VHib.openSession();
        s.setFlushMode(FlushMode.COMMIT);
        s.beginTransaction();
        s.getTransaction().setTimeout(HIBERNATE_TRANSACTION_TIMEOUT_IN_SECONDS);

        MSysOut.println(HIBERNATE_LOGS, "HSess.open() of sess " + s.hashCode());
        set(s);
    }

    public static void close() {
        close(true);
    }

    public static void close(boolean commit) {
        Session sess = get();
        if (sess == null || (!sess.isOpen()))
            return;

        Transaction trans = null;
        try {
            trans = sess.getTransaction();
            if (trans != null && trans.isActive() && commit)
                trans.commit();
        } catch (Throwable t) {
            if (trans != null)
                trans.rollback();
            MSysOut.println(HIBERNATE_LOGS,
                    "HSess.close() exception: " + t.getClass().getSimpleName() + " " + t.getLocalizedMessage());
            // The printStackTrace will bypass the deferred logging scheme, so head it up with this:
            System.out.println("Exception " + t.getClass().getSimpleName() + " " + t.getLocalizedMessage()
                    + " / trapped in HSess.close()/ dump follows");
            t.printStackTrace();
        } finally {
            if (sess.isOpen())
                sess.close();
        }
        unset();
        MSysOut.println(HIBERNATE_LOGS, "HSess.close() of sess " + sess.hashCode());
    }

    // Use the following 2 methods as a pair for conditional establishment of a thread-local session
    public static Object checkInit() {
        if (get() == null) {
            init();
            return true;
        }
        return false;
    }

    public static void checkClose(Object obj) {
        Boolean b = (Boolean) obj;
        if (b.booleanValue())
            close();
        return;
    }

    // Careful with this one; If any db objects are floating around in the thread, they are now out of sync with the
    // thread's session; used in game exporters
    public static void closeAndReopen() {
        close();
        init();
    }

    // Definitely close (and flush) session, but reopen since caller expects and open one; same caveat as previous method
    public static void closeAndCheckReopen(Object obj) {
        close();
        Boolean b = (Boolean) obj;
        if (!b.booleanValue())
            init();
    }

    //todo Consolidate with VHib
    public static SessionFactory getSessionFactory() {
        return VHib.getSessionFactory();
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static HbnContainer<?> getContainer(Class<?> cls) {
        return new HbnContainer(cls, getSessionFactory());
    }

    private static void repair() {
        close();
    }

    private static void dumpPreviousCallerTrace() {
        MSysOut.println(ERROR_LOGS, ">>>>>>>>>>>>>> Session leak, current stack:");
        StackTraceElement[] elems = new Throwable().getStackTrace();
        dumpStackElements(elems);

        elems = dbgThreadLocal.get();
        if (elems != null) {
            MSysOut.println(ERROR_LOGS, ">>>>>>>>>>>>> Existing leaked session was created by the following:");
            dumpStackElements(elems);
        }
    }

    private static void dumpStackElements(StackTraceElement[] stes) {
        for (StackTraceElement elem : stes)
            MSysOut.println(elem.toString());
        MSysOut.println(ERROR_LOGS, ">>>>>>>>>>>>> End of stack dumps.");
    }

    public static void queueDBMessage(MMessagePacket mmp) {
        msgs.get().add(mmp);
    }

    private static void unsetDBEvents() {
        if (msgs.get().isEmpty())
            return;

        ArrayList<MMessagePacket> alis = msgs.get();

        //  for(MMessagePacket mmp : alis) {
        //    MSysOut.println(HIBERNATE_LOGS," Pumping a db event to Appmaster.incomingDatabaseEvent now, msg = "+mmp.toString());
        //    AppMaster.instance().incomingDatabaseEvent(mmp);
        //  }

        MThreadManager.run(new DBMessageSender(alis));
        msgs.remove();
    }

    static class DBMessageSender implements Runnable {
        List<MMessagePacket> myLis;

        DBMessageSender(List<MMessagePacket> lis) {
            myLis = new ArrayList<MMessagePacket>(lis.size());
            for (int i = 0; i < lis.size(); i++)
                myLis.add(lis.get(i));
        }

        public void run() {
            //sleep(1000L); //test
            for (int i = 0; i < myLis.size(); i++) {
                MSysOut.println(HIBERNATE_LOGS, "Pumping a db event to Appmaster.incomingDatabaseEvent now, msg = "
                        + myLis.get(i).toString());
                AppMaster.instance().incomingDatabaseEvent(myLis.get(i));
            }
        }
        //    private void sleep(long ms)
        //    {
        //      try {Thread.sleep(ms);}catch(InterruptedException ex){}
        //    }
    }
}