-----Original Message-----
From: Christopher Schultz <ch...@christopherschultz.net> 
Sent: Friday, August 15, 2025 12:18 PM
To: users@tomcat.apache.org
Subject: Re: [EXTERNAL EMAIL] How to access a REST service

Daniel,

On 8/15/25 12:49 AM, Daniel Schwartz wrote:
> Robert (and all),
> 
> I will work on answers your various questions.  However, I decided to first 
> explore the comment (by someone) that a servlet can "swallow" an exception, 
> which I take to mean that it can throw an exception without reporting the 
> exception or terminating the program.
> 
> I have this system running on a PC identified as localhost. The test URL is:
> 
> https://urldefense.proofpoint.com/v2/url?u=http-3A__localhost-3A8080_H
> olidaysRESTJSON-2D1.0-2DSNAPSHOT_webresources_holidaysandevents_countr
> ies&d=DwICaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=AbCalLxzo
> pgQUG9LLcXdB80OM-GtDfItX76RMxNYqz4&m=NKm1FUayvDzFHyhbqCI0JR32OpW1rfTed
> HFkAoC_xT6Cjqt4-wsVFtYKPtR38vFY&s=4BYNb88ZN6WvyMyyZcR1FyT6Jg-qa4JSDa9P
> xsSFgB4&e=
> 
> I ran two tests.  First, I wrote in code to throw an SQL exception, which did 
> get caught in my catch clause, which printed out some messages and a stack 
> trace.  The web browser showed the retrieved list of countries, but nothing 
> else.
> 
> Second, I replaced the line that throws the SQL exception by one that tries 
> to do a division by zero.  This of course was not caught, but it did print 
> out a stack trace and reported a 505 error in the browser, and the program 
> did terminate.
> 
> I take this to mean that exceptions are not being "swallowed" by my program.  
> When/if an exception occurs, there is definitely some indication of this, 
> either in the server.log or the browser.  Because I have never seen either of 
> these actions, I'm fairly sure that my program is not throwing exceptions and 
> all database connections are being closed immediately after they are used, 
> i.e., no memory leaks in this respect.
> 
> The actual code fragments and outputs are copied below.
> 
> ----------------------------------------------------------------
> The code that throws the SQL exception
> ----------------------------------------------------------------
>      @GET
>      @Path("/countries")
>      @Produces(MediaType.APPLICATION_JSON)
>      public String getJsonCountries() {
>          if (TempDataStorage.countryList == null) {
>              Connection connection = null;
>              try {
>                  connection = dataSource.getConnection();
>                  System.out.println("countries connection has been opened");
>                  TempDataStorage.countryList = 
> GetCountryList.doIt(connection);
>                  throw new SQLException("testing sql exception");
> //                connection.close();
> //                System.out.println("countries connection has been closed");
>              } catch (SQLException e) {
>                  System.out.println(e);
>                  System.out.println("catching sql exception");
>                  if (connection != null) {
>                      try {
>                          connection.close();
>                      } catch (SQLException ex) {
>                          System.out.println(ex);
>                      }
>                  }
>              }
>          }

100% connection leak every time, guaranteed.

You are never closing the connection, because it's been commented out. 
Perhaps this was just for testing, because I see you are throwing an exception.

DGS: When I put in the throw statement, I had to comment out those two lines 
because the Java compiler complains that they are unreachable.  This was just 
to test for what would happen if an SQL exception was thrown, in which case, 
yes, there will be a memory.  The point is that my program never throws SQL 
exceptions, because if it did, I would know about it.

The conn.close() *MUST* be in a finally {} block. Do not put it in the try 
block. Do not put it in the catch block. Always put it in the finally block.

DGS: Sounds like good advice.  I'll do this and see if it makes a difference.

> ------------------------------------------------------------------
> The output in the server.log file
> ------------------------------------------------------------------
> [2025-08-14T23:34:42.019-0400] [glassfish 4.1] [INFO] [] [] [tid: 
> _ThreadID=40 _ThreadName=Thread-8] [timeMillis: 1755228882019] [levelValue: 
> 800] [[
>    countries connection has been opened]]
> 
> [2025-08-14T23:34:42.022-0400] [glassfish 4.1] [INFO] [] [] [tid: 
> _ThreadID=40 _ThreadName=Thread-8] [timeMillis: 1755228882022] [levelValue: 
> 800] [[
>    java.sql.SQLException: testing sql exception
>       at 
> com.worldholidaysandevents.restjsonwebservice.HolidaysRESTJSONResource
> .getJsonCountries(HolidaysRESTJSONResource.java:54)
> 
>          ... stack trace ...
> 
> [2025-08-14T23:34:42.022-0400] [glassfish 4.1] [INFO] [] [] [tid: 
> _ThreadID=40 _ThreadName=Thread-8] [timeMillis: 1755228882022] [levelValue: 
> 800] [[
>    catching sql exception]]

... and the server does not crash. You can make any request without restarting 
Glassfish, right?

> ----------------------------------------------------------------
> The code that divides by zero
> ----------------------------------------------------------------
>      @GET
>      @Path("/countries")
>      @Produces(MediaType.APPLICATION_JSON)
>      public String getJsonCountries() {
>          if (TempDataStorage.countryList == null) {
>              Connection connection = null;
>              try {
>                  connection = dataSource.getConnection();
>                  System.out.println("countries connection has been opened");
>                  TempDataStorage.countryList = 
> GetCountryList.doIt(connection);
>                  float something = 1/0;
>                  connection.close();
>                  System.out.println("countries connection has been closed");
>              } catch (SQLException e) {
>                  System.out.println(e);
>                  System.out.println("catching sql exception");
>                  if (connection != null) {
>                      try {
>                          connection.close();
>                      } catch (SQLException ex) {
>                          System.out.println(ex);
>                      }
>                  }
>              }
>          }


100% connection leak every time, guaranteed.

You are never closing the connection, because your code is throwing an uncaught 
exception (divide by zero) Perhaps this was just for testing, because I see you 
are intentionally dividing by zero.

DGS: Right.  This was to test for what would happen if a non-SQL exception were 
thrown, i.e., one that is not caught in the catch clause.   This created a 505 
error and the program quit running.  Here the point is that, if something like 
this were to happen, I would certainly know about it, and it has never 
happened, so no memory leak is being created in this way. 

The conn.close() *MUST* be in a finally {} block. Do not put it in the try 
block. Do not put it in the catch block. Always put it in the finally block.

DGS: Thanks again.  I'll do this and see if it makes any difference in the 
connection pooling.

-chris


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to