package com.peterphi.std.guice.hibernate.module;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.peterphi.std.annotation.Doc;
import com.peterphi.std.guice.common.shutdown.iface.ShutdownManager;
import com.peterphi.std.guice.common.shutdown.iface.StoppableService;
import com.peterphi.std.guice.database.annotation.Transactional;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

import javax.inject.Named;

/**
 * A SessionFactory Provider for Guice
 */
class HibernateSessionFactoryProvider implements Provider<SessionFactory>, StoppableService
{
	private static final Logger log = Logger.getLogger(HibernateSessionFactoryProvider.class);

	private final Provider<ServiceRegistry> serviceRegistryProvider;
	private final Configuration config;

	private SessionFactory sessionFactory;

	@Inject(optional = true)
	@Named("hibernate.shutdown.sql")
	@Doc("The SQL to run on the database before a shutdown occurs")
	private String shutdownSql;


	@Inject
	public HibernateSessionFactoryProvider(ShutdownManager coordinator,
	                                       Provider<ServiceRegistry> serviceRegistryProvider,
	                                       Configuration config)
	{
		this.serviceRegistryProvider = serviceRegistryProvider;
		this.config = config;

		coordinator.register(this);
	}


	public synchronized SessionFactory get()
	{
		if (this.sessionFactory == null)
		{
			final ServiceRegistry serviceRegistry = serviceRegistryProvider.get();

			this.sessionFactory = config.buildSessionFactory(serviceRegistry);
			log.trace("Hibernate Setup Complete.");
		}

		return sessionFactory;
	}


	@Override
	public void shutdown()
	{
		log.info("Shut down Hibernate SessionFactory...");

		if (sessionFactory != null)
		{
			runShutDownSQL();
			sessionFactory.close();
			sessionFactory = null;
		}
		else
		{
			log.info("SessionFactory already null");
		}
	}


	@Transactional
	void runShutDownSQL()
	{
		if (StringUtils.isNotEmpty(shutdownSql))
		{
			sessionFactory.getCurrentSession().createNativeQuery(shutdownSql).executeUpdate();
		}
	}
}

@@ -1352,16 +1352,128 @@
 fig)%0A%09%7B%0A
+%09%09if (config == null)%0A%09%09%09throw new IllegalArgumentException(%22Must provide non-null hibernate Configuration!%22);%0A%0A
 %09%09this.s
@@ -1522,16 +1522,16 @@
 ovider;%0A
-
 %09%09this.c
@@ -1741,16 +1741,29 @@
 get();%0A%0A
+%09%09%09try%0A%09%09%09%7B%0A%09
 %09%09%09this.
@@ -1824,16 +1824,127 @@
 istry);%0A
+%09%09%09%7D%0A%09%09%09catch (Throwable t) %7B%0A%09%09%09%09log.warn(%22Error setting up hibernate session factory%22,t);%0A%0A%09%09%09%09throw t;%0A%09%09%09%7D%0A
 %09%09%09log.t

Improve error logging when hibernate SessionFactory construction fails