LAB-5569: ODFDOM - Changing ODF documents using the new opensourced multi-tiered API

Expected Duration: 100 minutes

Exercise 2: Create Web Application Project (30 minutes)

 

The goal of this exercise is to let you build a simple Netbeans Web Application Project by following step by step instructions.


Steps to Follow

 

Step 1: Creating a web based Project

  1. If NetBeans is not already running, start it.
    1. Select File Menu
    2. Select New Project
    3. Select Category 'Java Web' and Project 'Web Application'
    4. Press 'Next'

    Figure-01: New Project: Choose Project

  2. In the next dialog, do the following
    1. Set 'Project Name' to CustomerInvoice
    2. Set 'Project Location' to '<lab_root>' - note for JavaOne attendees: this is correct as it is - just keep the default.
    3. Press 'Next'

    Figure-02: New Web Application: Name and Location

  3. In the next dialog, do the following
    1. Set 'Server' to 'Glassfish V2'
    2. Set 'Java EE Version' to 'Java EE 5'
    3. Press 'Finish'

    Figure-03: New Web Application: Server and Settings

  4. After the project creation, the index.jsp file is automatically opened by NetBeans. This is how it looks like:


    Figure-04: New Web Application: Project View

  5. The following code creates a web application form to get data. Replace the complete content of the index.jsp file with it:
    <%--
        Document   : index
        Created on : June 04, 2009, 01:19:08 PM
        Author     : your name
    --%>
    
    <%@page contentType="text/html" pageEncoding="UTF-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
    
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Customer Invoice</title>
        </head>
        <body>
            <h2>Create a Customer Invoice</h2>
            <form action="createInvoice.jsp" method="POST">
                <table border="0">
                    <tbody>
                        <tr>
                            <td>Name, First Name</td>
                            <td><input type="text" name="myName" value=""/></td>
                        </tr>
                        <tr>
                            <td>Street</td>
                            <td><input type="text" name="myStreet" value=""/></td>
                        </tr>
                        <tr>
                            <td>Zip Code</td>
                            <td><input type="text" name="myZip" value=""/></td>
                        </tr>
                        <tr>
                            <td>City</td>
                            <td><input type="text" name="myCity" value=""/></td>
                        </tr>
                    </tbody>
                </table>
                <table border="0">
                    <thead>
                        <tr>
                            <th>Product ID</th>
                            <th>Product Name</th>
                            <th>Quantity</th>
                            <th>Single Price</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td><input type="text" name="myProdID" value=""/></td>
                            <td><input type="text" name="myProdName" value=""/></td>
                            <td><input type="text" name="myProdQuantity" value=""/></td>
                            <td><input type="text" name="myProdPrice" value=""/></td>
                        </tr>
                        <tr>
                            <td><input type="text" name="myProdID" value=""/></td>
                            <td><input type="text" name="myProdName" value=""/></td>
                            <td><input type="text" name="myProdQuantity" value=""/></td>
                            <td><input type="text" name="myProdPrice" value=""/></td>
                        </tr>
                        <tr>
                            <td><input type="text" name="myProdID" value=""/></td>
                            <td><input type="text" name="myProdName" value=""/></td>
                            <td><input type="text" name="myProdQuantity" value=""/></td>
                            <td><input type="text" name="myProdPrice" value=""/></td>
                        </tr>
                    </tbody>
                </table>
                <input type="submit" value="Send" />
            </form>
        </body>
    </html>

    Do not forget to save the file.

  6. We are adding some jar libraries to our project - for future usage.

    Right-click the CustomerInvoice project and choose 'Properties'. In the 'Libraries' category, click 'Add JAR/Folder'. Add the following libraries to the project:

    • <lab_root>/resources/odfdom/jars/xercesImpl.jar
    • <lab_root>/resources/odfdom/jars/odfdom.jar

    For JavaOne attendees, the libraries are here:

    • /export/home/lab5569/odfdom/resources/odfdom/jars/xercesImpl.jar
    • /export/home/lab5569/odfdom/resources/odfdom/jars/odfdom.jar

    Click "OK" afterwards.


    Figure-05: Add required libraries to the project

  7. Press F6 to start the project. Verify the form in your browser. Note that it may take a while to start glassfish.


    createInvoice JSP File

    Figure-06: Verify the form in the browser

  8. In Netbeans, right-click the 'Web Pages' folder and create a new JSP file named "createInvoice". Use the default settings in the 'New JSP File' dialog.


    createInvoice JSP File

    Figure-07: createInvoice JSP File

  9. You have to add a couple of 'imports' to the "createInvoice.jsp" file:

    <%@page import="java.text.*,
                    java.util.*,
                    org.w3c.dom.*,
                    org.odftoolkit.odfdom.dom.OdfNamespace,
                    org.odftoolkit.odfdom.dom.type.OdfPositiveInteger,
                    org.odftoolkit.odfdom.doc.OdfDocument,
                    org.odftoolkit.odfdom.doc.OdfFileDom,
                    org.odftoolkit.odfdom.doc.element.text.*,
                    org.odftoolkit.odfdom.doc.element.office.*,
                    org.odftoolkit.odfdom.doc.element.table.*,
                    javax.xml.xpath.*" %>
                                      

    Add required imports

    Figure-08: Add required imports

  10. Now change the text of the h1 element in "createInvoice.jsp" to 'Customer invoice generated.'
  11. Store the data which has been passed from the web front end form in variables. The data can be accessed using the getParameter() method of the request object. The parameter of the getParameter method is the name of the text input form which has been assigned in index.jsp. You will need to define the following variables:

        <%
            // Read received post parameter
            String name = request.getParameter("myName");
            String street = request.getParameter("myStreet");            
            String zip = request.getParameter("myZip");
            String city = request.getParameter("myCity"); 
            String[] productIds = request.getParameterValues("myProdID");
            String[] productNames = request.getParameterValues("myProdName");
            String[] productQuantities = request.getParameterValues("myProdQuantity");
            String[] productPrices = request.getParameterValues("myProdPrice");
        %>
                            

    This code has to be inserted after the h1 element and has to be enclosed by '<%' and '%>' to denote that this is Java code.


    Get data from request

    Figure-09: Get data from request

  12. We will extend the Java part in the "createInvoice.jsp" file. Now we start using the ODFDOM API. First we want to open a template bill file and get access to the content dom.

              ////////////////////////////////////////////////////////////////
              // Start ODFDOM handling
              ////////////////////////////////////////////////////////////////
              // 1. Load invoice template
              // if you are not attending JavaOneplease edit the <lab_root>
              OdfDocument document = OdfDocument.loadDocument("/export/home/lab5569/odfdom/resources/invoice_template.odt");
              // 1.1 Get the Content DOM of this Text Document
              OdfFileDom content = document.getContentDom();
    
                            

    Please note that you have to adjust the file location passed to the loadDocument method.

  13. Have a look at the template bill document. This document contains 4 placeholder fields: _NAME_, _STREET_, _ZIPCITY_, and _CURRENTDATE_. We want to replace the address placeholder fields with the data from the web front end and the date placeholder field should be replaced with the current date. For this we first create 4 new OdfSpan objects:

                               
              ////////////////////////////////////////////////////////////////
              // 2. Create OdfSpan elements for curstomer address and current date
              // 2.1 Add Name
              OdfSpan spanName = new OdfSpan(content);
              spanName.setTextContent(name);
              // 2.2 Street
              OdfSpan spanStreet = new OdfSpan(content);
              spanStreet.setTextContent(street);
              // 2.2 Zip And City
              OdfSpan spanCity = new OdfSpan(content);
              spanCity.setTextContent(zip + " " + city);
              // 2.3 Current Date
              OdfSpan spanDate = new OdfSpan(content);
              SimpleDateFormat dateFormater = new SimpleDateFormat();
              String dateStr = dateFormater.getDateInstance(DateFormat.FULL).format(new Date());
              spanDate.setTextContent(dateStr);
                            
  14. In order to find the placeholder fields in the template document, we use a xpath. The result is returned in a NodeList. Please note that the namespace context has to be set to the OdfNamespace. Alternatively, we could use

              ////////////////////////////////////////////////////////////////
              // 3. Find all placeholder elements
              XPath xpath = XPathFactory.newInstance().newXPath();
              xpath.setNamespaceContext(new OdfNamespace());
              NodeList placeholder = (NodeList)xpath.evaluate("//text:placeholder", content, XPathConstants.NODESET);
                            
  15. Now we can iterate over the found placeholder fields and replace them with our new spans:

              // 3.1 Apply Address Details and Date
              for(int i=0; i<placeholder.getLength(); i++) {
                  OdfPlaceholder pl = (OdfPlaceholder)placeholder.item(i);
                  OdfParagraph parentParagraph = (OdfParagraph)pl.getParentNode();
                  String placeholderText = pl.getTextContent();
                  if(placeholderText.indexOf("_NAME_") > 0) {
                      parentParagraph.replaceChild(spanName, pl);
                  } else if(placeholderText.indexOf("_STREET_") > 0) {
                      parentParagraph.replaceChild(spanStreet, pl);
                  } else if(placeholderText.indexOf("_ZIPCITY_") > 0) {
                      parentParagraph.replaceChild(spanCity, pl);
                  } else if(placeholderText.indexOf("_CURRENTDATE_") > 0) {
                      parentParagraph.replaceChild(spanDate, pl);
                  }
              }
                            
  16. We also want to fill the table in the template bill with the data from the web front end. So we first need to get access to the table in the template bill content dom:

              ///////////////////////////////////////////////////////
              // 4. Calculate Product Details and add them as Table Rows
              // 4.1 Find the Billing Table
              xpath = XPathFactory.newInstance().newXPath();
              xpath.setNamespaceContext(new OdfNamespace());
              OdfTable table = (OdfTable)xpath.evaluate("//table:table[1]", content, XPathConstants.NODE);
                            

    Since there's only one table in the template document, we can access this directly without using a NodeList.

  17. We append a new table row for each set of data obtained from the web frontend. Each of these rows will consist of 5 table cells containing a paragraph with the following data:

    • the product ID
    • the product name
    • the product quantity
    • the product single price and
    • the total price

    The style for the table cells should be a copied from the respective cells in the first table row. The style for the paragraphs in the table cells should be "Table_20_Contents". This style is a document style of the bill template document. The last row of the table should state the overall price in the last table cell.

              // 4.2 Find the first Row get the style info for table cell
              OdfTableRow firstRow = (OdfTableRow)table.getElementsByTagName("table:table-row").item(0);
              // 4.3 Calculate row sum to insert
              float priceOverall = 0;
              // 4.4 Insert rows for billing items
              for(int i=0; i < productIds.length; i++) {
                  OdfTableRow billingItemRow = new OdfTableRow(content);
                  // 4.4.1 Add cells billing item details
                  for(int j=0; j < 5; j++) {
                      // Create new Cell
                      OdfTableCell cell = new OdfTableCell(content);
                      // Get and set correct style name for this cell
                      cell.setStyleName( ((OdfTableCell)firstRow.getCellAt(j)).getStyleName() );
                      // Create new Paragraph
                      OdfParagraph paragraph = new OdfParagraph(content);
                      // Set correct style name for this cell
                      paragraph.setStyleName( "Table_20_Contents" );
                      // Apply text regarding the current cell index
                      if(j == 0) {
                          paragraph.setTextContent(productIds[i]);
                      } else if(j == 1) {
                          paragraph.setTextContent(productNames[i]);
                      } else if(j == 2) {
                          paragraph.setTextContent(productQuantities[i]);
                      } else if(j == 3) {
                          paragraph.setTextContent(productPrices[i]);
                      } else if(j == 4) {
                          float priceTotal = Float.parseFloat(productPrices[i])*Float.parseFloat(productQuantities[i]);
                          priceOverall += priceTotal;
                          paragraph.setTextContent(String.valueOf(priceTotal));
                      }
                      cell.appendChild(paragraph);
                      billingItemRow.appendCell(cell);
                  }
                  table.appendRow(billingItemRow);
              }
                            
  18. The last row of the table should state the overall price for the customer bill. It shall consist of two cells, the first of which has a column span of 4 and the second contains a new paragraph with the overall price. The paragraph style for this is "SumPrice".

                          
              // 4.5 Add last row showing overall price
              OdfTableRow lastRow = new OdfTableRow(content);
              OdfTableCell cell = new OdfTableCell(content);
              cell.setNumberColumnsSpanned(OdfPositiveInteger.valueOf("4"));
              lastRow.appendCell(cell);
              cell = new OdfTableCell(content);
              OdfParagraph paragraphFullPrice = new OdfParagraph(content);
              paragraphFullPrice.setStyleName("SumPrice");
              paragraphFullPrice.setTextContent(String.valueOf(priceOverall));
              cell.appendChild(paragraphFullPrice);
              lastRow.appendCell(cell);
              table.appendRow(lastRow);
                            
  19. Finally, we save the file:

          
              ///////////////////////////////////////////////////////
              // 5. Save the resulting file
              // Save to the project directory
              // Edit the path if you are NOT a JavaOne attendee
              document.save("/export/home/lab5569/NetBeansProjects/CustomerInvoice/invoice_final.odt");
                            
  20. The whole "ceateInvoice.jsp" file can be viewed here:

    <%--
        Document   : createInvoice
        Created on : Mar 31, 2009, 01:41:35 PM
        Author     : your name
    --%>
    
                            
  21. You can now run the web application by pressing F6. If the application does not what you expect it to do, you can debug the code by pressing STRG+F5

    When you fill out the web form and click on send, the invoice_final.odt file is generated. Verify this by starting OpenOffice.org and load the invoice. It could look like this:


    The created customer invoice

    Figure-10: The created customer invoice


Challenge

 

The example above produces an exception when not all fields in the table are filled. Fix this.

Hint: Debug the project to verify where the exception actually happens.


Summary

 

In this exercise, you learned how to create a new Netbeans Web Application Project that gathers some data that is written into a document using the ODF Toolkit.

 

Back to top
Next exercise