views:

200

answers:

1

In my JSP/HTML files i use the following servlet to get blob-images from the MySQL-database.

<img src="/image?id=1" />

Image servlet

This is mapped to a imageservlet, who:
- gets a stateless session-bean injected
- uses the session-bean to lookup a product, based on the id passed in to the servlet
- streams this image out as the response

public class Image extends HttpServlet {

    @EJB
    private ProductLocal productBean;

    protected void processRequest(HttpServletRequest request, 
        HttpServletResponse response) throws ServletException, IOException {
    long id = 0;
    Product product = null;

    String possibleID = request.getParameter("id");
    if(possibleID == null){
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }

    // Try to parse id
    try{
        id = Long.parseLong(possibleID);
        product = productBean.getById(id);
        if(product == null) throw new NullPointerException("Product not found");
    } catch(NumberFormatException e){
        response.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return;
    } catch(NullPointerException e){
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }

    // Serve image
    byte[] image = product.getImage();
    response.setContentType(product.getImageContentType());
    response.setContentLength(image.length);
    ServletOutputStream output = response.getOutputStream();

    for(int i = 0; i < image.length; i++){
        output.write(image[i]);
    }
    output.flush();
    output.close();
} 
}

ProductBean:

@Stateless
public class ProductBean implements ProductLocal {

    @PersistenceContext(unitName="xxx")
    private EntityManager em;

    public Product getById(long id) {
        return em.find(Product.class, id);
    }

}

Product (Entity-bean)

@Entity
public class Product implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Lob
    private byte[] image;

    private String imageContentType;

    /* getters and setters */
}

The problem

When iterating over a page of products, say 15, the servlet gets called 15 times and I consequently get the same result (although with different order on the IDs):

alt text

Some images always hang until they time out (15 sec. shown in firebug above). The server is Glassfish v2.1 (integrated in Netbeans 6.7.1). At first the timeout was 30 sec, so I started setting different timeout values in Glassfish to narrow the problem. One of these timeouts were HttpService -> Keep Alive -> Timeout, which I sat (as the only one) to 15 sec. After restarting GF, firebug now reports the timeout after 15 sec. instead of the default 30. Since I put different timeouts in GF, I'm pretty sure the problem is related to Keep-Alive. Here is the rest of my settings in this tab:

alt text

This is out of the box configuration from the version bundled with NetBeans, and I haven't done anything besides changing the timeout value. My question: is this caused by wrong settings in Glassfish, or problems with my ImageServlet or other code?

A: 

This could be related to the fact that your EJB instance retrieved in the Servlet is locking somehow other threads making requests to the same servlet. I have a couple of suggestions:

1) To know the exact answer you should take a thread dump and then you will see which thread is holding back others or what threads are busy doing.

2) Another idea is to try to retrieve EJB instance on each request. It's, of course, not the perfect solution, but maybe it will save you from some locking issues you may have. If it helps, then you can introduce a pool of EJBs latter. But in any case I would suggest going the first path to have more information on what is going on.

Superfilin
Fetching the bean inside each request (inside doGet) didn't seem to make a difference. I tried to take a thread dump, but have never done so before. I'm using OSX, and tried "kill -3 <pid>" as the Glassfish manual suggest, but nothing appeared in the domain1/logs. I sucessfully ran the profiler from NetBeans, but I'm not sure what to look for. The threads waiting were a bunch of timers, and "MySQL cancelation request"
Mads Mobæk
Look at the locks. May be if you can attach a couple of picture from the profiler it will be easier to say something.
Superfilin