Search code examples
javarestpostgresql-9.4illegalstateexceptiontomcat8.5

Unable to connect to pgsql database with Java REST-API on local Tomcat server. Stack contains ExceptionInInitializerError and IllegalStateException


I am developing a REST-API and currently trying to fix an issue. The issue is that the REST-API is Unable to connect to pgsql database, when I go to my web page in chrome. To show this issue, I'll post a stripped down version of my stack with some explanation, describing the origin and functionality of the involved Java classes and XML. Afterwards, I'll show some code of the involved XML files and java classes. I'll look forward to your answers and feedback on my first post.

UPDATE: at the end of the post I'll disclose my major progress towards finding the answer.

Up till now I'm using the following tools:

  • Eclipse EE (Oxygen II at the moment)
  • Apache Tomcat 8.5.14
  • Maven
  • Chrome
  • PG-admin 4

the stack begins with this line, which probably means Jersey runs into some difficulties.

WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:

My stack continues with java.lang.ExceptionInInitializerError shown below, originating from my database connection broker.

MultiException stack 1 of 2
java.lang.ExceptionInInitializerError
at nl.hu.v1wac.PostgresDAO.webservices.WorldResource.<init (WorldResource.java:25) 
Caused by: java.lang.RuntimeException: javax.naming.NameNotFoundException: Name [jdbc/PostgresDS] is not bound in this Context. Unable to find [jdbc].
at nl.hu.v1wac.PostgresDAO.jdbc.BaseDAO.<init>(BaseDAO.java:38)
at nl.hu.v1wac.PostgresDAO.jdbc.CountryDAO.<init>(CountryDAO.java:13)
at nl.hu.v1wac.PostgresDAO.model.WorldService.<init>(WorldService.java:9)
at nl.hu.v1wac.PostgresDAO.model.ServiceProvider.<clinit>(ServiceProvider.java:4)
... 61 more

the second exception in the multistack is the IllegalStateException, originating from my WorldResource class, containing the Unified Resource Identifiers and JSON interpreter for parsing json messages to my front-end.

MultiException stack 2 of 2
java.lang.IllegalStateException: Unable to perform operation: create on nl.hu.v1wac.PostgresDAO.webservices.WorldResource
Caused by: java.lang.RuntimeException: javax.naming.NameNotFoundException: 
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:393)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

Below I will show my web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>MavenJersey</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>nl.hu.v1wac.PostgresDAO.webservices</param-value>
    </init-param>
    <init-param>
      <param-name>jersey.config.server.provider.classnames</param-name>
      <param-value>org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/restservices/*</url-pattern>
  </servlet-mapping>
</web-app>

Below Ill show my BaseDAO. This class is a connection broker for my Data Access Objects.

import java.sql.Connection;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.net.URI;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;

public class BaseDAO {
    private static final String URL = "jdbc:postgresql://";
    private static final String JDBC_DRIVER = "org.postgresql.Driver";
    private static final String CONTEXT = "java:comp/env/jdbc/PostgresDS";
    private DataSource connectionPool;
    public BaseDAO() {
    try {
        final String DATABASE_URL_PROP = System.getenv("DATABASE_URL");
        if (DATABASE_URL_PROP != null) {
            URI dbUri = new URI(DATABASE_URL_PROP);
            String dbUrl = URL + dbUri.getHost() + dbUri.getPath();
            BasicDataSource pool = new BasicDataSource();

            if (dbUri.getUserInfo() != null) {
                pool.setUsername(dbUri.getUserInfo().split(":")[0]);
                pool.setPassword(dbUri.getUserInfo().split(":")[1]);
                }
                pool.setDriverClassName(JDBC_DRIVER);
                pool.setUrl(dbUrl);
                pool.setInitialSize(1);

                connectionPool = pool;

        } else{
            InitialContext ic = new InitialContext();
            connectionPool = (DataSource) ic.lookup(CONTEXT);
        }
    } catch (Exception e) {

      throw new RuntimeException(e);
    }
    }
  protected final Connection getConnection() {
      try {
          return connectionPool.getConnection();
      } catch (Exception ex) {
          throw new RuntimeException(ex);
      }
  }
}

Finally, I'll conclude this post with my WorldResource class. please note that most code is excluded.

public class WorldResource{
    private WorldService service = ServiceProvider.getWorldService();    
@GET
@RolesAllowed({"admin"})
@Path("/getAll")
@Produces(MediaType.APPLICATION_JSON)
public String getCountries() {
        JsonArrayBuilder jab;
        jab = Json.createArrayBuilder();
        for (Country c : service.getAllCountries()) {
            jab.add(makeCountryObj(c));
        }
        return jab.build().toString();
}

Edit: After @Alok Sinha posted that the context.xml is missing, I added my already existing context.xml to give some extra insight.

<?xml version="1.0" encoding="UTF-8"?> 
<Context> <Resource name="jdbc/PostgresDS" 

url="jdbc:postgresql://localhost:5432/mydb" driverClassName="org.postgresql.Driver" 
auth="Container" 
type="javax.sql.DataSource" 
username="javaduser" 
password="javadude" 
/> 
<ResourceLink name="jdbc/PostgresDS" global="jdbc/PostgresDS" type="javax.sql.DataSource" 
/>
</Context>

UPDATE: after adding a resource references to my web.xml, recommended by this manual of Apache, I was able to get some new insight in my connection problems.

  <resource-ref>
    <description>PostgreSQL Datasource example</description>
    <res-ref-name>jdbc/PostgresDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

As shown in the stack below, it seems that adding a resource ref helps pointing my Application into the right direction. however, the name and url seem to be empty.

Cannot create JDBC driver of class '' for connect URL 'null'
java.sql.SQLException: No suitable driver
at java.sql.DriverManager.getDriver(Unknown Source)
at nl.hu.v1wac.PostgresDAO.jdbc.BaseDAO.getConnection(BaseDAO.java:47)
at nl.hu.v1wac.PostgresDAO.webservices.WorldResource.getCountries(WorldResource.java:34)

UPDATE2: I've tried another approach. I began with an initial maven project, and build my application up from there. I got rid of the IllegalstateException. I've implemented your context.xml exactly as Alok Sinha described. So, no Resourcelink. I've also undressed the BaseDAO to a point where it only has an Initialcontext and a Datasource. Now I can deploy the application as a war file without the basedao. If I try to deploy it with BaseDAO, I can't run due to the following error in my tomcat log:

org.apache.catalina.deploy.NamingResourcesImpl.cleanUp Failed to retrieve
JNDI naming context for container [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/holidayboardapp]] so no cleanup was performed for that container 
  javax.naming.NameNotFoundException: Name [comp/env] is not bound in this Context. Unable to find [comp].`

Solution

  • It appears that you have not bound your datasource in tomcat's JNDI. You would need to make an entry in context.xml , like the below -

    <Resource name="jdbc/PostgresDS" auth="Container" type="javax.sql.DataSource"
               maxActive="100" maxIdle="30" maxWait="10000"
               username="javauser" password="javadude" driverClassName="org.postgresql.Driver"
               url="jdbc:postgresql:localhost..."/>