I am seeing strange behaviour with a servlet I wrote to return an image
from a database table. I'm not sure if it's struts related or not, but I
am relying on a datasource defined in the struts-config.xml. It might be
a silly mistake in the servlet code itself even.

I've attached the struts-config.xml which shows my datasource
definition, the web.xml where I define the servlet and provide an
initialization parameter, the servlet code (PhotoServlet.java) and a
simple test.jsp page.

The code I have seems to work most of the time (about 25/30 requests)
before failing a couple of times. The log.txt attachment shows the
result of doing:

   while true
   do 
     lwp-request \
     'http://localhost:8080/shona/servlets/photo?id=1&class=thumbnail' \
     | wc -c 
   done

(just sequential requests)

The error.txt attachment shows the exception information generated when
a request fails. Note there seem to be two types of exceptions occuring
here: a low level jdbc error, and a "no results returned" error.

I've played with the maxCount and minCount parameters in the struts
datasource definition. Same results, except in the case of several
simultaneous requests to the servlet -- in which case raising maxCount
seems to prolong the interval between exceptions.

It's really been baffling me for a while now. What could be going wrong?
Am I seeing a limitation of Struts' connection pool perhaps? Even if
it's not struts related, suggestions would still be very welcome.

Matt
/*
 * PhotoServlet.java
 *
 * Created on February 23, 2002, 2:53 AM
 */

package mbkennedy.pshop.servlets;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.*;
import java.io.*;
import java.sql.*;

/**
 *
 * @author  mkennedy
 * @version
 */
public class PhotoServlet extends org.apache.struts.action.ActionServlet {
    
    private static final long DEFAULT_BUFFER_SIZE =  1024;
    
    /**
     * bufferSize to use when transfering blob to servlet response.
     */
    private long bufferSize;
    
    private DataSource dataSource = null;
    
    /** 
     * Initializes the servlet.
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        String bufferSizeParam = null;

        if ((bufferSizeParam = config.getInitParameter("bufferSize")) != null) {
            // Servlet deployer intends to override default bufferSize
            this.bufferSize = Long.parseLong(config.getInitParameter("bufferSize"));
            if (this.bufferSize <= 0) {
                throw new ServletException("bufferSize must be > 0: bufferSize == " + 
                    this.bufferSize);
            }
        } else {
            this.bufferSize = this.DEFAULT_BUFFER_SIZE;
        }
        dataSource = this.findDataSource("default");
    }
    
    
    /** 
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
      
        // Check request parameters
        if (request.getParameter("id") == null || request.getParameter("class") == null) {
            throw new ServletException("invalid request parameters: id = " + 
                request.getParameter("id") + ", class = " + request.getParameter("class"));
        }
        // Validate parameters
        int paramId = 0;
        try {
            paramId = Integer.parseInt(request.getParameter("id"));
        } catch (NumberFormatException e_nf) {
            throw (ServletException) new ServletException("id must be an integer: id = " + 
                request.getParameter("id")).initCause(e_nf);
        }
        Connection conn = null;
        try {
            String paramClass = null;
            conn = this.dataSource.getConnection();
            PreparedStatement stmt1 = 
                conn.prepareStatement("SELECT class FROM image_class WHERE class = ?");
            stmt1.setString(1, request.getParameter("class"));
            if (stmt1.executeQuery().getFetchSize() == 0) {
                throw new ServletException("class is invalid: class = " + 
                    request.getParameter("class"));
            } else {
                paramClass = request.getParameter("class");
            }
            stmt1.close();
            
            // At this point parameters have been validated for correctness (it 
            // should be safe to process the request)
        
            PreparedStatement stmt2 = conn.prepareStatement("SELECT image, mime_type " + 
                "FROM item_photos WHERE (item_id = ?) AND (image_class = ?)");
            stmt2.setInt(1, paramId);
            stmt2.setString(2, paramClass);
            ResultSet results = stmt2.executeQuery();
      
            ServletOutputStream out = response.getOutputStream();
            if (results.getFetchSize() == 0) {
                out.close();
            } else {
                // TODO: Handle multiple photos for a single pruduct
                results.first();
                Blob blob = results.getBlob("image");
                long length = blob.length();
                long chunks = length / this.bufferSize;
                long remainder = length % this.bufferSize;
                response.setContentType(results.getString("mime_type"));

                long pos = 0; 
                for (long i = 0; i < chunks; i++, pos += this.bufferSize) {
                    out.write(blob.getBytes(pos, (int) this.bufferSize));
                }
                out.write(blob.getBytes(pos, (int) remainder));

                out.close();
            }
            stmt2.close();
            
        } catch (SQLException e_sql) {
            throw (ServletException) 
                new ServletException("SQL error").initCause(e_sql);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e_sql) {
                }
            }
        }
    }
    
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, java.io.IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }
              
    /** 
     * Returns a short description of the servlet.
     */
    public String getServletInfo() {
        return "Servlet to return photo images from the database.";
    }
    
}
2002-03-10 02:10:14 - Ctx( /shona ): Exception in: R( /shona + /servlets/photo + null) 
- javax.servlet.ServletException: SQL error
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:121)
        at mbkennedy.pshop.servlets.PhotoServlet.doGet(PhotoServlet.java:141)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.tomcat.core.ServletWrapper.doService(ServletWrapper.java:404)
        at org.apache.tomcat.core.Handler.service(Handler.java:286)
        at org.apache.tomcat.core.ServletWrapper.service(ServletWrapper.java:372)
        at 
org.apache.tomcat.core.ContextManager.internalService(ContextManager.java:797)
        at org.apache.tomcat.core.ContextManager.service(ContextManager.java:743)
        at 
org.apache.tomcat.service.http.HttpConnectionHandler.processConnection(HttpConnectionHandler.java:210)
        at org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
        at org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
        at java.lang.Thread.run(Thread.java:536)
Caused by: No results were returned by the query.
        at org.postgresql.jdbc2.Statement.executeQuery(Unknown Source)
        at org.postgresql.jdbc2.PreparedStatement.executeQuery(Unknown Source)
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:81)
        ... 12 more
2002-03-10 02:10:44 - Ctx( /shona ): Exception in: R( /shona + /servlets/photo + null) 
- javax.servlet.ServletException: SQL error
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:121)
        at mbkennedy.pshop.servlets.PhotoServlet.doGet(PhotoServlet.java:141)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.tomcat.core.ServletWrapper.doService(ServletWrapper.java:404)
        at org.apache.tomcat.core.Handler.service(Handler.java:286)
        at org.apache.tomcat.core.ServletWrapper.service(ServletWrapper.java:372)
        at 
org.apache.tomcat.core.ContextManager.internalService(ContextManager.java:797)
        at org.apache.tomcat.core.ContextManager.service(ContextManager.java:743)
        at 
org.apache.tomcat.service.http.HttpConnectionHandler.processConnection(HttpConnectionHandler.java:210)
        at org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
        at org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
        at java.lang.Thread.run(Thread.java:536)
Caused by: No results were returned by the query.
        at org.postgresql.jdbc2.Statement.executeQuery(Unknown Source)
        at org.postgresql.jdbc2.PreparedStatement.executeQuery(Unknown Source)
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:81)
        ... 12 more
2002-03-10 02:11:29 - Ctx( /shona ): Exception in: R( /shona + /servlets/photo + null) 
- javax.servlet.ServletException: SQL error
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:121)
        at mbkennedy.pshop.servlets.PhotoServlet.doGet(PhotoServlet.java:141)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.tomcat.core.ServletWrapper.doService(ServletWrapper.java:404)
        at org.apache.tomcat.core.Handler.service(Handler.java:286)
        at org.apache.tomcat.core.ServletWrapper.service(ServletWrapper.java:372)
        at 
org.apache.tomcat.core.ContextManager.internalService(ContextManager.java:797)
        at org.apache.tomcat.core.ContextManager.service(ContextManager.java:743)
        at 
org.apache.tomcat.service.http.HttpConnectionHandler.processConnection(HttpConnectionHandler.java:210)
        at org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
        at org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
        at java.lang.Thread.run(Thread.java:536)
Caused by: FastPath call returned ERROR:  current transaction is aborted, queries 
ignored until end of transaction block
        at org.postgresql.fastpath.Fastpath.fastpath(Unknown Source)
        at org.postgresql.fastpath.Fastpath.fastpath(Unknown Source)
        at org.postgresql.fastpath.Fastpath.getInteger(Unknown Source)
        at org.postgresql.largeobject.LargeObject.<init>(Unknown Source)
        at org.postgresql.largeobject.LargeObjectManager.open(Unknown Source)
        at org.postgresql.largeobject.PGblob.<init>(Unknown Source)
        at org.postgresql.jdbc2.ResultSet.getBlob(Unknown Source)
        at org.postgresql.jdbc2.ResultSet.getBlob(Unknown Source)
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:104)
        ... 12 more
2002-03-10 02:11:52 - Ctx( /shona ): Exception in: R( /shona + /servlets/photo + null) 
- javax.servlet.ServletException: SQL error
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:121)
        at mbkennedy.pshop.servlets.PhotoServlet.doGet(PhotoServlet.java:141)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.tomcat.core.ServletWrapper.doService(ServletWrapper.java:404)
        at org.apache.tomcat.core.Handler.service(Handler.java:286)
        at org.apache.tomcat.core.ServletWrapper.service(ServletWrapper.java:372)
        at 
org.apache.tomcat.core.ContextManager.internalService(ContextManager.java:797)
        at org.apache.tomcat.core.ContextManager.service(ContextManager.java:743)
        at 
org.apache.tomcat.service.http.HttpConnectionHandler.processConnection(HttpConnectionHandler.java:210)
        at org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
        at org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
        at java.lang.Thread.run(Thread.java:536)
Caused by: FastPath call returned ERROR:  current transaction is aborted, queries 
ignored until end of transaction block
        at org.postgresql.fastpath.Fastpath.fastpath(Unknown Source)
        at org.postgresql.fastpath.Fastpath.fastpath(Unknown Source)
        at org.postgresql.fastpath.Fastpath.getInteger(Unknown Source)
        at org.postgresql.largeobject.LargeObject.<init>(Unknown Source)
        at org.postgresql.largeobject.LargeObjectManager.open(Unknown Source)
        at org.postgresql.largeobject.PGblob.<init>(Unknown Source)
        at org.postgresql.jdbc2.ResultSet.getBlob(Unknown Source)
        at org.postgresql.jdbc2.ResultSet.getBlob(Unknown Source)
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:104)
        ... 12 more
2002-03-10 02:11:53 - Ctx( /shona ): Exception in: R( /shona + /servlets/photo + null) 
- javax.servlet.ServletException: SQL error
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:121)
        at mbkennedy.pshop.servlets.PhotoServlet.doGet(PhotoServlet.java:141)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.tomcat.core.ServletWrapper.doService(ServletWrapper.java:404)
        at org.apache.tomcat.core.Handler.service(Handler.java:286)
        at org.apache.tomcat.core.ServletWrapper.service(ServletWrapper.java:372)
        at 
org.apache.tomcat.core.ContextManager.internalService(ContextManager.java:797)
        at org.apache.tomcat.core.ContextManager.service(ContextManager.java:743)
        at 
org.apache.tomcat.service.http.HttpConnectionHandler.processConnection(HttpConnectionHandler.java:210)
        at org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
        at org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
        at java.lang.Thread.run(Thread.java:536)
Caused by: No results were returned by the query.
        at org.postgresql.jdbc2.Statement.executeQuery(Unknown Source)
        at org.postgresql.jdbc2.PreparedStatement.executeQuery(Unknown Source)
        at mbkennedy.pshop.servlets.PhotoServlet.processRequest(PhotoServlet.java:81)
        ... 12 more
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
<HTML>
<HEAD><TITLE>An Error Occurred</TITLE></HEAD>
<BODY>
<H1>An Error Occurred</h1>
500 Internal Server Error
</BODY>
</HTML>
      0
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
<HTML>
<HEAD><TITLE>An Error Occurred</TITLE></HEAD>
<BODY>
<H1>An Error Occurred</h1>
500 Internal Server Error
</BODY>
</HTML>
      0
<HTML>
<HEAD><TITLE>An Error Occurred</TITLE></HEAD>
<BODY>
<H1>An Error Occurred</h1>
500 Internal Server Error
</BODY>
</HTML>
      0
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
   3635
<HTML>
<HEAD><TITLE>An Error Occurred</TITLE></HEAD>
<BODY>
<H1>An Error Occurred</h1>
500 Internal Server Error
</BODY>
</HTML>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Created by mkennedy on February 13, 2002, 3:57 PM -->
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
    "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd";>
<struts-config>
    <data-sources>
        <data-source id="default" key="default">
            <set-property property="driverClass" value="org.postgresql.Driver"/>
            <set-property property="user" value="mkennedy"/>
            <set-property property="password" value=""/>
            <set-property property="url" value="jdbc:postgresql://localhost/pshop"/>

            <set-property property="autoCommit" value="false"/>
            <set-property property="description" value="PostgreSQL"/>
            <set-property property="maxCount" value="1"/>
            <set-property property="minCount" value="0"/>
        </data-source>
    </data-sources>
       
    <global-forwards>
        <forward name="index" path="/index.jsp"/>
    </global-forwards>
</struts-config>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Created by mkennedy on February 13, 2002, 3:57 PM -->
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd";>
<web-app>
    <!-- Action Servlet Configuration -->
    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>mbkennedy.pshop.ApplicationResources</param-value>
        </init-param>
        <init-param>
            <param-name>config</param-name>
            <param-value>/WEB-INF/struts-config.xml</param-value>
        </init-param>
        <init-param>
            <param-name>debug</param-name>
            <param-value>2</param-value>
        </init-param>
        <init-param>
            <param-name>detail</param-name>
            <param-value>2</param-value>
        </init-param>
        <init-param>
            <param-name>validate</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>photo</servlet-name>
        <servlet-class>mbkennedy.pshop.servlets.PhotoServlet</servlet-class>
        <init-param>
            <param-name>bufferSize</param-name>
            <param-value>8192</param-value>
        </init-param>
    </servlet>
    
    <!-- Action Servlet Mapping -->
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>photo</servlet-name>
        <url-pattern>/servlets/photo</url-pattern>
    </servlet-mapping>
        
    <!-- The Welcome File List -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- Application Tag Library Descriptor -->
    <taglib>
        <taglib-uri>/tags/application.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/appilcation/application.tld</taglib-location>
    </taglib>

    <!-- Struts Tag Library Descriptors -->
    <taglib>
        <taglib-uri>/tags/struts.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/struts/struts.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>/tags/struts-bean.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/struts/struts-bean.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>/tags/struts-form.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/struts/struts-form.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>/tags/struts-logic.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/struts/struts-logic.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>/tags/struts-html.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/struts/struts-html.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>/tags/struts-template.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/struts/struts-template.tld</taglib-location>
    </taglib>

    <!-- DBTags Tag Library Descriptor -->
    <taglib>
        <taglib-uri>/tags/dbtags.tld</taglib-uri>
        <taglib-location>/WEB-INF/tld/dbtags.tld</taglib-location>
    </taglib>
</web-app>

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to