0

I am someone that normally figures things out by myself researching and trying stuff (That's why I had zero questions here). However, I already wasted days trying to figure this out and I am out of options. I hope you guys can help me. I am trying to make my Java/Maven/Hibernate/JPA/Tomcat web application work on a free Heroku account. I was able to deploy successfully and send some data to the Heroku Postgres DB. The same application, running on a local server (Tomcat/IntelliJ), can successfully connect and retrieve data from the Heroku database. However, the deployed Heroku application is not working with the Heroku database. The application is running fine, but I am getting errors when it tries to retrieve data from the database.

I searched here for solutions related to this error and the others in the stack below, including the one already suggested: The meaning of NoInitialContextException error. None seems to fit my situation. The link above mentions using a Properties object, but as I mentioned, it is working fine locally and I never had to use such an object before. If you believe this could be a solution, could you provide more details on how to implement that in my environment?

I don't have a Procfile setup and I am deploying the application using the following Heroku command:

heroku war:deploy target/appname.war --app appname

This is the error stack I am getting (from Heroku log with debug log enabled):

2021-07-18T19:27:42.218347+00:00 app[web.1]: SEVERE: Servlet.service() for servlet [AdminServlet] in context with path [] threw exception [Servlet execution threw an exception] with root cause
2021-07-18T19:27:42.218348+00:00 app[web.1]: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
2021-07-18T19:27:42.218349+00:00 app[web.1]:    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:673)
2021-07-18T19:27:42.218349+00:00 app[web.1]:    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
2021-07-18T19:27:42.218350+00:00 app[web.1]:    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:350)
2021-07-18T19:27:42.218350+00:00 app[web.1]:    at javax.naming.InitialContext.getNameParser(InitialContext.java:505)
2021-07-18T19:27:42.218358+00:00 app[web.1]:    at org.hibernate.engine.jndi.internal.JndiServiceImpl.parseName(JndiServiceImpl.java:118)
2021-07-18T19:27:42.218358+00:00 app[web.1]:    at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:95)
2021-07-18T19:27:42.218359+00:00 app[web.1]:    at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.configure(DatasourceConnectionProviderImpl.java:98)
2021-07-18T19:27:42.218363+00:00 app[web.1]:    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:107)
2021-07-18T19:27:42.218363+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:246)
2021-07-18T19:27:42.218365+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101)
2021-07-18T19:27:42.218367+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
2021-07-18T19:27:42.218367+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
2021-07-18T19:27:42.218367+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
2021-07-18T19:27:42.218368+00:00 app[web.1]:    at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
2021-07-18T19:27:42.218368+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
2021-07-18T19:27:42.218369+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
2021-07-18T19:27:42.218369+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
2021-07-18T19:27:42.218369+00:00 app[web.1]:    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:176)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:127)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1224)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
2021-07-18T19:27:42.218371+00:00 app[web.1]:    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
2021-07-18T19:27:42.218371+00:00 app[web.1]:    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
2021-07-18T19:27:42.218376+00:00 app[web.1]:    at dataaccess.HibernateUtil.<clinit>(HibernateUtil.java:12)
2021-07-18T19:27:42.218376+00:00 app[web.1]:    at dataaccess.CityDB.getAllCities(CityDB.java:37)
2021-07-18T19:27:42.218376+00:00 app[web.1]:    at servlets.AdminServlet.doGet(AdminServlet.java:61)
2021-07-18T19:27:42.218377+00:00 app[web.1]:    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
2021-07-18T19:27:42.218377+00:00 app[web.1]:    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
2021-07-18T19:27:42.218378+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
2021-07-18T19:27:42.218378+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2021-07-18T19:27:42.218378+00:00 app[web.1]:    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
2021-07-18T19:27:42.218386+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
2021-07-18T19:27:42.218387+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2021-07-18T19:27:42.218387+00:00 app[web.1]:    at filters.AdminFilter.doFilter(AdminFilter.java:35)
2021-07-18T19:27:42.218387+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
2021-07-18T19:27:42.218388+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2021-07-18T19:27:42.218388+00:00 app[web.1]:    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
2021-07-18T19:27:42.218388+00:00 app[web.1]:    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
2021-07-18T19:27:42.218390+00:00 app[web.1]:    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
2021-07-18T19:27:42.218390+00:00 app[web.1]:    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
2021-07-18T19:27:42.218392+00:00 app[web.1]:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
2021-07-18T19:27:42.218392+00:00 app[web.1]:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
2021-07-18T19:27:42.218392+00:00 app[web.1]:    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
2021-07-18T19:27:42.218393+00:00 app[web.1]:    at java.lang.Thread.run(Thread.java:748)

The error happens when any of the classes in my application calls the EntityManagerFactory method in my HibernateUtil class. This is the code being called:

public class HibernateUtil {
    private static final EntityManagerFactory emf =
            Persistence.createEntityManagerFactory("AbsPu");

    public static EntityManagerFactory getEmFactory() {
        return emf;
    }
}

This is what my webapp/META-INF/context.xml looks like (I removed sensisitve data). Here I also tried to use the DATABASE_URL system variable from Heroku instead of hard coding the url but I couldn't figure out how to make it work. But it is working like this:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
    <Resource name="jdbc/postgres" auth="Container"
              type="javax.sql.DataSource"
              driverClassName="org.postgresql.Driver"
              url="jdbc:postgresql://ec2-52-2-118-38.compute-1.amazonaws.com:5432/...?sslmode=require"
              username="..." password="..."
              maxActive="100" maxIdle="30" maxWait="10000"
              logAbandoned="true" removeAbandoned="true"
              removeAbandonedTimeout="60" />
</Context>

And this is what my resources/META-INF/persisence.xml looks like. Again, I just removed the sensitive data (class names):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
  <persistence-unit name="AbsPu">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <non-jta-data-source>java:/comp/env/jdbc/postgres</non-jta-data-source>
    <class>...</class>
    ...
    <class>...</class>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
  </persistence-unit>
</persistence>

And lastly, my pom.xml:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>1.0</version>
  <packaging>war</packaging>

  <name>...</name>
  <URL>...</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.4.30.Final</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.20</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>...</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <configuration>
                  <source>8</source>
                  <target>8</target>
              </configuration>
          </plugin>
      </plugins>
  </build>
</project>

I provided as many details as I could think of. Let me know if you need more details!

DiegoWR
  • 11
  • 4
  • Does this answer your question? [The meaning of NoInitialContextException error](https://stackoverflow.com/questions/1525385/the-meaning-of-noinitialcontextexception-error) – Péter Veres Jul 18 '21 at 21:49

2 Answers2

1

Finally got it solved. These are the steps I did to fix the problem:

  1. Enabled JNDI naming by adding "--enable-naming" to the initialization: heroku config:set WEBAPP_RUNNER_OPTS="--enable-naming" --app appname. After adding this, I started to get a different error: java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory

  2. Based on the new error, I specified the resource factory in my context.xml: factory="org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory"

  3. And finally, added a new dependency to pom.xml:

    <dependency>
          <groupId>org.apache.tomcat</groupId>
          <artifactId>tomcat-dbcp</artifactId>
          <version>10.1.0-M2</version>
    </dependency>
    

The last two steps came from this question: SpringBoot JNDI datasource throws java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory

I believe IntelliJ works fine with JNDI naming by default and has an embedded Database Connection Pool API for Tomcat. That is probably why it was working fine locally and not on Heroku.

DiegoWR
  • 11
  • 4
0

Have you tried the approaches in the related questions for the same exception? Here is one of them. I've noticed that the maven compiler java versions do not match in the properties and in the actual plugin.

here:

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

and here:

 <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <configuration>
          <source>8</source>
          <target>8</target>
     </configuration>
 </plugin>

According to the docs Heroku currently has 1.8 as default

Péter Veres
  • 955
  • 1
  • 10
  • 25
  • I changed the version to 8 but it made no difference. Thank you for pointing that out though. I tried many things that I saw here related to this error but none seems to fit my situation. I never have to use the Properties object before. It is working fine locally as I mentioned. If this could be a solution, I have no idea how to implement that in my case. – DiegoWR Jul 18 '21 at 22:47
  • Maybe it's a bit far fetched idea, but if the code permits it and if there is room for a bit of experimentation, you could try to port it to SpringBoot or Quarkus. They are great for providing a lot of things out of the box, and jpa/hibernate is one of them. I would start with creating a small test project just with hibernate, a simple query and a rest endpoint, then add the connection details and upload it to Hiraku and see if it works. Testing on simpler projects when I have a complex problem has helped in many cases. – Péter Veres Jul 18 '21 at 23:15
  • 1
    This project is actually a capstone project. I have been studying Spring Boot / REST for a while by myself and I understand how powerful it is to make things easier and remove a ton of boilerplate code. However, my team did not want to switch to Spring since they did not want to leave their comfort zone with JSP/Servlets. The project is in an advanced stage now and it wouldn't be easy to switch to Spring. We also don't have much time and I am pretty sure they would not agree on that. I completely agree with you on that though, I would definitely switch to Spring. – DiegoWR Jul 18 '21 at 23:25
  • You mentioned that locally, when it worked, you've run it in Intellij. Is it possible that the final deployment package does not contain the xml config files? Have you tried to run it locally as well (not from the IDE) – Péter Veres Jul 18 '21 at 23:42
  • I removed everything from Tomcat/webapps, copied the war file to the folder, started Tomcat from the command line and it still works – DiegoWR Jul 19 '21 at 01:48
  • That's a good sign, it means that the problem is with the runtime environment at Heroku. There might be something that is present on your dev machine but missing or different up there. Like Java version, Tomcat version, environment variables (according to the documentation and the error message, the missing parameter can be set via env vars as well). – Péter Veres Jul 19 '21 at 02:30