Using Images
So, what good is a Web page without some images? I say the key to a good looking Web site is to go heavy with the tables, and then pile on the KBs of images. (But then, I haven't won any awards for Web site design, so you probably shouldn't take that advice...)
There are a few ways to add images to your components. One way is to make the images part of your application and display them using a WOImage dynamic element. For most situations, this is appropriate method.
Another way is to bind the URL for the image to one of the WOImage bindings. This is useful if you are reusing images that already exist on a HTTP server.
It's fairly easy to add images to your application. The first thing you need to do is add the images to your Web Server Resources suitcase. This is done by either double-clicking the suitcase or by dragging the images from the file viewer and dropping them in the suitcase (see Figure 3.22). Next, you can drag the image from Project Builder to WebObjects Builder.
Figure 3.22 Drag an image to your component from Project Builder to WebObjects Builder to create a WOImage dynamic element.
Dragging or dropping the image from Project Builder to WebObjects Builder will create a WOImage dynamic element, with the filename bound to the name of the image. Table 3.6 lists the bindings for a WOImage.
Table 3.6 WOImage Attributes
Attribute |
Description |
data |
This should be bound to an instance of NSData, which is a class that stores a blob of data. This binding is used when the images are either retrieved from disk or database or are created dynamically. If this is bound, the mimeType binding must also be specified. |
filename |
Specifies a filename for a file in the Web Server Resources suitcase or in the framework specified by the framework binding. |
framework |
If the image is in a WebObjects framework, it is the name of the framework. Frameworks will be discussed in Chapter 11, "Creating Reusable Components." |
key |
When using the data binding, the WebObjects Resource Manager will cache the data according to the key specified in this binding. If this is used, the application will be able to use the cached data rather than reload it. |
mimeType |
The mime type of the image; that is, image/gif, image/jpg, and so on. This is required if the data tag is specified. |
otherTagString |
What is displayed if the browser cannot display the image. |
src |
The URL of the image. This is useful if the images for your application are stored on an existing HTTP server. |
In general, there are three ways to use a WOImage: binding the data, binding the src, or binding the filename. If two of those bindings are set for a WOImage, it will be invalid.
WOImage data Binding Example
One of the ways to use a WOImage is to bind the data attribute to an instance of an NSData. NSData is a class in the Foundation kit that stores a blob of data as an array of bytes. This gives you a lot of flexibility: You can store and retrieve image data from the database, you can manipulate image data, or you can generate images on-the-fly, similar to the way the Street Mapping Web sites work.
NSData has only a few methods (see Table 3.7), mainly because the purpose if the class is to provide an object-oriented interface to an array of bytes.
Table 3.7 Common NSData Methods
Method |
Description |
NSData( java.net.URL ) |
Creates an NSData object using the contents of the URL provided. |
NSData( byte [] ) |
Creates an NSData object using the array of bytes. |
NSData( java.io.File ) |
Opens the file and creates an NSData object using the contents of the file. |
public byte[] bytes() |
Returns the contents of the NSData object as an array of bytes. |
public int length() |
Returns the length, in bytes, of the contents of the object. |
An example of using the NSData class is modifying the Random Numbers example to display a random image. Assume that there are six images in a dice directory. The images are shown in Table 3.8. These images are available at the book's Web site: http://www.wowack.com.
Table 3.8 The Dice Images
Image |
Filename |
one.jpg |
|
two.jpg |
|
three.jpg |
|
four.jpg |
|
five.jpg |
|
six.jpg |
We need to create a method that will return an NSData object that represents one of the random images every time. The easiest way to do this is to create an array of filenames, and randomly choose a file to load and display. The code for this component is given in Listing 3.4.
Listing 3.4
The Main Component for the RandomDice Application
import com.apple.yellow.foundation.*; import com.apple.yellow.webobjects.*; import com.apple.yellow.eocontrol.*; import com.apple.yellow.eoaccess.*; import java.io.*; public class Main extends WOComponent { String [] filenames={ "one.jpg", "two.jpg", "three.jpg","four.jpg", "five.jpg","six.jpg"}; String basePath="d:\\WOProjects\\dice\\"; public int randomNumber() { return (int)(Math.random()*6.0); } public NSData randomImage() { String filename = basePath+filenames[this.randomNumber()]; File file = new File( filename ); return new NSData(file); } }
The filenames instance variable stores the filenames, and the basePath instance variable stores the location where the files are stored. Replace this with the actual location of the files. The double backslashes are used because the filename is a string, and the backslash is an escape character. Therefore, \\ represents one backslash. If you're specifying a path on the Mac, you simply need to use the forward slash. For example, if the dice directory is in your home directory under the images, the basePath instance variable would be set as follows:
String basePath="~/images/dice/";
For complete cross-platform compatibility, get the file.separator Java system property using:
System.getProperties().getProperty("file.separator");
Another change in Listing 3.4 is the randomNumbers method. It now returns a random number between 0 and 5.
The biggest change is the addition of the randomImage method. This method returns an NSData object that represents one of the filenames specified in the instance variable array. The complete filename is calculated based on the basePath and filenames variables, and then the File object is created. This can be used to construct the NSData object that is returned. After we have this code, displaying the data will be easy.
Add a WOImage to the Main component in WebObjects Builder, and bind the values according to Table 3.9. Save the component and the code, and build your application.
Table 3.9 WOImage Bindings for the Dice Example
Binding |
Value |
data |
randomImage |
mimeType |
"image/jpeg" |
Where Are the Web Server Resources?
WebObjects does a good job of handling the resources such as images and text files for you. This is extremely useful most of the time because you are freed from the mundane task of keeping track of files and directories. However, it can get in the way sometimes, such as when you want to retrieve the image for a different reason, or if you want to find the relative path to another resource.
Resources Versus Web Server Resources
Resources that are not going to be sent to the client can be installed anywhere on the server. Examples of this type of resource are the model file, lookup files, configuration files, and so on. Resources that are to be served to the clients must be installed in a location within the Web Server's document root directory. When your application is built, it is placed in a .woa directory. Two directories are inside that directory: Resources and WebServerResources. The application executable is placed inside the .woa directory. Figure 3.23 displays the directory structure for the RandomDice application.
Figure 3.23 The directory structure for the RandomDice application.
When the application is installed, the contents of the WebServerResources directory are copied into a directory within the document root of the Web server. This is set in the WebServerConfig.plist, which is found in the \Apple\Library\WebObjects\Configuration directory on Windows and the /System/Library/WebObjects/Configuration directory on Macs. An example of this file is given in Listing 3.5.
Listing 3.5
The WebServerConfig.plist
{ //** This configuration file is used by WOF //** to compute startup parameters. DocumentRoot = "d:/inetpub/wwwroot/"; WOAdaptorURL = "http://localhost/scripts/WebObjects.exe"; }
Programmatic Access to Resources
It's common to want to have access to the resources within the project. There's a need to access these resources through the file system and another need to access resources by providing URLs. The WOResourceManager is used to retrieve the files either way.
To retrieve the WOResourceManager, use the WOApplication's resourceManager() method:
public WOResourceManager resourceManager()
The WOResourceManager contains two methods that are used to return file paths: urlForResourceNamed() and pathForResourceNamed().
urlForResourceNamed()
The declaration for the urlForResourceNamed() method is as follows:
public String urlForResourceNamed( String fileName, String frameworkName, NSArray laguageList, WORequest request )
The urlForResourceNamed() returns a path on the Web server to the resource given in the filename argument. The resource name is the name as it appears in the suitcase in Project Builder. If the resource is contained in a framework, give the framework name in the second argument; otherwise use null. You can also specify a language list for multilingual applications, or null for a single-language application. And, you will need to pass in the current request so the URL can be generated correctly. The URL returned can then be used in a hyperlink.
pathForResourceNamed()
The declaration for the pathForResourceNamed() method is as follows:
public String pathForResourceNamed( String fileName, String frameworkName, NSArray laguageList )
This method returns the absolute file path to the resource given the name of the resource. Similar to urlForResourceNamed(), this method can compute the path given a framework and list of languages. Unlike urlForResourceNamed(), a WORequest is not required.