Chapter 9. J2EE/ADF Application Development

Introduction

This chapter will introduce the development of applications using J2EE technologies, such as Java, Java Server Pages (JSP), and Java Server Faces (JSF), as well as Oracle’s Application Development Framework (ADF).

Oracle’s Application Development Framework (ADF) is a collection of technologies that can be used to automate the complexities of developing an application using J2EE’s model-view-controller (MVC) design paradigm. This allows the developer to concentrate on the business logic. ADF is based on proven J2EE technologies, such as Java Server Faces (JSF), and business components from previous versions of Oracle JDeveloper.

Development of a rich-media application using Java and J2EE technologies is much quicker and easier with the use of an integrated development environment (IDE) such as JDeveloper. This is especially true when the IDE includes wizards to access media data. However, some may choose, for various reasons, not to use an IDE for development. For this reason, this chapter will show how an IDE can be used for interMedia data as well as plain code samples. The reason for this is that the concepts presented here can be used for multiple J2EE IDEs as well as for those developing J2EE applications without the use of an IDE.

Some may choose to use plain Java applications to access media, while others will integrate this media access into JSP pages. The choice of using plain Java or JSP technology is typically one made outside of the question of where the media is going to be managed. The concepts in this chapter are how to use these J2EE technologies to use media professionally managed in the database using these technologies.

Application Development Framework

To make J2EE development simpler and more accessible, Oracle JDeveloper introduces the Oracle Application Development Framework (Oracle ADF), a J2EE development framework based on the model-view-controller (MVC) architecture that implements design patterns and eliminates infrastructure coding. Oracle ADF has four layers:

  1. The business services layer—provides access to data from various sources and handles business logic.

  2. The model layer—provides an abstraction layer on top of the business services layer, enabling the view and controller layers to work with different implementations of business services in a consistent way.

  3. The controller layer—provides a mechanism to control the flow of the Web application.

  4. The view layer—provides the user interface to the application.

Oracle ADF integrates seamlessly with interMedia at all layers, thus providing great flexibility and simplicity in the way in which developers can create media-rich Java applications.

On the business services layer, developers can drag and drop tables from the database browser onto the UML diagram to generate business services that provide Java interfaces to these tables. interMedia object types are automatically recognized by Oracle ADF and corresponding domain classes are created on this layer. The same mechanism also makes the interMedia object transparent in the drag-and-drop operations on the model layer and the controller layer.

On the view layer, developers can create a media-rich JSP/UIX application as any other JSP/UIX application by the drag-and-drop business services component from JDeveloper Data Control Palette. Render value tag and input render tag will automatically bind user interface components with interMedia domain objects so that users are able to view, insert, update, and delete multimedia content just like handling other textual data in the JSP/UIX application. The developers can debug or run the JSP/UIX application from inside the JDeveloper. When the development work is done, the developers can deploy the JSP/UIX application to an application server in the form of WAR file or EAR file from the JDeveloper.

Finally, developers can choose to program directly against the underlying interMedia ADF Integration Package. The interMedia ADF Integration Package includes the interMedia ADF domain classes and a set of utility classes. The OrdImageDomain, OrdAudioDomain, OrdVideoDomain, and OrdDocDomain interMedia ADF domain classes are available since Release 9i of JDeveloper. These domain classes are wrappers of the interMedia Java Client classes described earlier and inherit all the underlying multimedia retrieval, upload, and manipulation methods.

The interMedia business components domain classes support the DomainOwnerInterface, LobInterface, AttributeList, and XMLDomainInterface of the Oracle ADF, and so provide built-in, integrated multimedia capabilities. The utility classes support the retrieval, rendering, and uploading of multimedia content. For example, any application can use the interMedia ADF domain classes to facilitate uploading multimedia into the database. Servlet and JSP applications can use the OrdURLBuilder and OrdPlayMedia classes to build URLs and retrieve multimedia content from the database. OrdURLBuilder constructs URLs that locate interMedia objects using the ADF run-time framework, while OrdPlayMedia interprets the URLs to fetch the interMedia content from the database and deliver it to the browser.

To illustrate this point, we will take the steps necessary to create a very simple media application using JDeveloper ADF.

Creating the Model Component

To create a model component to interface to the database and retrieve and upload media from the photos table that was created in previous samples, business components are used.

To create the model, we must first create an application and database connection. This is accomplished using simple wizards. The Database Connection connects to a database where the photos table was created.

After creating a JDeveloper application and database connection, we create a project to hold the model and use a JDeveloper wizard to create the model. In the General category, Projects or ADF Business Components is selected. We choose Business Components to create a component that can retrieve/insert data from/to a database table. See Figure 9.1.

Creating the Database Connection

Figure 9.1. Creating the Database Connection

After naming the model project “MediaProject” we accept the defaults in the next screen that specifies the paths. After the second step in creating the project, the following screen shown in Figure 9.2 is displayed to guide us through creating the business object from database tables. In this screen we choose the database connection we had defined previously.

Business Component Initialization

Figure 9.2. Business Component Initialization

After defining the connection to use, it is time to select the table to build the business component to use. JDeveloper displays a list of database tables when the Tables object type checkbox is selected. The photos table is selected by identifying the object type as a table and selecting the Photos table, as shown in Figure 9.3

Create Business Component Step 1

Figure 9.3. Create Business Component Step 1

The next step is to create an Updatable View Object (Figure 9.4). This updatable view business object allows for a view that can be updated by the application. The following step would be to create read-only view objects that we will skip.

Creating Business Component Step 2

Figure 9.4. Creating Business Component Step 2

After skipping the read-only object view selection, we take the defaults on the next screen that define the package and application module name. On the last screen of this wizard, we can optionally create a business components diagram of this module. This can be useful to understand the configuration of the business object. We choose to create a diagram.

At this point, we have created a business object that can be used by a model component.

 

Creating the Controller and View Components

To create a JSF application, we use the JDeveloper. First an empty project is created and then we create a new JSF page control and configuration (faces configuration) into the project. This controller will handle the control component of the JSF application. After these steps, JDeveloper has the appearance shown in Figure 9.5.

Initial Component Diagram

Figure 9.5. Initial Component Diagram

After creation of the faces configuration file, named faces-config.xml by default, JDeveloper immediately brings the faces configuration file to the foreground and displays it in a Design GUI. To see the actual XML source code, you can press the source tab at the lower portion of the center screen. At this point, there is no actual content in the JSF application, so the Design GUI is empty.

On the upper right side there is a Palette that contains components. Using the mouse, drag a JSF page component from the Palette onto the Design screen. At this point the Design screen contains a page that will be invoked by the JSF controller. We double click on the page to bring up the Create JSF JSP wizard. On the second screen of the wizard the newly created JSP is named browse.jsp, as shown in Figure 9.6.

Create JSF JSP Step 1

Figure 9.6. Create JSF JSP Step 1

After this page of the wizard, we take the defaults for the next screen and then continue to choose the tag libraries we will use. We choose the tag libraries illustrated in Figure 9.7.

Create JSF JSP Step 2

Figure 9.7. Create JSF JSP Step 2

Then, click Finish to take the rest of the defaults for this new JSP page. In a real application, we would at least review and verify the default choices, and perhaps change them to what the development environment requires.

After creation of the JSF page, we place it within a JSP Editor. From our Palette, we choose data controls, expand AppModuleDataControl, and locate the PhotosView1 component. This component is dragged onto the JSP screen. A dialog appears, and we choose Create->Table->ADF Read-Only Form. A dialog appears to let us choose which columns will appear on the screen. For this example, the only image we want to display is the thumbnail image in the table, since it will display a list. We could, and should, show the full size image in a real application by creating a link on this page to a detail page. We will display all the text fields, as well as the thumbnail image.

We delete the Image column, and are left with the rest of the columns. We also want some navigation and a submit button, so we check these items. Figure 9.8 shows the state before we continue.

JSF JSP Form Fields

Figure 9.8. JSF JSP Form Fields

At this point, the design screen has the appearance shown in Figure 9.9.

JSP Form Design

Figure 9.9. JSP Form Design

We will be concerned with the row called Thumb. This row needs to be rendered as an image rather than text. Before we can render this as an image, we will need to configure the page to be able to render the thumbnail as an image. This involves the following steps:

  1. Changing the binding of Thumb to use the OrdValueHandler in the page definition file.

  2. Creating a servlet endpoint for the handler to use to get or put media in interMedia objects.

  3. Changing the JSP page to use OrdValueHandler.

For the first set, we use the navigator on the left side to expand the application sources in MyJMFProject. In the list is a package called myjmfproject.pageDefs. This project includes definitions for each of the JSF pages in the project. After expanding the myjmfproject.pageDefs project and opening browsePageDef.xml, we can see the definitions for each of the fields. The definition that will be modified is highlighted. See Figure 9.10.

Figure 9.10. 

The highlighted definition for Thumb will be a custom input handler set to OrdDomainValueHandler. After this change, the XML segment describing Thumb will be the following:

<attributeValues id="Thumb" IterBinding="PhotosView1Iterator"
    CustomInputHandler="OrdDomainValueHandler">
  <AttrNames>
    <Item Value="Thumb"/>
  </AttrNames>
</attributeValues>

At this point, we need to create a servlet endpoint for media requests. The OrdDomainHandler uses the OrdDeliverMedia servlet. Creation of this endpoint is done by modifying web.xml. To open web.xml, use the navigator to expand Web Content and then WEB-INF. Open web.xml. The Following XML segment is added to the XML file to define the servlet that will be used for getting (or putting) media from (or to) the database. This XML segment is placed within the upper-level <web-app> tag. This change needs to only be done once in the project, not like the change of the InputHandler that needs to be done for every page that will want to display media from the database or insert media into the database.

<filter-mapping>
    <filter-name>adfBindings</filter-name>
    <servlet-name>ordDeliverMedia</servlet-name>
</filter-mapping>

<servlet>
     <servlet-name>ordDeliverMedia</servlet-name>
    <servlet-class>oracle.ord.html.OrdPlayMediaServlet</
servlet-class>
    <init-param>
        <param-name>releaseMode</param-name>
        <param-value>Stateful</param-value>
    </init-param>
</servlet>

<servlet-mapping>
     <servlet-name>ordDeliverMedia</servlet-name>
     <url-pattern>ordDeliverMedia</url-pattern>
</servlet-mapping>

At this point, we have to go into the source code of the JSP. Select the tab for browse.jsp. Choose the Source tab at the lower part of the main screen. Find the following code in browse.jsp:

<af:outputText value="#{bindings.Thumb.inputValue}"/>

Change this text to output media with the MIME type of the media with the following objectMedia tag:

<af:objectMedia
source="#{bindings.Thumb.inputValue.source}"

contentType="#{bindings.Thumb.inputValue.media.mimeType}"/>

The ObjectMedia tag has a source, which indicates the source of the data with a URL, and a contentType, that is the MIME type of the media. If the media is an image, an image tag is produced, otherwise an anchor tag is produced (for nonimage media, you should add something within the ObjectMedia tag to click on).

We are nearly there! Now, only one thing is left to be done before we can see the image. We need to add the jar file BC4JHTML.jar to the project. To do this, highlight the MyJMFProject in the navigator, right click on it, and choose Project Properties. Now highlight Libraries and click on the Add Library button. Select BC4JHTML and click OK. Click OK to leave the project properties dialog. We are ready to test the JSP page.

To test browse.jsp, select it in the navigator, right click, and select run. If all went well, you should see something like the screen in Figure 9.11.

Figure 9.11. 

To create a form to edit or create media in the database is quite similar. The differences are:

  • The form must be changed to be of type multipart/form data. This can be done in many ways, like double clicking on the <h:form> element on the lower left. The <h:form> element should end up looking like:

    <h:form enctype=îmultipart/form-data
  • The form field to edit/create the media field must be changed to accept a file. The wizard will put in code that looks like the following:

    <af:inputText value="#{bindings.Image.inputValue}"
     label="#{bindings.Image.label}"
     required="#{bindings.Image.mandatory}"
     columns="#{bindings.Image.displayWidth}">
     <af:validator binding="#{bindings.Image.validator}"/>
    </af:inputText>
  • This should be changed to something like the following that will create a field to accept a filename for update/insert and also display the media when updating an existing record:

    <af:panelLabelAndMessage>
     <af:inputFile value="#{bindings.Image.inputValue}"
    simple="true">
     <af:validator binding="#{bindings.Image.validator}"/>
     </af:inputFile>
     <af:objectMedia source="#{bindings.Image.inputValue.source}"
     contentType="#{bindings.Image.inputValue.media.mimeType}"/>
    </af:panelLabelAndMessage>
    >

interMedia Java Server Pages Tag Library

Oracle interMedia provides a custom Java Server Pages (JSP) tag library that lets users easily generate multimedia HTML tags in Java Server Pages, and upload multimedia data into interMedia objects in the database.

The interMedia JSP tag library is used with Oracle JDeveloper, however, the application can be deployed on the J2EE platform of your choice.

Retrieving Multimedia Data Using the interMedia JSP Tag Library

Oracle interMedia Java Classes for servlets and JSP uses the OrdHttpResponseHandler class to retrieve media data from an Oracle database and deliver it to a browser or other HTTP client from a Java servlet or JSP page.

Multimedia Tag Library provides media retrieval tags, which JSP developers can use to generate complete HTML multimedia tags or create multimedia retrieval URLs for inclusion in the customized use of an HTML multimedia tag. The media retrieval tags are embedAudio, embedImage, embedVideo, and mediaURL.

Example of Retrieving Multimedia Data Using the interMedia JSP Tag Library

The PhotoAlbum.jsp file is one component of a sample JSP application that uses tags from the Multimedia Tag Library to retrieve media data from the database and deliver it to a browser, which displays the media in a simple photograph album application. Example 2-1 shows the tags mediaUrl and embedImage.

The PhotoAlbum.jsp file generates the HTML code that displays the contents of the database table named Photos, including the contents of the description, location, and thumb columns. The contents of the thumb column in the photos table are displayed as thumbnail images that link to the full-size images that are stored in the image column in the Photos Table. From the browser, users can click a thumbnail image to view the full-size image.

[1] <%@ page language="java" %>
[2] <%@ taglib prefix="ord" uri="/Web-inf/intermedia taglib.tld" %>
    <%@ taglib prefix="sql" uri="/web-inf/sqltaglib.tld"

    <%
[3] public static final String escapeHtmlString(String input)
    {
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < input.length(); i++)
        {
            char ch = input.charAt(i);
            switch (ch)
            {
                case '<':
                    sb.append("<");
                    break;

                case '>':
                    sb.append(">");
                    break;
                case '&':
                    sb.append("&");
                    break;
                case '"':
                    sb.append(""");
                    break;
                case ' ':
                    sb.append(" ");
                    break;

                 default:
                    sb.append(ch);
             }

         }

        return sb.toString();
     }
%>
<%-- HTML header --%>
<HTML LANG="EN">
<HEAD>
<TITLE>interMedia JavaServer Pages Photo Album Demo</TITLE>
</HEAD>

<BODY>

   <%-- Page heading --%>
[4] <TABLE BORDER="0" WIDTH="100%">
   <TR>

    <TD COLSPAN="2" BGCOLOR="#F7F7E7" ALIGN="CENTER">
    <FONT SIZE="+2">
      <I>inter</I>Media JavaServer Pages Photo Album Demo
      </FONT>
     </TD>
   </TR>
   </TABLE>

   <P>
   <TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0"
    WIDTH="100%"
     SUMMARY="Table of thumb nail images"<
    <TR BGCOLOR="#336699">
      <TH id="description"><FONT
      COLOR="#FFFFFF">Description</FONT></TH>
      <TH id="location"><FONT COLOR="#FFFFFF">Location
      </FONT></TH>
      <TH id="image"><FONT COLOR="#FFFFFF">Image</FONT></TH>
     </TR>

    <% int rowCount = 0; %>
[5] <sql:dbOpen connId = "myConn" dataSource="jdbc/OracleDS"
    />
      <sql:dbQuery connId = "myConn" queryId="myQuery"
      output="jdbc">

      SELECT id, description, location from photos order by
      description
     </sql:dbQuery>
     <sql:dbNextRow queryId="myQuery">
     <%
[6]    String id = myQuery.getString(1);
       String description = myQuery.getString(2);
       String location = myQuery.getString(3);
     %>
[7]     <TR>
        <TD HEADERS="description">
          <%= escapeHtmlString(description) %>
        </TD>
         <%
          if ( location != null )
             out.print( "<TD HEADERS="location">" +
               escapeHtmlString(location) + "</TD>" );
           else
            out.print( "<TD HEADERS="location"> </TD>"
                      );
         %>

        <TD HEADERS="image">
[8]       <ord:mediaUrl dataSourcename="jdbc/OracleDS"
                           table = "photos"
                           column = "image"
                           key = "<%=id%>"
                           keyColumn = "id"
                           id = "urlId">
[9]        <A HREF="<%= urlId.getUrl()%>">
[10]        <ord:embedImage dataSourceName="jdbc/OracleDS"
                                  table = "photos"
                                  column = "thumb"
                                  key = "<%= id %>"
                                  keyColumn = "id"
                                  alt =
            "<%=escapeHtmlString(description)%>"
                               border="1" />

            </A>
           </ord:mediaUrl>
       </TD></TR>

[11] <% rowCount ++; %>
     </sql:dbNextRow>
     <sql:dbCloseQuery queryId="myQuery"/>
      <sql:dbClose connId="myConn"/>

      <TR>
      <TD SCOPE="col" COLSPAN="3" ALIGN="CENTER">
      <FONT COLOR="#336699"><B><I>
<%
        if (rowCount == 0)
         {
          out.println(" The photo album is empty");
         }
         else
         {
          out.println
        (" Select the thumb-nail to view the full-size image");
         }
 %>
      </I></B></FONT></TD>
     </TR>
<%-- Finish the table --%>
</TABLE>

</P>

 <P>
<TABLE WIDTH="100%">
  <TR BGCOLOR="#F7F7E7">
     <TD COLSPAN="3" ALIGN="CENTER">
       <A HREF="PhotoAlbumUploadForm.jsp">Upload new photo</A>
     </TD>
  </TR>
</TABLE>
</P>

</BODY>
</HTML>

The Java, SQL, and HTML statements in the PhotoAlbum.jsp file perform the following operations:

  1. Declare Java as the script language used in the JSP page. (This line of code is a JSP directive.)

  2. Provide the prefix and uri attributes. The value of the uri attribute indicates the location of the tag library descriptor (TLD) file for the tag library. The prefix attribute (ord) specifies the XML namespace identifier, which should be inserted before each occurrence of the library’s tags in the JSP page. (These two lines of code are Multimedia Tag Library directives.)

  3. Declare a method that provides escape sequences to interpret some commonly used special characters in HTML. (This is called a method declaration statement.)

  4. Use an HTML table to display the entries of the photos table in the database. (This is an HTML program.)

  5. Open the database connection, perform a query on the photos table, and then loop over the retrieved result set.

  6. Retrieve data from the result set.

  7. Begin to display the entries in the table.

  8. Create a script variable named urlId that points to the image column of the photos table in the database. (This line of code shows the Multimedia JSP tag mediaUrl.)

  9. Provide a link that points to the URL stored in the script variable.

  10. Generate the HTML <IMG> tag that displays the thumb column of the photos table (see embedImage for information about the HTML output). The HTML <A HREF> tag uses the JSP tag embedImage as the link anchor. (This line of code shows the Multimedia JSP tag embedImage.)

  11. End the loop then close the query and the database connection.

Uploading Multimedia Data Using the interMedia JSP Tag Library

Oracle interMedia Java Classes for servlets and JSP uses the OrdHttpUploadFile class to facilitate the handling of uploaded media files. This class provides a simple application programming interface (API) that applications call to load media data into the database.

File uploading using HTML forms encodes form data and uploaded files in POST requests using the multipart/form-data format. The OrdHttpUploadFormData class facilitates the processing of such requests by parsing the POST data and making the contents of regular form fields and the contents of uploaded files readily accessible to a Java servlet or JSP page.

Multimedia Tag Library provides media upload tags, which facilitate the development of multimedia applications that upload media data into the database. The media upload tags are storeMedia, uploadFile, and uploadFormData.

The PhotoAlbumInsertPhoto.jsp file is one component of a sample JSP application that uses tags from Multimedia Tag Library to upload media files into a database. The following example shows the tags uploadFormData, uploadFile, and storeMedia.

[1] <%@ page language="java" %>
<%@ taglib prefix="ord" uri="/Web-inf/intermedia-taglib.tld"
%>
<%@ taglib prefix="sql" uri="/web-inf/sqltaglib.tld" %>


[2] <ord:uploadFormData formDataId = "fd">

[3]  <ord:uploadFile
         parameter = "photo"
         fullFileName = "ffName"
         shortFileName = "sfName"

         length = "fLength" >

    <%
[4]   if (ffName == null || ffName.length() == 0)
      {
    %>
      <jsp:forward
      page="PhotoAlbumUploadForm.jsp?error=
      Please+supply+a+file+name."/>
    <%
        return;
      }

      if (fLength.intValue() == 0)

      {
    %>
        <jsp:forward
        page="PhotoAlbumUploadForm.jsp?error=
        Please+supply+a+valid+image+file."/>
      <%
        return;
      }

      String description = fd.getParameter("description");
      String location = fd.getParameter("location");
[5]   if ( description == null || description.length() == 0 )
      {
          description = "Image from file: " + sfName + ".";
          if(description.length() > 40)

          {
              description = description.substring(0, 40);
          }
      }

      java.util.Vector otherValuesVector =
      new java.util.Vector();
      otherValuesVector.add(description);
      otherValuesVector.add(location);
   %>

    <%String id = "original"; %>
[6] <sql:dbOpen connId = "myConn" dataSource="jdbc/OracleDS"
                commitOnClose="true"/>

    <sql:dbQuery connId = "myConn" queryId=
    "myQuery" output="jdbc">
       SELECT photos_sequence.nextval from dual
    </sql:dbQuery>

    <sql:dbNextRow queryId="myQuery">
        <% id = myQuery.getString(1); %>
    </sql:dbNextRow>

     <sql:dbCloseQuery queryId="myQuery"/>
[7] <ord:storeMedia
       conn = "<%=
(oracle.jdbc.driver.OracleConnection)myConn.getConnection()
%>"
       table = "photos"

       key = "<%=id%>"
       keyColumn = "id"
       mediaColumns = "image"
       mediaParameters = "photo"
       otherColumns = "description, location"
       otherValues = "<%=otherValuesVector%>"
    />

[8] <sql:dbSetParam name = "myid" value = "<%=id%>"/>
    <sql:dbExecute connId = "myConn" bindParams="myid">
      {call generateThumbNail(?)}
    </sql:dbExecute>

   <sql:dbClose connId = "myConn" />

  </ord:uploadFile>

</ord:uploadFormData>


<%-- HTML header --%>
<HTML LANG="EN">
<HEAD>
<TITLE>interMedia JavaServer Pages Photo Album Demo</TITLE>
</HEAD>

[9] <META HTTP-EQUIV="REFRESH"
CONTENT="2;URL=PhotoAlbum.jsp">


<BODY>

  <%-- Page heading --%>
  <TABLE BORDER="0" WIDTH="100%">
   <TR>
     <TD COLSPAN="2" BGCOLOR="#F7F7E7" ALIGN="CENTER">
     <FONT SIZE="+2">
      <I>inter</I>Media JavaServer Pages Photo Album Demo
      </FONT>
    </TD>
   </TR>
 </TABLE>

 <%-- Display header and instructions --%>
 <P>
 <FONT SIZE=3 COLOR="#336699">
 <B>Photo successfully uploaded into photo album</B>
 </FONT>
 <HR SIZE=1>
 </P>
 <P>
Please click the link below or wait for the browser to refresh
the page.
</P>

<%-- Output link to return to the main page --%>
<P>
<TABLE WIDTH="100%">
  <TR BGCOLOR="#F7F7E7">
    <TD COLSPAN="3" ALIGN="CENTER">
  <A HREF="PhotoAlbum.jsp">Return to photo album</A>
    </TD>
  </TR>
</TABLE>
</P>

<%-- Finish the page --%>
</BODY>
</HTML>

The Java, SQL, and HTML statements in the PhotoAlbumInsert-Photo.jsp file perform the following operations:

  1. Declare Java as the script language used in the JSP page (JSP directive). Provide the location of the TLD file and the required ord and sql prefix attributes. (These are Tag Library directives.)

  2. Create a script variable named fd, which is an instance of the oracle.ord.im.OrdHttpUploadFormData object. (This line of code shows the multimedia JSP tag uploadFormData.)

  3. Create the script variables ffName, sfName, and fLength, which contain the full file name, short file name, and file length of the uploaded media, respectively. (This line of code shows the multimedia JSP tag uploadFile.)

  4. Provide error checking.

  5. Generate a default description if no description is provided.

  6. Open the database connection and get the next unique ID for the photos table in the database.

  7. Upload the media data into the image column of the photos table, and the description and location information into the description and location columns of the photos table. (This line of code shows the multimedia JSP tag storeMedia.)

  8. Call a PL/SQL procedure to populate the thumb column of the photos table from the uploaded image column.

  9. Display a message of success and then direct the JSP page back to the main page (PhotoAlbum.jsp).

interMedia Java Proxy Classes

The image proxy classes were introduced in chapter 2. Aside from the OrdImage class, the other classes are OrdAudio, OrdVideo, and OrdDoc. These classes make the functionality of the interMedia classes available to Java programs outside the database. They also include utility classes to make programming common functions more convenient.

The database table used for proxy classes can be created from the Java program or previously using standard SQL. In this chapter, it is assumed that the table is created outside the Java program. Most client programs should not be performing database definition language (DDL) statements that, in most cases, are left to the DBA.

A Note on the Context Parameter

You will note that many of the methods have a context parameter. You may wonder why it is there and why you should care. In most cases you should not, however, it is not used by most interMedia users.

Where it is used is if you have a user-written source plug-in. This may be something like a legacy laser disk picture server that can only be accessed using an API. If you do have a system like this, you may need to store a context when the system is opened. Perhaps device handles, current position, etc.

So, if you write a user-written source plug-in, you do care about the context parameter and you will store your context there. If you are using the Database BLOB source, the HTTP source, or file source, you should not worry about the context parameter, except to know you need to pass it in many of the APIs.

Preparing to Use the Proxy Classes

The proxy classes must be associated with a media object in the database. They are used to represent the database media objects in the Java program. The creation of the media object can be done from Java with a simple insert statement, after the object is created, and it can be associated with a proxy class and its contents manipulated. To create the association between the proxy class and the database media object, JDBC is used. To use the proxy classes, the following actions may be taken:

  • Create a JDBC connection, with AutoCommit set to off unless no SQL update operations are to occur, then the programmer can choose either AutoCommit on or off.

  • A new media row may be created.

  • Obtain the media object into a CallableStatement or ResultSet from a procedure or a select statement.

  • Use the proxy classes.

  • Update the proxy classes.

Creating the JDBC Connection

The creation of a JDBC connection is the same as you would do for using an SQL connection on any database, except it is typically important to set AutoCommit to off for operations that will update the database. Note that AutoCommit is set on by default in JDBC connections. For example:

// register the oracle jdbc driver with the JDBC driver
manager
DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());

Connection conn = DriverManager.getConnection(connectString,
username, password);

// Note: for update operations, it is CRITICAL to set the
autocommit to false so that
// two-phase select-commit of BLOBS can occur.
conn.setAutoCommit(false);

Creating a New Media Row with the Media Objects and Create the Proxy Objects

To create a new media row, a simple insert statement is executed with the media column inserted. Typically, when you insert a new media object, you are going to put media data into it in subsequent operations, so to avoid round trips, you may want to return the initialized media object. To be a bit more efficient, we will insert and return the image object in one step using a JDBC CallableStatement block.

// After prepare, this can be used over and over again.
        CallableStatement cstmt =
          conn.prepareCall (
          "begin " +
          "insert into photos t (id, description, location,"
          + image, thumb) " +
          "  values (?," +
          "'Desc that should be an input param'',"
          "'A place that should be an input param too', " +
           "ORDImage.init(), ORDImage.init())" +
        "  returning rowid, t.image, t.thumb into ?, ?, ? ; " +
           "end;");

        // Register input parameters
        cstmt.setInt(1, 17);
        // Register Output Parameters

    cstmt.registerOutParameter(2, Types.VARCHAR);  // rowid
     ((OracleCallableStatement)cstmt).registerOutParameter
                  (3, Types.STRUCT, "ORDIMAGE");
     // image
     ((OracleCallableStatement)cstmt).registerOutParameter
                  (4, Types.STRUCT, "ORDIMAGE");
     // thumb

         int rowsUpdated  = cstmt.executeUpdate();

         String rowid = cstmt.getString(2);
         // Obtain the proxy objects
         OrdImage imgObj =

 (OrdImage)((OracleCallableStatement)cstmt).getORAData
                  (3,
  OrdImage.getORADataFactory());
         OrdImage thumbObj =

 (OrdImage)((OracleCallableStatement)cstmt).getORAData
                  (4,
  OrdImage.getORADataFactory());

Execute an SQL Select Statement to Return a Media Column for Existing Rows and Obtain the Proxy Objects

To return the media rows from an existing or just inserted row, we could also use a standard select statement.

// select the new ORDImage into a java proxy OrdImage object
(imageProxy)

String rowSelectSQL = "select image from photos where id = 1
for update";
OracleResultSet rset =
(OracleResultSet)stmt.executeQuery(rowSelectSQL);
rset.next();
OrdImage imageProxy = (OrdImage)rset.getORAData("image",
OrdImage.getORADataFactory());
rset.close();

Note that the for update clause should only be used if there is a potential of the media, or row, being updated. The media is typically updated through the proxy object.

Use the Proxy Classes

Once obtained, the proxy classes can be used. They can be used to retrieve media or attributes, or they can be used to modify the media and attributes. They are like any other Java object except that the modifications can be made permanent in the database.

One example of using a proxy class would be to create an image using Image IO. This image then can be used in other display objects, like an ImageIcon that can be put into various controls, like a JLabel that can be displayed in a frame.

InputStream is =
    imgObj.getContent().getBinaryStream();
ImageInputStream iis =
    ImageIO.createImageInputStream(is);
    Image image = ImageIO.read(iis);
    ImageIcon imgIcon = new ImageIcon(image);
    JLabel label = new Jlabel(imgIcon);

Another example is to use the methods provided to perform image processing and modify images in the database. For example:

imgObj.loadDataFromFile("goats.gif");
imgObj.setProperties();
imgObj.processCopy("fileFormat=JFIF maxScale=128 128",
    thumbObj);

Update the Media Objects in the Databases

If you change the Java proxy object during processing, these changes do not become permanent until the row is updated and the current transaction committed. Here is an example of updating and committing the update after proxy object changes.

OraclePreparedStatement insertImg =
    (OraclePreparedStatement)conn.prepareStatement(
    "Update photos Set image = ?, thumb = ? " +
          " where rowid = ?" );

    insertImg.setORAData(1, imgObj);
    insertImg.setORAData(2, thumbObj);
    insertImg.setString(3, rowid);
    insertImg.execute();
    insertImg.close();
    conn.commit();

OrdAudio, OrdImage, OrdAudio, and OrdDoc

Common methods for OrdAudio, OrdImage, OrdVideo, and OrdDoc

Table 9.1 contains a signature and brief description of the common methods. For full information, see the interMedia Java Classes Reference Manual.

Table 9.1. Common Methods

Method Signature

Description

void clearLocal()

Clears the local attribute to indicate that the media data is stored externally.

int closeSource(byte[ ] [ ] ctx)

Closes a plug-in data source.

void deleteContent()

Deletes media stored locally in the source BLOB.

void export (byte[ ] [ ] ctx, String srcType, String srcLocation, String srcName)

Exports data from the source BLOB into a file.

Oracle.sql.BFILE getBFILE()

Returns a BFILE locator from the database when the media is stored in a file outside the database.

Oracle.sql.BLOB getContent()

Returns the BLOB locator from the localData attribute.

getContentLength()

Returns the length of the media data.

byte[ ] getDataInByteArray()

Returns a byte array containing the media data from the localData BLOB attribute.

boolean getDataInFile(String filename)

Writes the data from the database specified by the localData BLOB attribute to a local file.

InputStream getDataInStream()

Returns an InputStream object from which the data in the database BLOB specified by the localData attribute.

static oracle.sql.ORADataFactory getORADataFactory()

Returns the OrdAudio ORADataFactory interface for use by the getORAData() method.

String getFormat()

This method returns the value of the format attribute as a string.

String getMimeType()

This method returns the value of the mimeType attribute as a string.

String getSource()

Returns the source information in the form srcType://srcLocation/srcName.

String getSourceLocation()

Returns the value of the srcLocation attribute.

String getSourceName()

This method returns the value of the src-Name attribute.

String getSourceType()

This method returns the value of the srcType attribute.

java.sql.Timestamp getUpdateTime()

This method returns the value of the updateTime attribute.

boolean isLocal()

This method returns true if the data is stored in the database in a BLOB; false otherwise.

boolean loadDataFromByteArray(byte[ ] byteArr)

Loads data from a byte array into the database BLOB specified by localData; it replaces any existing content and updates the Update Time.

boolean loadDataFromFile(String filename)

Loads data from a file local to the Java program into the database BLOB specified by localData; it replaces any existing content and updates the Update Time.

boolean loadDataFromInputStream(Input Stream inpStream)

Loads data from an InputStream into the database BLOB specified by localData; it replaces any existing content and updates the Update Time.

void setFormat(String format)

Sets the value of the format attribute.

void setLocal()

Sets the value of the local attribute to indicate that the media data is stored locally in the database in a BLOB specified by the localData attribute.

void setMimeType(String mimeType)

Sets the value of the mimeType attribute.

setSource(String srcType, String srcLocation, String srcName)

Sets the values of the srcType, srcLocation, and srcName attributes.

void setUpdateTime(java.sql.Timest amp currentTime)

Sets the value of the updateTime attribute.

OrdImage Noncommon Methods

Table 9.2 shows the OrdImage noncommon methods.

Table 9.2. OrdImage Noncommon Methods

Method Signature

Description

boolean checkProperties()

Checks if the properties of the image data are consistent with the attributes of the OrdImage Java object.

void copy(OrdImage dest)

Copies all the attributes of the current OrdImage. If the media is stored locally in a BLOB, the BLOB is also copied.

String getCompressionFormat()

Returns the value of the compressionFormat attribute.

String getContentFormat()

Returns the value of the contentFormat attribute.

int getHeight()

This method returns the value of the height attribute.

int getWidth()

This method returns the value of the width attribute.

void importData(byte[ ] [ ] ctx)

Imports data from an external source into the database BLOB specified by the localData attribute. Calls setProperties() after obtaining the data unless the setFormat() method sets the format attribute.

importFrom(byte[ ] [ ] ctx, String srcType, String srcLocation, String srcName)

Imports data from an external source, specified by the method parameters, into the database BLOB specified by the localData attribute. Calls setProperties() after obtaining the data unless the setFormat() method sets the format attribute.

void process(String cmd)

Performs one or more image-processing operations on the image data in the database BLOB specified by the localData attribute.

void processCopy(String cmd, OrdImage dest)

Copies the image data to the destination object and performs one or more imageprocessing operations on the image data.

void setCompressionFormat(String compressionFormat)

Sets the value of the compressionFormat attribute.

void setContentFormat(String contentFormat)

Sets the value of the contentFormat attribute.

setContentLength(int contentLength)

Sets the value of the contentLength attribute, but does not affect the media itself.

void setHeight(int height)

Sets the value of the height attribute.

void setProperties()

Parses the image data properties and sets the values of the attributes in the OrdImage Java object.

void setProperties(String description)

Writes the characteristics of a foreign image into the appropriate attribute fields. See the interMedia Reference Guide for the format of this string.

void setWidth(int width)

Sets the value of the width attribute.

OrdAudio Noncommon Methods

Table 9.3 shows the OrdAudio noncommon methods.

Table 9.3. OrdAudio Noncommon Methods

Method Signature

Description

boolean checkProperties(byte[ ] [ ] ctx)

Checks if the properties of the audio data are consistent with the attributes of the OrdAudio object.

CLOB getAllAttributes(byte[ ] [ ] ctx)

Returns the values of the audio properties in a temporary CLOB in a form defined by the format plug-in.

String getContentFormat()

Returns the value of the contentFormat attribute.

String getAttribute(byte[ ] [ ] ctx, String name)

Returns the value of the requested audio property defined by user-defined format plug-ins.

int getAudioDuration()

This method returns the value of the audioDuration attribute.

Oracle.sql.CLOB getComments()

Returns the CLOB locator from the comments attribute.

String getCompressionType()

Returns the value of the compressionType attribute.

oracle.sql.BLOB getContentInLob(byte[ ] [ ] ctx, String mimetype[ ], String format[ ])

Returns the data from the BLOB specified by the localData attribute in a temporary BLOB in the database.

int getContentLength()

Returns the length of the audio data.

int getContentLength(byte[ ] [ ] ctx)

Returns the length of the audio data using source plug-in context information. Not supported for all source types.

String getDescription()

Returns the value of the description attribute.

String getEncoding()

This method returns the value of the encoding attribute.

int getNumberOfChannels()

Returns the value of the numberOfChannels attribute.

int getSamplingRate()

Returns the value of the samplingRate attribute.

void importData(byte[ ] [ ] ctx)

Imports data from an external source into the database BLOB specified by the localData attribute.

importFrom(byte[ ] [ ] ctx, String srcType, String srcLocation, String srcName)

Imports data from an external source, specified by the method parameters, into the database BLOB, specified by the localData attribute. Calls setProperties() after obtaining the data unless the setFormat() method sets the format attribute.

int openSource(byte[ ] userarg, byte[ ] [ ] ctx)

Opens a data source for a plug-in if necessary.

byte[ ] processAudioCommand(byte[ ] [ ] ctx, String cmd, String args, byte[ ] [ ] result)

Calls the format plug-in in the database to execute a command implemented by a user-written plug-in.

byte[ ] processSourceCommand(byte[ ] [ ] ctx, String cmd, String args, byte[ ] [ ] result)

Calls the user-written source plug-in in the database to execute a command.

int readFromSource(byte[ ] [ ] ctx, int startpos, int numbytes, byte[ ] [ ] buffer)

Reads data from the data source.

void setAudioDuration(int audioDuration)

Sets the value of the audioDuration attribute.

void setComments(oracle.sql.CLOB comments)

Sets the value of the comments attribute.

void setCompressionType(String compressionType)

Sets the value of the compressionType attribute. Set automatically for some formats with setProperties(Byte[][]).

void setDescription(String description)

Sets the value of the description attribute.

void setEncoding(String encoding)

Sets the value of the encoding attribute. May be set with setProperties(Byte[][]).

void setKnownAttributes(String format, String encoding, int numberOfChannels, int samplingRate, int sampleSize, String compressionType, int audioDuration)

Sets the values of the known attributes of the OrdAudio Java object. SetProperties(Byte[][]) may set these as well.

void setNumberOfChannels(int numberOfChannels)

Sets the value of the numberOfChannels attribute.

void setProperties(byte[ ] [ ] ctx)

Parses the audio data properties and sets the values of the attributes in the OrdAudio Java object.

void setProperties(byte[ ] [ ] ctx, boolean setComments)

Parses the audio data properties, sets the values of the attributes in the OrdAudio Java object, and optionally populates the CLOB specified by the comments attribute.

void setSampleSize(int sampleSize)

Sets the value of the sampleSize attribute.

void setSamplingRate(int samplingRate)

Sets the value of the samplingRate attribute.

int trimSource(byte[ ] [ ] ctx, int newLen)

Trims the data to the specified length by source plug-ins that support the operation.

int writeToSource(byte[ ] [ ] ctx, int startpos, int numbytes, byte[ ] buffer)

Writes data to the data source for source plug-ins that support it.

OrdVideo Noncommon

Table 9.4 shows the OrdVideo noncommon methods.

Table 9.4. OrdVideo Noncommon Methods

Method Signature

Description

boolean checkProperties(byte[ ] [ ] ctx)

Checks if the properties of the audio data are consistent with the attributes of the OrdAudio object.

CLOB getAllAttributes(byte[ ] [ ] ctx)

Returns the values of the audio properties in a temporary CLOB in a form defined by the format plug-in.

String getContentFormat()

Returns the value of the contentFormat attribute.

String getAttribute(byte[ ] [ ] ctx, String name)

Returns the value of the requested audio property defined by user-defined format plug-ins.

int getBitRate()

Returns the value of the bitRate attribute.

Oracle.sql.CLOB getComments()

Returns the CLOB locator from the comments attribute.

String getCompressionType()

Returns the value of the compressionType attribute.

oracle.sql.BLOB getContentInLob(byte[ ] [ ] ctx, String mimetype[ ], String format[ ])

Returns the data from the BLOB specified by the localData attribute in a temporary BLOB in the database.

int getContentLength()

Returns the length of the audio data.

int getContentLength(byte[ ] [ ] ctx)

Returns the length of the audio data using source plug-in context information. Not supported for all source types.

String getDescription()

Returns the value of the description attribute.

String getEncoding()

This method returns the value of the encoding attribute.

int getFrameRate()

Returns the value of the frameRate attribute.

int getFrameResolution()

Returns the value of the frameResolution attribute.

int getHeight()

Returns the value of the height attribute.

int getNumberOfColors()

Returns the value of the numberOfColors attribute.

int getNumberOfFrames()

Returns the value of the numberOfFrames attribute.

int getVideoDuration()

Returns the value of the videoDuration attribute.

int getWidth()

Returns the value of the width attribute.

void importData(byte[ ] [ ] ctx)

Imports data from an external source into the database BLOB specified by the localData attribute.

importFrom(byte[ ] [ ] ctx, String srcType, String srcLocation, String srcName)

Imports data from an external source, specified by the method parameters, into the database BLOB, specified by the localData attribute. Calls setProperties() after obtaining the data unless the setFormat() method sets the format attribute.

int openSource(byte[ ] userarg, byte[ ] [ ] ctx)

Opens a data source for a plug-in if necessary.

byte[ ] processSourceCommand(byte[ ] [ ] ctx, String cmd, String args, byte[ ] [ ] result)

Calls the user-written source plug-in in the database to execute a command.

byte[ ] processVideoCommand(byte[ ] [ ] ctx, String cmd, String args, byte[ ] [ ] result)

Calls the format plug-in in the database to execute a command implemented by a user-written plug-in.

int readFromSource(byte[ ] [ ] ctx, int startpos, int numbytes, byte[ ] [ ] buffer)

Reads data from the data source.

void setBitRate(int bitRate)

Sets the value of the bitRate attribute.

void setComments(oracle.sql.CLOB comments)

Sets the value of the comments attribute.

void setCompressionType(String compressionType)

Sets the value of the compressionType attribute. Set automatically for some formats with setProperties(Byte[][]).

void setDescription(String description)

Sets the value of the description attribute.

void setEncoding(String encoding)

Sets the value of the encoding attribute. May be set with setProperties(Byte[][]).

void setFrameRate(int frameRate)

Sets the value of the frameRate attribute.

void setFrameResolution(int frameResolution)

Sets the value of the frameResolution attribute.

void setHeight(int height)

Sets the value of the height attribute.

void setNumberOfColors(int numberOfColors)

Sets the value of the numberOfColors attribute.

public void setNumberOfFrames(int numberOfFrames)

Sets the value of the numberOfFrames attribute.

void setProperties(byte[ ] [ ] ctx)

Parses the audio data properties and sets the values of the attributes in the OrdAudio Java object.

void setProperties(byte[ ] [ ] ctx, boolean setComments)

Parses the audio data properties, sets the values of the attributes in the OrdAudio Java object, and optionally populates the CLOB specified by the comments attribute.

void setVideoDuration(int videoDuration)

Sets the value of the videoDuration attribute.

void setWidth(int width)

Sets the value of the width attribute.

int trimSource(byte[ ] [ ] ctx, int newLen)

Trims the data to the specified length by source plug-ins that support the operation.

int writeToSource(byte[ ] [ ] ctx, int startpos, int numbytes, byte[ ] buffer)

Writes data to the data source for source plug-ins that support it.

OrdDoc Noncommon

Table 9.5 shows the OrdDoc noncommon methods.

Table 9.5. OrdVideo Noncommon Methods

Method Signature

Description

Oracle.sql.CLOB getComments()

Returns the CLOB locator from the comments attribute.

oracle.sql.BLOB getContentInLob(byte[ ] [ ] ctx, String mimetype[ ], String format[ ])

Returns the data from the BLOB specified by the localData attribute in a temporary BLOB in the database.

int getContentLength()

Returns the length of the audio data.

void importData(byte[ ] [ ] ctx)

Imports data from an external source into the database BLOB specified by the localData attribute.

importFrom(byte[ ] [ ] ctx, String srcType, String srcLocation, String srcName)

Imports data from an external source, specified by the method parameters, into the database BLOB, specified by the localData attribute. Calls setProperties() after obtaining the data unless the setFormat() method sets the format attribute.

int openSource(byte[ ] userarg, byte[ ] [ ] ctx)

Opens a data source for a plug-in if necessary.

byte[ ] processSourceCommand(byte[ ] [ ] ctx, String cmd, String args, byte[ ] [ ] result)

Calls the user-written source plug-in in the database to execute a command.

int readFromSource(byte[ ] [ ] ctx, int startpos, int numbytes, byte[ ] [ ] buffer)

Reads data from the data source.

void setComments(oracle.sql.CLOB comments)

Sets the value of the comments attribute.

void setProperties(byte[ ] [ ] ctx)

Parses the audio data properties and sets the values of the attributes in the OrdAudio Java object.

void setProperties(byte[ ] [ ] ctx, boolean setComments)

Parses the audio data properties, sets the values of the attributes in the OrdAudio Java object, and optionally populates the CLOB specified by the comments attribute.

int trimSource(byte[ ] [ ] ctx, int newLen)

Trims the data to the specified length by source plug-ins that support the operation.

int writeToSource(byte[ ] [ ] ctx, int startpos, int numbytes, byte[ ] buffer)

Writes data to the data source for source plug-ins that support it.

OrdImageSignature Methods

OrdImageSignature is used as a proxy to the database OrdImageSignature database type. This signature describes the contents of the image in terms of color, shape, and texture. The image signature is used for image-matching applications. This is a quick list of the methods available.

To use these methods, the OrdImageSignature object must be populated and associated with a signature object in the back end. See Table 9.6 and the following code, for example.

Table 9.6. OrdImageSignature Methods

Method Signature

Description

static float evaluateScore(OrdImage Signature signature1, OrdImageSignature signature2, String attrWeights)

Compares two image signatures, returning a score that indicates the degree of difference between the image signatures.

void generateSignature(OrdImage img)

Reads data from the data source. Generates an image signature for the specified image. The signature is stored in the OrdImageSignature object. Must be updated and committed into the database to be stored.

static oracle.sql.ORADataFactory getORADataFactory()

Returns the OrdImageSignature ORADataFactory interface for use by the getORAData() method.

static int isSimilar(OrdImageSignature signature1, OrdImageSignature signature2, String attrWeights, float threshold)

Compares two image signatures, returning a status that indicates if the degree of difference between the image signatures is within a specified threshold.

/ select the ORDImageSignature into a java proxy
OrdImageSignature object (imageSigProxy)
String rowSelectSQL = "select imageSig from photos";
OracleResultSet rset =
(OracleResultSet)stmt.executeQuery(rowSelectSQL);
rset.next();
OrdImageSignature imageSigProxy =
               (OrdImageSignature)rset.getORAData("image",
OrdImage.getORADataFactory());

interMedia Java Classes for Servlets

The interMedia Java Classes for servlets are utility classes used to help with the delivery and upload on media to and from the Web using the HTTP protocol. These classes make it easy to write a servlet to deliver or upload media from and to the database. These classes depend on a JDBC connection and the proxy classes that were discussed earlier in this chapter to manipulate the database media.

For delivery of media from the database, these classes can take the inter-Media proxy objects and the contents, with the correct HTTP headers populated from the media objects, as a response to an HTTP request.

For upload of media, these classes help parse the multipart/form-data request returning both text and file parts of the form. This is quite a convenience to the programmer.

The classes that are used for media retrieval are:

  • OrdHttpResponseHandler—used in a Java servlet to deliver media to an HTTP client, like a browser.

  • OrdHttpJspResponseHandler—used in a JSP to deliver media to an HTTP client. Note that JSP engines are not required to be capable of delivering binary data.

    The classes used to upload media data into the database are:

  • OrdHttpUploadFormData—this class parses the upload request so that the programmer does not have to do this. Returns parts of the request to the programmer as demanded.

  • OrdHttpUploadFile—a representation of a file that is part of the upload request.

  • OrdMultipartFilter—the class that implements the javax.servlet.Filter interface in servlet 2.3. A filter preprocesses the request before the servlet is called. It must be defined in the servlet parameter file for the servlet pattern being used and wraps the multipart HttpServletRe-quest in OrdMultipartWrapper.

  • OrdMultipartWrapper—the wrapper around multipart/form-data request when OrdMultipartFilter is used. This wrapper wraps the servlet’s HttpServletRequest object so that multipart fields can be easily accessed without parsing (which is done in the filter).

For uploading media into the database, it should be noted that you should either use the first two classes above or the last two. You should not mix the two to avoid unnecessary reprocessing of the request.

One thing that should definitely be implemented for both methods in a real application is JDBC connection pooling. To connect to the database on every request would make access to any database data very expensive.

Media Delivery

Media Delivery Using JSPs

Note that not all JSP engines are capable of delivering nontext data. If this is the case with your servlet engine, you will be required to use a servlet. To deliver media using a JSP using OrdHttpJspResponseHandler, you need the following:

  • A JSP that will deliver the media.

  • Java code to return the media.

The JSP is just an endpoint of a URL. It can inspect the request and reject it. The JSP can then call a method to obtain the media. Typically this uses information in the request for finding the media, for example, an ID.

The JSP can then call one of the OrdHttpJspResponseHandler methods to send the media data. This data can be in the form of one of the media proxy objects, or a BFILE, BLOB or InputStream. If you want to send media using a BFILE, BLOB, or InputStream, you will also need to supply a MIME type and a time stamp indicating the last update time. This information is already in the media objects, so it is not necessary when sending media from interMedia proxy classes.

In the following example, we have defined a data source in OC4J data-sources.xml. Your data source may be defined differently. The definition used for the examples is as follows:

     <data-source

class="oracle.jdbc.pool.OracleConnectionPoolDataSource"
            name="jdbc/pool/OracleMediaPoolDS"
            location="jdbc/pool/OracleMediaPoolDS"
            url="jdbc:oracle:thin:@localhost:1521:orcl10g"
            username="scott"
            password="tiger"
     />

An example of a JSP that delivers interMedia images follows:

<%@ page import="oracle.ord.im.OrdHttpJspResponseHandler" %>
<%@ page import="oracle.ord.im.OrdImage" %>
<%@ page import="oracle.ord.im.OrdMediaUtil" %>
<%@ page
import="oracle.jdbc.pool.OracleConnectionPoolDataSource" %>
<%@ page import="oracle.jdbc.pool.OraclePooledConnection" %>
<%@ page import="oracle.jdbc.driver.OracleConnection" %>
<%@ page import="oracle.jdbc.OraclePreparedStatement" %>
<%@ page import="oracle.jdbc.OracleResultSet" %>

<jsp:useBean id="handler" scope="page"
              class="oracle.ord.im.OrdHttpJspResponseHandler"/>

<%
     //
     // Get ID of image to fetch. We could get other parameters
     // as well
     //
     boolean imageSent = false;
     String id = request.getParameter( "id" );
     if ( id != null && !"".equals(id) )
     {
         //
         // Use a try block to ensure the JDBC connection is
         // released
         //
         OracleConnection conn = null;
         try
         {
             //
             // Get a connection from the pool. The SQL would
             // be better
             // done from a factory....
             //
             javax.naming.InitialContext ic =
                    new javax.naming.InitialContext();
             OracleConnectionPoolDataSource ds =
                (OracleConnectionPoolDataSource)
                     ic.lookup("jdbc/pool/OracleMediaPoolDS");
             OraclePooledConnection pc =
                          (OraclePooledConnection)
                          ds.getPooledConnection();
             conn =  (OracleConnection)pc.getConnection();

             //
            // Here, we go to the database and select an image
             // from the database, Returns null if image not
             // found or
             // image column is null (not populated).
             //
             String imgSelectSQL ="select image from photos
            where id = "+id;

             OraclePreparedStatement stmt =
                  (OraclePreparedStatement)
                  conn.prepareStatement(imgSelectSQL);
             OracleResultSet rset =
                 (OracleResultSet)stmt.executeQuery();
             rset.next();
             OrdImage imageProxy = (OrdImage)
                rset.getORAData("image",
                OrdImage.getORADataFactory());
             rset.close();

             if ( imageProxy == null)
             {
                response.setStatus( response.SC_NOT_FOUND );
                return;
             }

             //
             // Send this image.
             //
             handler.setPageContext( pageContext );
             handler.sendImage( imageProxy );
             imageSent = true;
         }
         finally
         {
             //
             // Ensure the JDBC connection is released
             //
             if (conn != null) conn.close();
         }
         // Go to not found error
         if (imageSent) return;
    }
%>

<%-- The request does not include a key to the row --%>
<html lang="EN"><head><title>ExampleMediaDelivery.jsp -
malformed URL</title></head>
<body><h1>ExampleMediaDelivery.jsp - malformed URL</h1>
</body></html>

Media Delivery Using Servlets

Media delivery using servlets and the interMedia classes for JSP and servlets require that the data is obtained and then sent using the method necessary for the data type being sent.

The class that is used to deliver interMedia data from a servlet is OrdHttpResponseHandler. This class implements the send methods to send the contents of a proxy object or other types of objects, including BLOBS, to the HTTP client.

The following servlet example presents a form to the user, and when a row is found in the table, displays the thumbnail and full-size image. Please note that this servlet could have better performance by caching the more recent results of queries. Three requests are made to retrieve the data: one to populate the HTML, one to obtain the thumbnail image, and one to obtain the full-size image. Remember that each image, or multimedia, request will be a new request to the server. In this example, we use metadata from the image on the first request to populate the width and height of the image. The following is an example JSP that delivers data.

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import java.sql.PreparedStatement;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.naming.NamingException;
import oracle.jdbc.OracleResultSet;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;
import oracle.jdbc.pool.OraclePooledConnection;
import oracle.jdbc.driver.OracleConnection;
import oracle.ord.im.OrdImage;
import oracle.ord.im.OrdHttpResponseHandler;
import oracle.ord.im.OrdMultipartWrapper;

public class deliveryServlet extends HttpServlet
{
   OracleConnection conn = null;
   String servletURL = null;

   /**
    * Servlet initialization method.
    */
   public void init( ServletConfig config ) throws
       ServletException
   {
     super.init(config);
   }

   /*
    * Get a pooled database connection
    */
   private void getPooledConnection() throws SQLException,
      NamingException
   {
     javax.naming.InitialContext ic = new
         javax.naming.InitialContext();
     OracleConnectionPoolDataSource ds=
         (OracleConnectionPoolDataSource)
         ic.lookup("jdbc/pool/OracleMediaPoolDS");
     OraclePooledConnection pc = (OraclePooledConnection)
                                ds.getPooledConnection();
     conn = (OracleConnection)pc.getConnection();
     // conn.setAutoCommit(false); // just query. No need for
     // this
   }

   /*
    * Process an HTTP GET request used to deliver an image
      column
    */
   public void doGet( HttpServletRequest request,
                       HttpServletResponse response )
       throws ServletException, IOException
   {
     String id = request.getParameter( "id" );
     String what = request.getParameter( "what" );
     if (!"image".equalsIgnoreCase(what)) what = "form";
     // set a default

      if ("form".equalsIgnoreCase(what))
      {
      String servletURL = request.getRequestURL().toString();
       try
      {
        if (conn == null) getPooledConnection();
         PrintWriter out = response.getWriter();
         response.setContentType( "text/html" );
         out.println( "<HTML><BODY>" +
                      "<H1>Display Images</H1>" +
                     "<FORM action="" + servletURL + "">" +
              " Enter Row ID:<INPUT type="text" name="id" /><BR/>");
         if (id != null)
        {
           PreparedStatement stmt =
             conn.prepareStatement("select description,"+
            "location, " +
                                          "thumb, image "+
                                  " from photos where id = ?" );
           stmt.setString( 1, id );
           OracleResultSet rset =
           (OracleResultSet)stmt.executeQuery();
           //
           // Fetch the row from the result set.
           //
           if ( rset.next() )
           {
              //
              // Get columns from query
              //
             String location = rset.getString(1);
             String description = rset.getString(2);
              OrdImage thumb =
                 (OrdImage)rset.getORAData(3,
                 OrdImage.getORADataFactory());
              OrdImage img =
                 (OrdImage)rset.getORAData(4,
              OrdImage.getORADataFactory());
               out.println("<B>Description: </B>" +
              description+ "<BR/>");
               out.println("<B>Location: </B>" + location+
               "<BR/>");
               if (thumb != null &&
                   thumb.getMimeType().startsWith("image/"))
               if (thumb != null &&
                  thumb.getMimeType().startsWith("image/"))
              {

                String thmbWidthStr =  thumb.getWidth() == 0 ?
                "" :
                  "WIDTH="" + thumb.getWidth()  + "" ";

                String thmbHeightStr =  thumb.getHeight() == 0
                   ? "" :
                     "HEIGHT="" + thumb.getHeight()  + "" ";
                out.println("<B>Thumbnail: </B>" +
                   "<IMG SRC="" + servletURL + "?id=" + id +
                                    "&what=image&col=thumb" " +
                                        thmbWidthStr +
                                        thmbHeightStr +
                               "/>" );
              }
               if (img != null &&
               img.getMimeType().startsWith("image/"))
              {
                 String imgWidthStr =  img.getWidth() == 0 ? ""
                    :
                    "WIDTH="" + img.getWidth()  + "" ";
                 String imgHeightStr =  img.getHeight() == 0 ?
                         "" :
                        "HEIGHT="" + img.getHeight()  + "" ";

                 out.println("<B>Image: </B>" +
                    "<IMG SRC="" + servletURL + "?id=" + id +
                                     "&what=image&col=image" " +
                                        imgWidthStr +
                                     imgHeightStr +
                               "/>" );
              }
           }

           else
           {
              //
              // Print not found
              //
             out.println("<H2>Row with ID"" + id +
                         "" Not Found</H2><BR/>");
           }
         }
         out.println("</FORM></BODY></HTML>");
     }
      catch (Exception e)
      {
      conn  = null; // Get another connection next time.
       throw new ServletException(e);
      }
    }
    else
    {
      try
       {
     if (conn == null) getPooledConnection();
        String col = request.getParameter("col");
        if (col == null) col = "thumb";
        //default to the thumbnail column
        PreparedStatement stmt =
          conn.prepareStatement( "select " + col +
                " from photos where id = ? " );
        stmt.setString( 1, id );
        OracleResultSet rset =
                (OracleResultSet)stmt.executeQuery();

        //
        // Fetch the row from the result set.
        //
        if ( rset.next() )
        {
           //
           // Get the OrdImage object from the result set.
           //
           OrdImage img =
                 (OrdImage)rset.getORAData(1,
           OrdImage.getORADataFactory());

           //
           // Create an OrdHttpResponseHandler object, then
           // use it to get
           // the image from the database and deliver it to
           // the browser.
           //
           OrdHttpResponseHandler handler =
            new OrdHttpResponseHandler( request, response );
           handler.sendImage( img );
         }
         else
         {
           //
           // Row not found, return a suitable error.
           //
           response.setStatus( response.SC_NOT_FOUND );
         }

         //
         // Close the result-set and the statement.
         //
         rset.close();
         stmt.close();
       }
       catch (Exception e)
       {
       conn  = null; // Get another connection next time.
        throw new ServletException(e);
       }
      }
    }
}

Media Upload Classes for Servlets

The media upload classes are convenience classes to help parse a request with media in a servlet environment. It can be quite a bit of code to parse a multipart/form-data POST request. These classes perform this parsing for you. If you want total control over the parsing of the form, you are not required to use these classes to upload media data. You can parse the request yourself.

Uploading interMedia media over HTTP using Java is done through a servlet. To upload data to the database you need:

  • A Web page form that

    • Sends the form data in multipart/form-data format in an HTTP POST request.

    • Has at least one input field of type file.

  • A servlet that will accept the form from the client.

    • This servlet will have a connection to the database.

    • This servlet will either create a new row in the database for the media or populate an existing row.

There are two techniques that you can use with the convenience classes to upload media. The first is to have all the code in the servlet to parse the multipart/form-data POST request. The second is to make use of the servlet filter provided by interMedia. This will parse the request before the servlet code is called and wrap the request in an OrdMultipartWrapper object that has all the functionality of an HttpServletRequest object plus much of the functionality that OrdHttpUploadFormData has. The first technique is called the request parsing technique, the second is called the filter technique.

One important note when uploading media data from the Web is to know the maximum size of the data. If this data is very large, perhaps a 10-gigabyte movie, it is certainly best for the servlet to cache this movie in a file rather that Java’s virtual memory. You can set the limit of the Java virtual memory use with either technique. In the filter technique, you would call the OrdHttpUploadFormData setMaxMemory method to set the maximum size of virtual memory use and the directory to use for temporary files. For the filter technique, these settings are set as part of the filter configuration. These parameters should always be set to prevent exhausting Java memory event if you don’t think the data will ever be that large. A mistake, or mischief, could cause problems for your Web server.

One nice feature of using these classes to upload files into interMedia database objects is that they populate the MIME type of the object from the HTTP request before attempting to get properties from the binary data. In the case that the binary data is not recognized by interMedia media parsing the MIME type will still be set to an appropriate value. A browser typically sets the MIME type of data it is uploading based on the file extension.

The result of using either the parsing technique or filtering technique is the standard parameters from a form request in string objects and the file parts of the form in OrdHttpUploadFile objects. The OrdHttpUploadFile objects are used to provide information about the file, such as MIME type, file name, and length, and populate the database with file data from the request in interMedia proxy objects or a standard database BLOB.

To upload media from a browser requires an appropriate HTML form. A very simple example of an HTML form that uploads an image follows.

<HTML>
<BODY>
<FORM action="http://localhost:8888/servlet/uploadServlet"
name="uploadForm"
      method="post" enctype="multipart/form-data">
<P>
 Location?    <INPUT type="text" name="location"/><BR/>
 Description? <INPUT type="text" name="description"/><BR/>
 Image File?  <INPUT type="file" name="photo"/><BR/>
 <INPUT type="submit" value="Submit" />
</P>
</FORM>
</BODY>
</HTML>

In the following example a database sequence object is created to assign an ID number to added media. It is preferable to use sequences rather than the maximum ID plus one because two users may be trying to insert media at the same time. With a sequence, we can guarantee that simultaneous update requests do not try to use the same ID. This sequence is created with the following SQL statement.

SQL> create sequence photos_sequence;

This example is a servlet that handles the upload request from the preceding form. This servlet works with either the filter technique or parsing using OrdHttpUploadFormData. To use the filter method, the filter must be put into the servlet filter chain. Each technique will be described in more detail in subsequent sections, but a simple example servlet follows.

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.naming.NamingException;
import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OraclePreparedStatement;
import oracle.jdbc.OracleResultSet;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;
import oracle.jdbc.pool.OraclePooledConnection;
import oracle.jdbc.driver.OracleConnection;
import oracle.ord.im.OrdImage;
import oracle.ord.im.OrdHttpUploadFile;
import oracle.ord.im.OrdHttpUploadFormData;
import oracle.ord.im.OrdHttpResponseHandler;
import oracle.ord.im.OrdMultipartWrapper;

public class uploadServlet extends HttpServlet
{
    OracleConnection conn = null;
    OrdHttpUploadFormData formData = null;

    /**
     * Servlet initialization method.
     */
    public void init( ServletConfig config ) throws
    ServletException
    {
        super.init(config);
    }

    /*
     * Get a pooled database connection
     */
    private void getPooledConnection() throws SQLException,
    NamingException
    {
      javax.naming.InitialContext ic = new
      javax.naming.InitialContext();
      OracleConnectionPoolDataSource ds =
      (OracleConnectionPoolDataSource)
                ic.lookup("jdbc/pool/OracleMediaPoolDS");
      OraclePooledConnection pc = (OraclePooledConnection)
                ds.getPooledConnection();
      conn = (OracleConnection)pc.getConnection();
      conn.setAutoCommit(false);
      // Update or put Media, need this
    }


    /*
     * Process an HTTP Post request used to upload a new photo
     * into the album
     */
    public void doPost( HttpServletRequest request,
                        HttpServletResponse response )
        throws ServletException, IOException
    {
        String description = null;
        String location = null;
        OrdHttpUploadFile photo = null;

       if (request instanceof OrdMultipartWrapper)
       {
            //
            // This request was parsed by OrdMultipartFilter,
            // use it.
            //
           OrdMultipartWrapper ordMultiPartWrapper =
                   (OrdMultipartWrapper)request;
 
           //
           // Get the description, location and photo from the
           // wrapper
           //
           description =
                  ordMultiPartWrapper.getParameter(
                  "description" );
           location = ordMultiPartWrapper.getParameter(
                  "location" );
           photo = ordMultiPartWrapper.getFileParameter(
                  "photo" );
        }
        else
        {
            // Parse the data using OrdHttpUploadFormData
            //
            // Create an OrdHttpUploadFormData object.
            //
            formData = new OrdHttpUploadFormData( request );
            if ( !formData.isUploadRequest() )
            {
              return;
            }

            //
            // Parse the multipart/form-data message.
            // (10 meg max before using file), use system
            // temp directory
            formData.setMaxMemory(10 (1024*1024), null);
            formData.parseFormData();

            //
            // Get the description, location and photo.
            //
            description = formData.getParameter( "description"
                );
             location = formData.getParameter( "location" );
             photo = formData.getFileParameter( "photo" );
        }
         //
         // Make sure a valid image file was provided.
         //
         if ( photo == null ||
            photo.getOriginalFileName() == null ||
            photo.getOriginalFileName().length() == 0 ||
            photo.getContentLength() == 0
          )
        {
           return;
        }

        try
    {
        if (conn == null)
            getPooledConnection(); //Get connection if needed
         //
         // Get a value for the ID column of the new row
         //
         OraclePreparedStatement stmt =
              (OraclePreparedStatement)conn.prepareStatement(
                   "select photos_sequence.nextval from dual"
                    );
         OracleResultSet rset =
              (OracleResultSet)stmt.executeQuery();
         if ( !rset.next() )
             throw new ServletException( "new ID not found" );
         String id = rset.getString( 1 );
         rset.close();
         stmt.close();

         //
         // Prepare and execute a SQL statement to insert the
         // new row.
         //
         OracleCallableStatement cstmt =
              (OracleCallableStatement)
              conn.prepareCall (
                 "begin " +
                 "insert into photos t " +
                  "     (id, description, location, image," +
                        "thumb) " +
                  "values (?, ?, ?, ORDImage.init()," +
                      "ORDImage.init())" +
                 " returning rowid, t.image, t.thumb into " +

                "?, ?, ? ; " +
                "end;");
         cstmt.setString( 1, id );
         cstmt.setString( 2, description );
         cstmt.setString( 3, location );
         cstmt.registerOutParameter(4, Types.VARCHAR);
         // rowid
        cstmt.registerOutParameter(5, Types.STRUCT,
              "ORDIMAGE"); // image
        cstmt.registerOutParameter(6, Types.STRUCT,
              "ORDIMAGE"); // thumb
         cstmt.executeUpdate();
         cstmt.close();

         String rowid = cstmt.getString(4);
         // Obtain the proxy objects
         OrdImage image = (OrdImage)
                      cstmt.getORAData(5,
                      OrdImage.getORADataFactory());
         OrdImage thumb = (OrdImage)
                      cstmt.getORAData(6,
                      OrdImage.getORADataFactory());
         cstmt.close();

         //
         // Load the photo into the database and set
         // the properties.
         //
         photo.loadImage( image );
         if (formData != null) formData.release();
         // Release any resources

         //
         // Try to copy the full-size image and process it to
         // create the thumb-nail. This may not be
         // possible if the image format is
         // not recognized.
         //
         try
         {
             image.processCopy( "maxScale=50,50", thumb );
         }
         catch ( SQLException e )
         {
             thumb.deleteContent();
             thumb.setContentLength( 0 );
         }

         //
         // Prepare and execute a SQL statement to update the
         // full-size and
         // thumb-nail images in the database.
         //
         stmt =
              (OraclePreparedStatement)conn.prepareStatement(
              "update photos set image = ?, thumb = ? where" +
               "rowid = ?" );
         //
         stmt.setORAData( 1, image );
         stmt.setORAData( 2, thumb );
         stmt.setString( 3, rowid );
         stmt.execute();
         stmt.close();

         //
         // Commit the changes.
         //
            conn.commit();
       }
        catch (Exception se)
       {
            conn = null; // We may need a new connection
            if (formData != null)
                formData.release();//Release any resources
            throw new ServletException(se);
       }
        // Print a response page (or we could redirect here
           PrintWriter out = response.getWriter();
        response.setContentType( "text/html" );
        out.println( "<html><body>" +
                      "<h1>Upload Sucessful</h1>" +
                      "<input type="button" onclick=

                       "history.go(-1)" "+
                              "value="back"/>" +
                     "</body></html>");
    }
}

Media Upload Using OrdHttpUploadFormData

The following example servlet shows how the multipart/form-data request is parsed.

            // Parse the data using OrdHttpUploadFormData
           //
           // Create an OrdHttpUploadFormData object.
           //
 [1]       OrdHttpUploadFormData formData =
                                new OrdHttpUploadFormData( request );
 [2]       if ( !formData.isUploadRequest() )
           {
              return;
           }

           //
           // Parse the multipart/form-data message.
           //
 [3]       formData.parseFormData();

           //
           // Get the description, location and photo.
           //
 [4]       description = formData.getParameter( "description" );
           location = formData.getParameter( "location" );
 [5]       photo = formData.getFileParameter( "photo" );

To receive media and other form data from an HTTP request, the following steps are taken:

  1. Create the OrdHttpUploadFormData object using the servlet request, HttpServletRequest.

  2. Test the object to make sure it is a multipart/form-data request.

  3. Parse the request.

  4. Get text parameters from the request.

  5. Get a file from the request in OrdHttpUploadFile format.

Media Upload Using OrdMultipartFilter

To use a filter in J2EE, the filter parameters must be set in web.xml for the Web application the servlet is running from. You need to specify the filter and filter parameters, and then specify which servlet will use the filter. The interMedia HTTP filter only filters requests. An example snippet from web.xml is shown below that will cause the filter to be invoked, parsing the multipart/form-data, before our servlet is invoked.

     <filter>
        <filter-name>ordMultipartFilter</filter-name>
        <filter-class>oracle.ord.im.OrdMultipartFilter
           </filter-class>
        <init-param>
           <param-name>tempDir</param-name>
           <param-value>d:	emp</param-value>
        </init-param>
        <init-param>
           <param-name>maxMemory</param-name>
           <param-value>10000000000</param-value>
        </init-param>
     </filter>

      <filter-mapping>
        <filter-name>ordMultipartFilter</filter-name>
        <url-pattern>/servlet/tstPhotoAlbumServlet
          </url-pattern>
     </filter-mapping>

When the above code is set correctly, the section of the example servlet that uses the filter method will be used. This section is:

[1]  if (request instanceof OrdMultipartWrapper)
    {
         //
         // This request was parsed by OrdMultipartFilter, use it.
         //
[2]    OrdMultipartWrapper ordMultiPartWrapper =
                                        (OrdMultipartWrapper)request;

         //
         // Get the description, location and photo from the wrapper
         //
[3]      description = ordMultiPartWrapper.getParameter( "description" );
         location = ordMultiPartWrapper.getParameter( "location" );
[4]      photo = ordMultiPartWrapper.getFileParameter( "photo" );
    }

When using OrdMultipartWrapper to receive media data and other form data from an HTTP request, the following stepts are taken:

  1. Test if the HttpServletRequest has been wrapped in OrdMultipartWrapper by OrdMultipartFilter.

  2. Cast the request to OrdMultipartWrapper for convenience.

  3. Obtain the text parts of the request as string objects.

  4. Obtain the file part of the request as an OrdHttpUploadFile object.

Summary

Oracle interMedia provides a rich set of features for the J2EE environment. It has support for servlets, JSPs and representing database interMedia objects as Java objects. interMedia can also be used effectively with Oracle JDeveloper, as this application development tool can recognize interMedia objects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.210.205