JDev11.1.2.1.0: Handling images/files in ADF (Part 2)

This blog article is part 2 of a series of posts showing how to deal with images or files in an ADF application. Each of the techniques to do this are described in other blog posts or documents, but I couldn’t find a sample doing it all together in on sample application.
The goal of this series is to provide a sample showing how to upload a file from a client to the server, store the data on the server, make it available for later retrieval and show the data in the user interface (form and table).

    Part 1 gives an overview of the sample application I’m going to build and how to set it up
    Part 2 shows how to upload a file, store it and download it back to the client
    Part 3 implements two techniques to show the data (image) on the user interface
    Part 4 backport of the sample to JDeveloper 11gR1
    Part 5 implements a technique to show the uploaded file right after upload without the need to commit first


Uploading, downloading and storing of data in a blob

In this part of the series I show how to upload a file from the client to the server and store the data in a blob column in a db. The tables I’m using are CATALOG and IMAGES. The DML to define the tables and can be found in PART 1 of the series or in the sample workspace at the end of this part.
Lets start with uploading a file from client to the server. ADF rich faces provide the tag af:inputFile to allow uploading of data.

<af:inputFile label="Select new file" id="if1" autoSubmit="true"
              valueChangeListener="#{ImageBean.uploadFileValueChangeEvent}"/>

As you see the tag has set its autoSubmit property to true to allow direct upload of data. The real work is done in the valueChangeListener which is bound to a backing bean in request scope. The value the event carries allows access to the data and give us the original filename and mime type.

    public void uploadFileValueChangeEvent(ValueChangeEvent valueChangeEvent)
    {
        // The event give access to an Uploade dFile which contains data about the file and its content
        UploadedFile file = (UploadedFile) valueChangeEvent.getNewValue();
        // Get the original file name
        String fileName = file.getFilename();
        // get the mime type 
        String contentType = ContentTypes.get(fileName);
        // get the current roew from the ImagesView2Iterator via the binding
        DCBindingContainer lBindingContainer =
            (DCBindingContainer) BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding lBinding = lBindingContainer.findIteratorBinding("ImagesView2Iterator");
        Row newRow = lBinding.getCurrentRow();
        // set the file name
        newRow.setAttribute("ImageName", fileName);
        // create the BlobDomain and set it into the row
        newRow.setAttribute("ImageData", createBlobDomain(file));
        // set the mime type
        newRow.setAttribute("ContentType", contentType);
    }

    private BlobDomain createBlobDomain(UploadedFile file)
    {
        // init the internal variables
        InputStream in = null;
        BlobDomain blobDomain = null;
        OutputStream out = null;

        try
        {
            // Get the input stream representing the data from the client
            in = file.getInputStream();
            // create the BlobDomain datatype to store the data in the db
            blobDomain = new BlobDomain();
            // get the outputStream for hte BlobDomain
            out = blobDomain.getBinaryOutputStream();
            // copy the input stream into the output stream
            /*
             * IOUtils is a class from the Apache Commons IO Package (http://www.apache.org/)
             * Here version 2.0.1 is used
             * please download it directly from http://projects.apache.org/projects/commons_io.html
             */ 
            IOUtils.copy(in, out);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (SQLException e)
        {
            e.fillInStackTrace();
        }

        // return the filled BlobDomain
        return blobDomain;
    }

Please note the I use the Apache Commons IO package in the version 2.0.1 which you need to download from the Apache Software Foundation web side. The use the class IOUtils which allow easy copying of streams.
If your are using an older version of JDeveloper you may need to add the usesUpload property to the af:form tag. In the current JDev version it should work automatically (but please check it).

<af:form id="f1" usesUpload="true">

If you use fragments (as in this sample) you need to check the jspx or jsf page which is holding the af:form tag (Catalog.jsf), as the fragments don’t have a form tag.
By default, Oracle ADF 11g application allows to upload maximum 2 MB size files. This maximum can be configured in the web.xml file if you need to upload files bigger then 2 MB. For this you need to specify the context parameters

    org.apache.myfaces.trinidad.UPLOAD_MAX_MEMORY
    org.apache.myfaces.trinidad.UPLOAD_MAX_DISK_SPACE
    org.apache.myfaces.trinidad.UPLOAD_TEMP_DIR

For more information about the parameters and how they work check the doc Oracle® Fusion Middleware Web User Interface Developer’s Guide for Oracle Application Development Framework.

Now to the download part. This is handled in ADF via the af:fileDownloadActionListener tag. The tag is a client listener tag and is therefor applied to a command ui tag. In the sample I use a af:commandButton:

<af:commandButton text="Download Data" id="cb3"
                  visible="#{bindings.ImageData.inputValue ne null}"
                  binding="#{ImageBean.downloadButton}">
          <af:fileDownloadActionListener contentType="#{bindings.ContentType.inputValue}"
                                         filename="#{bindings.ImageName.inputValue}"
                                         method="#{ImageBean.downloadImage}"/>
</af:commandButton>

The real work is done in the downloadImage method in the managed bean. The signature of the method is

public void downloadImage(FacesContext facesContext, OutputStream outputStream)

This allows you to access to the FacesContext and the output stream which you use to pipe the data to the client.

    public void downloadImage(FacesContext facesContext, OutputStream outputStream)
    {
        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();

        // get an ADF attributevalue from the ADF page definitions
        AttributeBinding attr = (AttributeBinding) bindings.getControlBinding("ImageData");
        if (attr == null)
        {
            return;
        }

        // the value is a BlobDomain data type
        BlobDomain blob = (BlobDomain) attr.getInputValue();

        try
        {   // copy hte data from the BlobDomain to the output stream 
            IOUtils.copy(blob.getInputStream(), outputStream);
            // cloase the blob to release the recources
            blob.closeInputStream();
            // flush the outout stream
            outputStream.flush();
        }
        catch (IOException e)
        {
            // handle errors
            e.printStackTrace();
            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), "");
            FacesContext.getCurrentInstance().addMessage(null, msg);
        }
    }

This is all you need to do to download a blob from the db and send it back to the client.

I like to mention one other function of the sample application. If you hit the ‘Cancel’ button in the insert or edit image page I use a rollback to get the original data back and remove all changes made in the form. A rollback resets all current row pointers of the iterators. To avoid that the user sees the first row of the catalog table the rollback has to be handled in a special way. You have to save the current row (of the catalog iterator), do the rollback and reset the current row back to the saved one. This is done in the bean method

public String cancel_action() {...}

which you find in the ImageBean class.

This concludes part 2. In part three I implement two techniques to show the data (image) on the user interface (page)

The sample application workspace is build with JDeveloper 11.1.2.1.0 and can be loaded from here BlogUploadDownload_P2.zip
Please rename the file to ‘.zip’ after downloading it!
The Commons IO package in the version 2.0.1 you can download from the Apache Software Foundation apache web side

To be continued…

18 thoughts on “JDev11.1.2.1.0: Handling images/files in ADF (Part 2)

  1. Dear Timo :
    How can i install the commons-io-2.3 after i download it in my ADF Application

    best regards

  2. Hi Timo,
    I am following the same steps for downloading blob file from DB.File downloads successfully , but on browser process does not stop. It shows processing icon on screen.
    Can you tell me what is going
    wrong?

  3. Hi Timo,
    This is excellent.

    1)Can we Hard Code ContentType as MIME or
    2)should we have column content_type in table? How to decide value for content_type for Image or .doc or .zip

    Thanks,
    JIt

    • JIt,
      to answer your questions:
      1) you can hard code the mime type but then your users can only download one type of binary data. The browser uses the MIME type to distinguish the different types of binary data and to select an appropriate plug in of external program to show the data to the user. So hard coding the MIME type isn’t a good idea.
      2) You have to use a db column for the content type if you calculate the content type each time you need if. I personally find it easier to store it in a DB column as I then can access it with the data and don’t need to calculate the MIME type on the fly. If you lok into the sample application you’ll find the class ContentTypes (in package BlogUploadDownload\ULDLViewController\src\de\hahn\blog\uldl\view\util) which gets a file name an calculates the MIME type from the extension of the file name.

  4. Pingback: Importing BlobDomain package not found | BlogoSfera

  5. Hi Timo,
    I had followed your samples and implemented the same file upload and download in my application. In weblogic it was running properly but coming to websphere server the download was not working and it was throwing errors saying “org/apache/commons/io/IOUtils” and “The file was not downloaded or was not downloaded correctly”.. Pleas suggest your views on this

    • Have you downloaded the Commons io library and deployed it together with your application?
      Apparently the server can’t find the class.

  6. in continuation to above comment the below is the stack trace and the issue with below line
    IOUtils.copy(blob.getInputStream(), outputStream);

    The stack trace
    used by: java.lang.NoClassDefFoundError: org.apache.commons.io.IOUtils
    at com.oracle.Test.downloadImage(testController.java:569)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:45)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    at java.lang.reflect.Method.invoke(Method.java:599)
    at org.apache.el.parser.AstValue.invoke(AstValue.java:159)
    … 84 more
    Caused by: java.lang.ClassNotFoundException: org.apache.commons.io.IOUtils
    at java.lang.Throwable.(Throwable.java:80)

  7. Hi Timo,
    After the successful completion of part-2, When I press the commit button after browsing a image it will give the following error in a popup .
    Help me please …
    Cannot create an object of type:java.sql.Blob from type:oracle.jbo.domain.BlobDomain with value:ÿØÿàJFIF“ÿá`ExifII*1&i‡.Picasa�0220 \ êÿÛC

    ÿÛCÿÀê\”ÿÄ ÿĵ}!1AQa”q2�‘¡#B±ÁRÑð$3br‚ %&’()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×ØÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq”2�B‘¡±Á #3RðbrÑ $4á%ñ&’()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×ØÙÚâãäåæçèéêòóôõö÷øùúÿÚ?ý½ñoÆ[isÝݺE
    ²—vcŒëÏnõñ¯í)ûfø»â=õÆ�§]Üø{FC…ŽÒfŽk¡�C<¨Cãî©uÍKûPxæoÌtXnZ5‹6›ÐŽãâvöZ½¼%ˆ�B¬W·~ŸÊ¾ï†r*u"«×Wì�ÅüCã*ô*<
    ¸Ûy-ý<†Ý^]ÙèÖþ|ª²ÊÒ¤AˆÛ“�ÛzòÚMrm+I�æ¸�Û´;Z=çænqù Ä·ÓškÉf»™¥áK•óšâÒ|F‘“•Øx*Töäûu®sFÐSKø{k¥ÚùÓÙÚ•)mŒcbŽ (« ãMÒ¤ó‚ÎŒàí;v•èsÏ\T3ؽƒ<ö)‰³�Ì09û§žF+'…Ã7ïA?’6xìÍE8ÊJ/ÍÝ0ð¶£u£æ¥Äñª«\¹sžäŸþµ^ðåÝÔÑß¼™€Á‹’‰Ï_ï¯åXšý¼øûNµ¤B|å®á@½ŽrØþ˜­ÖtÛ[;ËTÔ,"hÓ µÜAÝóóù¾^ýxR�
    Thanks,

  8. Pingback: Handling images/files in ADF (Part 5) | JDev & ADF Goodies

  9. Pingback: JDev11.1.2.1.0: Handling images/files in ADF (Part 3) | JDev & ADF Goodies

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.