Announcement Announcement Module
Collapse
No announcement yet.
Error trapping for a missing data source in a Spring MVC web app Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Error trapping for a missing data source in a Spring MVC web app

    Hello,
    I have written a web app that uses Spring MVC libraries and Spring JDBC to connect to an Oracle DB. (I don't use any ORM type libraries as I create stored procedures on Oracle that do my stuff and I'm quite happy with that.)
    I use a connection pool to Oracle managed by the Tomcat container

    The app generally works absolutely fine by the way!

    BUT...
    I noticed the other day when I tried to set up the app on another Tomcat instance that I had forgotten to configure the connection pool and obviously the app could not get hold of an org.apache.commons.dbcp.BasicDataSource object, so it crashed.

    I define the pool params in the tomcat "context.conf"

    In my "web.xml" I have:
    Code:
            <servlet>
    		<servlet-name>appServlet</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>/WEB-INF/Spring/appServlet/servlet-context.xml</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>appServlet</servlet-name>
    		<!-- Map *everything* to appServlet -->
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>
    
            <resource-ref>
    		<description>Oracle Datasource example</description>
    		<res-ref-name>jdbc/ora1</res-ref-name>
    		<res-type>org.apache.commons.dbcp.BasicDataSource</res-type>
    		<res-auth>Container</res-auth>
    	</resource-ref>
    And I have a Spring "servlet-context.xml" where JNDI is used to map the data source object provided by the connection pool to a Spring bean with the ID of "dataSource":
    Code:
    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ora1"
    		resource-ref="true" />
    Here's the question: Where do I trap the case where the database cannot be accessed for whatever reason?

    I don't want the user to see a yard-and-a-half of Java stack trace in their browser, rather a nicer message that tells them there is a database problem etc.
    It seems that my app tries to configure the "dataSource" bean (in "servlet-context.xml") before any code has tested it can actually provide a dataSource object from the pool?!

    Maybe I'm not fully understanding exactly what is going on in these stages of the app firing up ...

    Thanks for any advice!
    Last edited by grheatley; Apr 2nd, 2012, 08:58 AM. Reason: Readability

  • #2
    I have a feeling that something needs "decoupling" here: for my MVC app to work it depends on a data source object as it initializes. I suppose it is the presence of the data source object that allows the model part of the system (i.e. Model, View, Controller) to come into existence.
    But without the model's initialization the system is broken and I can't use the controller to change the view to a nice error message.

    I have a suspicion that the initialization of the app should not depend on the data source being available and the the data source object should be requested by the controller.

    Comment


    • #3
      Not sure about your requirement. I believe you deployed the application on an environment on which you had not configured a data source and as soon as you started the application, an error was thrown that no data source was found. You seem to be looking for a way for the application to start and later discover that there is no data source, although you haven't configured a data source at all. From my perspective, you will simply be deferring the discovery of a crucial application resource, which to me does not make sense. I would like to be notified of missing critical dependencies at the earliest, rather than later. From the explanation above, I would be very glad that the application did not start and I would correct the missing data source problem.

      There is still a valid case for the need to trap database errors generically (or any kind of errors for that matter). In our applications, we use an HTTP request filter as the first filter to execute. This filter simply traps any uncaught exceptions arising out of the request processing. Then, depending on the severity of the exception, many different things can occur. Non-critical exceptions are simply logged asynchronously to a log file for further investigation and diagnosis. Critical ones are pushed on to a JMS queue, from where they notifications are sent out over emails and text messages to alert the team. This allows us to react quickly to any undesirable event, such as, the database server crashing. In many cases we display a generic error page when an uncaught exception is trapped, but this is not always the case because an exception could be minor to be allowed to go through.

      Comment


      • #4
        Taking the JNDI lookup out of the servlet-context.xml file ...

        In this situation the error was due to my own forgetfulness and I could fix the problem myself. But as a general rule I don't have control over the database, so the same (or very similar) situation could arise (i.e. it would not be possible for the connection pool to provide a dataSource object for my app during its initialization stage), but for different reasons, for example if the DBA changed the Oracle account password etc.

        I just wanted to know how to test for error conditions at that initialization stage, and handle them gracefully as far as the browser messages were concerned.

        I was wondering if there was a way to do the jndi-lookup in java rather than in xml? In this way I could wrap it in a try/catch block?

        I'm thinking something like this:-
        [ I ripped this code from here, BTW ]

        Code:
        import java.sql.*;
        import javax.naming.*;
        import javax.sql.*;
        
        final class GetConnection {
        
          /** Uses JNDI and Datasource (preferred style).   */
          static Connection getJNDIConnection(){
            String DATASOURCE_CONTEXT = "java:comp/env/jdbc/blah";
            
            Connection result = null;
            try {
              Context initialContext = new InitialContext();
              if ( initialContext == null){
                log("JNDI problem. Cannot get InitialContext.");
              }
              DataSource datasource = (DataSource)initialContext.lookup(DATASOURCE_CONTEXT);
              if (datasource != null) {
                result = datasource.getConnection();
              }
              else {
                log("Failed to lookup datasource.");
              }
            }
            catch ( NamingException ex ) {
              log("Cannot get connection: " + ex);
            }
            catch(SQLException ex){
              log("Cannot get connection: " + ex);
            }
            return result;
          }

        I already have a Spring DAO configuration class in my app, shown below:-
        Code:
        import javax.sql.DataSource;
        
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        
        @Configuration
        public class DaoConfig {
        
            // Take the datasource as configured in the servlet-context.xml
            // file, and autowire it in here.
            @Autowired
            private DataSource dataSource;
        
            // Use the data source to create a new instance of this bean
            @Bean
            public EnrolScheduleStProc confStProc() {
                return new EnrolScheduleStProc(dataSource);
            }
        }
        Would it be "good Spring style" to remove the jndi-lookup XML line from the servlet-context.xml and test for a valid dataSource object in the configuration class, sort of in the style of the code in the first code block, above?
        Last edited by grheatley; Apr 4th, 2012, 06:06 AM. Reason: clarity

        Comment


        • #5
          FIXED! Let Spring configure the MVC stuff, but get a data source via the Controller

          I took the jndi-lookup line out of the servlet-context.xml file, and added another class, below. I called the getJndiDataSource method from my MVC Controller when I wanted to connect to the database, and needed the data source, trapping all errors in the obtaining and using of the datasource object.

          Code:
          import javax.naming.Context;
          import javax.naming.InitialContext;
          import javax.naming.NamingException;
          
          import javax.sql.DataSource;
          
          public class DataSrcConfig {
          
             public static DataSource getJndiDataSource() throws NamingException{
          
                 Context initialContext = new InitialContext();
                 DataSource ds = (DataSource)initialContext.lookup("java:comp/env/jdbc/ora1");
          
                 return ds;
             }
          }

          Comment

          Working...
          X