4

I am trying to configure a embedded tomcat instance in my app without any configuration files.

I have done some research and based upon this long tutorial and a shorter one i extracted this steps:

  1. Create a ServletContextListener

    @WebListener //some articles on the web mentioned, that this would add the 
    //Listener automatically to the app context, but i cant believe that this works in my case
    public class HibernateListener implements ServletContextListener {
    
        public void contextInitialized(ServletContextEvent event) {
            HibernateUtil.getSessionFactory(); // create a factory
        }
    
        public void contextDestroyed(ServletContextEvent event) {
            HibernateUtil.getSessionFactory().close(); // free resources
        }
    }
    
  2. Add that Listener to the app context

    Context rootCtx = tomcat.addContext("", base.getAbsolutePath());
    rootCtx.getServletContext().addListener("com.example.listeners.HibernateListener");
    
    tomcat.start();
    tomcat.getServer().await();
    
  3. Implement the HibernateUtil class with the necessary configuration

    public class HibernateUtil {
    
        private static final SessionFactory sessionFactory;
    
        static {
            try {
                //should i call .configure() on the returned Configuration here?                
                sessionFactory = getConfiguration()
                        .buildSessionFactory();
            } catch (Throwable ex) {
                System.err.println("Initial SessionFactory creation failed." + ex);
                throw new ExceptionInInitializerError(ex);
            }
    
        }
    
        private static Configuration getConfiguration(){
            Configuration c = new Configuration();
    
            c.setProperty("hibernate.connection.url", "jdbc:hsqldb:hsql://localhost:1234/mydb1");
            c.setProperty("hibernate.connection.username", "SA");
            c.setProperty("hibernate.connection.password", "");
            c.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver");
    
    
            c.setProperty("dialect", "org.hibernate.dialect.HSQLDialect");
            c.setProperty("cache.provider_class", "org.hibernate.cache.NoCacheProvider");
            c.setProperty("cache.use_query_cache", "false");
            c.setProperty("cache.use_minimal_puts", "false");
            c.setProperty("max_fetch_depth", "3");
    
            c.setProperty("show_sql", "true");
            c.setProperty("format_sql", "true");
            c.setProperty("hbm2ddl.auto", "create");
    
            c.addPackage("com.example.models");
            c.addAnnotatedClass(MyClass.class);
    
            return c;
        }
    
        public static SessionFactory getSessionFactory() {
            return sessionFactory;
        }
    }
    
  4. Now i should somehow work with MyClass to create and retrieve data from the linked database through hibernate, right? (right now i am not sure, how exactly, but thats not the point here)

But unfortunately i am getting a NullPointerException when im trying to add the listener to tomcat

Exception in thread "main" java.lang.NullPointerException at org.apache.catalina.core.ApplicationContext.addListener(ApplicationContext.java:1278) at org.apache.catalina.core.ApplicationContextFacade.addListener(ApplicationContextFacade.java:649)

which points to the line rootCtx.getServletContext().addListener("com.example.listeners.HibernateListener");

EDIT 1

But if i am running hibernate standalone (without tomcat) it works fine. The Data is being saved without errors!

In HibernateUtil

public static void main(String[] args) {
    MyClass mycls = new MyClass();

    mycls.setMyProperty("My Property");
    Session session = getSessionFactory().openSession();
    Transaction transaction = session.beginTransaction();
    session.save(mycls);
    transaction.commit();
}

So the way i am configuring hibernate is fine i think. The error has something to do with the listener adding...

What am i doing wrong here?

ali
  • 404
  • 4
  • 16

2 Answers2

3

After a deep digging in the source code of Tomcat I have found one possible solution:

rootCtx.addApplicationListener(new ApplicationListener("com.example.listeners.HibernateListener", false));

It does what I needed!

joragupra
  • 692
  • 1
  • 12
  • 23
ali
  • 404
  • 4
  • 16
  • Have a look here. The applicationlistener of tomcate is not the right place for the initialization since a hibernate configzration belongs the the web application. http://mrbool.com/working-with-servlet-context-listeners-in-java/29304 – Diversity Jan 02 '14 at 12:30
  • Hm. But it looks like tomcat does just that when you configure a listener in web.xml. See the [source](http://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk/java/org/apache/catalina/deploy/WebXml.java) in `public void configureContext(Context context)` – ali Jan 02 '14 at 12:44
  • @ali what is teh rootctx coming from? – mjs Jun 24 '21 at 07:36
0

I think you have missing the invocation of the method cinfigure() of the configuraton c right after your initialisation.

So it should look like this::

 SessionFactory sessionFactory =  getConfiguration().confgure().buildSessionFactory();

or

c = getConfiguration();
sessionFactory = c.configure().buildSessionFactory();

UPDATE

In order to add complete properties at runtim you can create a Prperties object and use the method.

  configuration.buildSettings(Properties props)

I am not sure but using this approach it could be pssible that hibernate not looks for the hibernate.cfg.xml or .properties within classpath .

UPDATE

What you can try additionally to invoke your getConfiguration method within the getSessionFactory method instead of calling it within the static initializer of the HibernateUtil expliciteLy

public static getSessionFactory() {
    Configuration c = getConfiguration();
    sessionFactory = c.buildSessionFactory();
    return sessionFactory;
}
Diversity
  • 1,890
  • 13
  • 20
  • Thanks for your comment. I have tested running your suggestion with hibernate standalone and got this Exception: `Initial SessionFactory creation failed.org.hibernate.HibernateException: /hibernate.cfg.xml not found`. I have updated my question. After some testing i can tell that the configuration of **hibernate** itself is fine. – ali Jan 02 '14 at 01:02
  • I would suggest to put an hibernate.cfg.xml within your web-inf folder. It could be empty between the hibernate-configuration element since you set all properties within your application – Diversity Jan 02 '14 at 01:42
  • Also have a look at this discussion: http://stackoverflow.com/questions/6074678/setting-properties-programmatically-in-hibernate – Diversity Jan 02 '14 at 01:51
  • Sorry under WEB-INF/classes – Diversity Jan 02 '14 at 01:57
  • Well, as i mentioned in my updated question, hibernate works just fine executing the `main` method of `HibernateUtil` without an hibernate.cfg.xml file and without calling `configuration.configure()`. Why do you still think that the problem lies here? – ali Jan 02 '14 at 10:00