macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Applying "Digital Hub" Concepts to Enterprise Software Design, Part 4

by Adam Behringer
07/30/2004

The "hub" of most enterprise software systems is a database. However, getting the information from the database to all of the applications that need it and then back again can be a challenge. It becomes particularly challenging if those applications are written in different computer languages or run on different operating systems.

XML is a fantastic technology for transferring data in a heterogeneous environment. Apple's WebObjects technology can be used to handle the conversions from database to XML to database so that any applications or scripts that can parse XML can participate in the system. This article demonstrates a WebObjects application that can handle this data conversion. It builds on a scenario described previously where scientists and students from all over the globe are collaborating on a huge set of weather data.

Prerequisites

If you're going to build the project in this article, you'll first need to complete the steps in part two of this series. You will also need to find the Weather.eomodeld file that you created in that tutorial. Of course, I recommend reading every article in the series, as each one builds on the concepts presented in previous articles.

Connect the Dots

We are going to take the database that we built in part two, and the XML that we designed in part three, and connect them. We want to be able to extract data from the database in XML format and to be able to get data from an XML file to add it to a database. We are going to use WebObjects to do this. WebObjects has some great technologies that handle a lot of the detail for us. Let's dive right in and I will show you.

Here is the XML template from part three that we are going to use for our design:


<?xml version="1.0" encoding="UTF-8"?>
<weather>
  <measureTypes>
    <type id="0" name="Temperature" dataType="number" />
    <type id="1" name="Wind Speed" dataType="number" />
  </measureTypes>
  <data>
    <item id="0" time="2004-04-17 00:00:00 -0700"
            typeId="0" data="60" />
    <item id="1" time="2004-04-17 00:00:00 -0700"
            typeId="1" data="3.2" />
  </data>
</weather>

Getting Started

  1. Launch Xcode and choose New Project... from the File menu.

  2. Choose WebObjects Application as the project type and click Next.

    Choose "WebObjects Application" as the project type and click Next.

  3. Name the project "WeatherHub" and click Next.

  4. When prompted with the J2EE options, click Next.

  5. On the Web Service Support panel, check the box labeled "Add Web service support" and click Next.

  6. On the EOAdaptor panel, JavaJDBCAdaptor.framework should be checked. Click Next.

  7. Leave the Frameworks set to their defaults and click Next.

  8. On the Choose EOModels page, add the model that we created in part two. It is named Weather.eomodeld. Click Finish.

  9. To make sure that WebObjects and your database are working, press Apple-R to build and run your project.

  10. The application should initialize and launch a blank web page in your browser. If it does, go ahead and stop the application by pressing the stop sign icon in the Xcode toolbar. If there is an error, please fix it before continuing. Make certain that your license keys are up to date for WebObjects and Openbase, and make sure that you properly set up the database according to the instructions in part two.

Now you have the basic skeleton of your application. Next we are going to create a class that will be the heart of our application. It will contain the code for moving information from XML to database and back.

  1. Right click (or Ctrl-click) the Classes folder in the left panel of your project (you may need to expand the WeatherHub group) and choose Add -> New File...

  2. Under the WebObjects section, choose the "Java Class" type and click Next.

    Under the WebObjects section, choose the "Java Class" type and click Next.

  3. Name the file XML.java and check the box next to Application Server in the Targets selector. Make sure that none of the other targets are selected and click Finish.

    Name the file XML.java

Now that you have created a new class, add a method to it called buildCompleteXml by copying the following code into your class:


import com.webobjects.foundation.*;
import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.EOUtilities;

public class XML {

  public static String buildCompleteXml() {
    StringBuffer xmlString = new StringBuffer();
    EOEditingContext editingContext= new EOEditingContext();
    xmlString.append("<?xml version=\"1.0\"
    xmlString.append("encoding=\"UTF-8\"?>\n");
    xmlString.append("<weather><measureTypes>");

    // get measureTypes from database
    EOFetchSpecification measureTypesFS = new
    EOFetchSpecification("MeasurementType",null, null);
    NSArray measureTypes =
    new NSArray(editingContext.objectsWithFetchSpecification(measureTypesFS));
    // for each one found, add it to the XML
    for (int i=0; i < measureTypes.count(); i++) {
      EOGenericRecord currentType = 
      (EOGenericRecord)measureTypes.objectAtIndex(i);
      xmlString.append( XML.buildTypeNode(currentType));
    }
        
    xmlString.append("</measureTypes><data>");
    // get weatherData from database
    EOFetchSpecification measuredDataFS =
    new EOFetchSpecification("MeasuredData", null, null);
    NSArray weatherData =
    new NSArray(editingContext.objectsWithFetchSpecification(measuredDataFS));
    //for each one found, add it to the XML
    for (int i=0; i < weatherData.count(); i++) {
      EOGenericRecord currentData = 
      (EOGenericRecord)weatherData.objectAtIndex(i);
      xmlString.append(XML.buildDataNode(currentData));
    }        
    xmlString.append("</data></weather>");
    return xmlString.toString();
  }
}

Before we move on, I would like to explain a few things about the code. Notice that we are creating an XML file by appending tags and data to a StringBuffer. We are not doing anything fancy to create the XML (like using DOM objects) because we don't need to. In fact the tags that are always the same, such as the root tags, are just added to the string using the append method. Simple is almost always the better option.

When we need data from the database, we build a fetch specification and grab an entire table of data out of the database at a time. We could specify a more complex query, but we want to include all of the data in the XML for now. There's a lot of good documentation from Apple regarding fetch specifications and data access, so I am not going to focus on it in this article.

In the above code, I left out some of the work of node building for separate methods, so let us add those other methods now. Add the following code after the buildCompleteXml method closing bracket.


private static String buildTypeNode(EOGenericRecord theType)
{
  EOGenericRecord dataType = 
  (EOGenericRecord)theType.valueForKey("dataType");
        
  NSDictionary primaryKey =
  EOUtilities.primaryKeyForObject(theType.editingContext(),
                                  theType);
  return "<type id=\"" +
        (Integer)primaryKey.valueForKey("measurementTypeId")
         + "\" name=\""
         + (String)theType.valueForKey("name")
         + "\" dataType=\""
         + (String)dataType.valueForKey("name")
         + "\" />";
}

private static String buildDataNode(EOGenericRecord theData)
{
  NSDictionary theDataKey = 
  EOUtilities.primaryKeyForObject(theData.editingContext(),
                                  theData);

  NSTimestampFormatter formatter = new
    NSTimestampFormatter("%Y-%m-%d %H:%M:%S %z");                                    
  
  return "<item id=\"" +
         (Integer)theDataKey.valueForKey("measuredDataId")
         + "\" time=\"" +
         formatter.format((NSTimestamp)theData.valueForKey(
                                              "timeTaken"))
         + "\" typeId=\""
         + (Number)theData.valueForKey("measurementTypeId")
         + "\" data=\""
         + (String)theData.valueForKey("data")
         + "\" />";
}

For those who would prefer to download the code, here is a link (XML.java).

If you have not used WebObjects before, you may be wondering when we will be writing SQL. Well, we do not have to! WebObjects really makes this kind of thing very simple, so that we can focus on building cool applications.

Notice, in the functions above, that we had to pull the primary key out of the database, which would not normally be an attribute displayed to users. We are doing this because we want to be able to round trip the data, and the primary key will help us to match up data when we import it back into the database.

The measurementTypeId is neither the primary key of the MeasuredData table nor an attribute that we have specified as a client attribute in our EOModel. We are going to need to change this so that we can easily access it in our Java code. Here is how to modify the EOModel:

  1. Open the "Resources" group in the left panel of your Xcode project.

  2. Double click the "Weather.eomodeld" group to open it in EOModeler application.

  3. In EOModeler, click the MeasuredData object in the left panel to display its attributes.

  4. Toggle the diamond icon next to the measurementTypeId attribute so that the diamond is showing. This will allow our Java code to access this attribute. Save the model and return to Xcode.

    Toggle the diamond icon next to the measurementTypeId attribute so that the diamond is showing. This will allow our java code to access this attribute. Save the model and return to Xcode.

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow