Home » General

Oracle ADF Medior: Rendering images based on BLOB columns

Written By: Pascal Alma on April 22, 2008 One Comment

For my current project we are building an application with Oracle ADF 10.1.3.3 (ADF BC + JSF). One of the functionalities they want is to show images that were stored in a Blob field in the database at a JSF page. After a short search it appeared that this can be rather easily done if the column in the database is of the type ORD_SYS.ORDIMAGE (see Steve's Muench post here).
For a Blob column, however, there isn't a standard way in ADF to do that, so he suggests to make a servlet that renders the image and use that servlet as the 'src' for a image tag. I followed this approach and I made the servlet configurable, so it can generate any kind of file, based on the content of the Blob.
Here is the code for the servlet:

JAVA:
  1. package net.pascalalma.view.servlet;
  2.  
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.OutputStream;
  6.  
  7. import java.util.Iterator;
  8. import java.util.Map;
  9.  
  10. import javax.servlet.ServletConfig;
  11. import javax.servlet.ServletException;
  12. import javax.servlet.http.HttpServlet;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15.  
  16. import oracle.jbo.ApplicationModule;
  17. import oracle.jbo.Row;
  18. import oracle.jbo.ViewObject;
  19. import oracle.jbo.client.Configuration;
  20. import oracle.jbo.domain.BlobDomain;
  21.  
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24.  
  25. /**
  26. * Use like:
  27. * <af:image source="/urlToServlet?someParam=#{bindings.someValue}"/>
  28. * @author Pascal Alma
  29. */
  30. public class ImageServlet extends HttpServlet
  31. {
  32.   private static final Log LOG = LogFactory.getLog(ImageServlet.class);
  33.  
  34.   public void init(ServletConfig config)
  35.     throws ServletException
  36.   {
  37.     super.init(config);
  38.   }
  39.  
  40.   public void doGet(HttpServletRequest request,
  41.                     HttpServletResponse response)
  42.     throws ServletException, IOException
  43.   {
  44.     String appModuleName = this.getServletConfig().getInitParameter("ApplicationModuleName");
  45.     String appModuleConfig = this.getServletConfig().getInitParameter("ApplicationModuleConfig");
  46.     String voQuery = this.getServletConfig().getInitParameter("ImageViewObjectQuery");
  47.     String mimeType = this.getServletConfig().getInitParameter("MimeType");
  48.    
  49.     //TODO: throw exception if mandatory parameter not set
  50.            
  51.     ApplicationModule am =
  52.       Configuration.createRootApplicationModule(appModuleName, appModuleConfig);
  53.     ViewObject vo =  am.createViewObjectFromQueryStmt("TempView", voQuery);
  54.    
  55.     Map paramMap = request.getParameterMap();
  56.     Iterator paramValues = paramMap.values().iterator();
  57.     int i=0;
  58.    
  59.     while (paramValues.hasNext())
  60.     {
  61.       // Only one value for a parameter is expected.
  62.       // TODO: If more then 1 parameter is supplied make sure the value is bound to the right bind   
  63.       // variable in the query! Maybe use named variables instead.
  64.       String[] paramValue = (String[])paramValues.next();
  65.       vo.setWhereClauseParam(i, paramValue[0]);
  66.       i++;
  67.     }
  68.     // Run the query
  69.     vo.executeQuery();
  70.     // Get the result (only the first row is taken into account
  71.     Row product = vo.first();
  72.    
  73.     BlobDomain image = null;
  74.     // Check if a row has been found
  75.     if (product != null)
  76.     {
  77.        // We assume the Blob to be the first a field
  78.        image = (BlobDomain) product.getAttribute(0);
  79.  
  80.        // Check if there are more fields returned. If so, the second one
  81.        // is considered to hold the mime type
  82.        if ( product.getAttributeCount()> 1 )
  83.        {
  84.           mimeType = (String)product.getAttribute(1);
  85.        }
  86.     }
  87.     else
  88.     {
  89.       LOG.warn("No row found to get image from !!!");
  90.       return;
  91.     }
  92.    
  93.     // Set the content-type. Only images are taken into account
  94.     response.setContentType("image/"+ mimeType+ "; charset=windows-1252");
  95.     OutputStream os = response.getOutputStream();
  96.     InputStream is = image.getInputStream();
  97.  
  98.     // copy blob to output
  99.     byte[] buffer = new byte[4096];
  100.     int nread;
  101.     while ((nread = is.read(buffer)) != -1)
  102.     {
  103.       os.write(buffer, 0, nread);
  104.     }
  105.     os.close();
  106.    
  107.     // Remove the temporary viewobject
  108.     vo.remove();
  109.     // Release the appModule
  110.     Configuration.releaseRootApplicationModule(am, false);
  111.   }
  112. }

As you can see there might be some loose ends in the servlet code, but if you keep it rather simple (only 1 parameter for the query) the servlet will do its job.

Here is how you can configure the servlet in your application's web.xml:

XML:
  1. <servlet-name>images</servlet-name>
  2.     <servlet-class>net.pascalalma.view.servlet.ImageServlet</servlet-class>
  3.     <init-param>
  4.       <param-name>ApplicationModuleName</param-name>
  5.       <param-value>net.pascalalma.model.services.MyService</param-value>
  6.     </init-param>
  7.     <init-param>
  8.       <description>The query that will select the image field. Second field might be selected
  9.       as mime type. Only the first row of the result will be taken into account</description>
  10.       <param-name>ImageViewObjectQuery</param-name>
  11.       <param-value>select image_file from my_images where image_id = ?</param-value>
  12.     </init-param>
  13.     <init-param>
  14.       <description>Configuration to be used</description>
  15.       <param-name>ApplicationModuleConfig</param-name>
  16.       <param-value>MyServiceLocal</param-value>
  17.     </init-param>
  18.     <init-param>
  19.        <description>Optional. If not set here, the second column in the query will be considered to
  20.                          contain the mime type!</description>
  21.        <param-name>MimeType</param-name>
  22.        <param-value>gif</param-value>
  23.      </init-param>
  24.   </servlet>
  25.   <servlet-mapping>
  26.     <servlet-name>images</servlet-name>
  27.     <url-pattern>/render_image</url-pattern>
  28.   </servlet-mapping>

And this is how you would make the images appear on your page:

XML:
  1. <af:objectImage source="/render_image?img_id=#{row.ImageId}"/>

where #{row.ImageId} refers to an id of a record in the my_images table.

Although it might not be exactly what you need, I hope it gives you enough ideas to create a servlet that meets your wishes.

Tags: ,

Digg this!Add to del.icio.us!Stumble this!Add to Techorati!Share on Facebook!Seed Newsvine!Reddit!Add to Yahoo!

One Response to “Oracle ADF Medior: Rendering images based on BLOB columns”

  1. Hatem said:

    perfect !!!!!

Copyright © 2009 Pascal’s Blog, All rights reserved.| Powered by WordPress