PAGE 95
Benefits of Reusable Components World Wide Web Wisdom, Inc. Please come visit us again! The thirteen lines are reduced to one, which positions the WebObject named NAVCONTROL.
Chapter 6 Creating Reusable Components the World Wide Web Wisdom company could change the look of the navigational controls in all of its applications by changing this one component. If your application’s pages are highly structured, reusable components could be the prevailing feature of each page: World Wide Web Wisdom, Inc.
Benefits of Reusable Components Figure 28. An Alert Panel This panel is similar to the navigation table shown in Figure 27, but as you’ll see, most of the component’s attributes are customizable.
Chapter 6 Creating Reusable Components the alertTitle and infoString attributes (leaving the other attributes private) using this AlertPanel.api file: Required = (alertTitle, infoString); Optional = (); See the WebObjects Tools and Techniques online book for more information. AlertPanel is one of several components included in a sample application called ReusableComponents. This application demonstrates and documents how to create and use reusable components.
Intercomponent Communication For reusable components to be truly versatile, there must also be a mechanism for the child component to interact with the parent, either by setting the parent’s variables or invoking its methods, or both. This mechanism must be flexible enough that a given child component can be reused by various parent components without having to be modified in any way. WebObjects provides just such a mechanism, as illustrated by the following example.
Chapter 6 Creating Reusable Components The parentAction attribute identifies a callback method, one that the child component invokes in the parent when the user clicks the Yes or No link. The exitStatus attribute identifies a variable that the parent can check to discover which of the two links was clicked. This attribute passes state information from the child to the parent. A reusable component can have any number of callback and state attributes, and they can have any name you choose.
Intercomponent Communication invoked by the child. In this example parentAction identifies the parent method named "respondToAlert", as specified in the parent’s declarations file. Note: You must enclose the name of the parent’s action method in quotes. Now, looking at the rejectChoice and acceptChoice method implementations, you can see that they are identical except for the assignment to exitStatus.
Chapter 6 Creating Reusable Components Parent1’s Declarations File (excerpt) ALERT: AlertPanel { ... parentAction = "respondToAlert"; exitStatus = usersChoice; }; Parent2’s Declarations File (excerpt) ALERT: AlertPanel { ... parentAction = "okCancel"; exitStatus = result; }; Parent3’s Declarations File (excerpt) ALERT: AlertPanel { ...
Intercomponent Communication For the sake of illustration, consider a page that displays a value in two different text fields—one provided by the parent component and one by the child (see Figure 31). Figure 31. Synchronized Components Setting the value of either text field and submitting the change causes the new value to appear in both text fields.
Chapter 6 Creating Reusable Components For instance, it’s sufficient in the example shown in Figure 31 to simply declare a childValue instance variable in the child component and a parentValue instance variable in the parent. You need to implement accessor methods (such as setChildValue: and childValue) only if the component must do some calculation (say, determine how long the application has been running) before returning the value.
Search Path for Reusable Components 4. Build the framework. If you perform a make install, it installs the framework in NeXT_ROOT/NextLibrary/Frameworks and the WebServer resources in /WebObjects/Frameworks. You must build the framework even if it contains only scripted components. After the framework is installed, you need to set up the applications so that they can use components in that framework. Do the following: 5.
Chapter 6 Creating Reusable Components that were linked in to the application executable for a component with that name. For example, applications written entirely in WebScript use the default application executable, WODefaultApp. This executable is linked to the frameworks WebObjects.framework and WOExtensions.framework, so any components defined in either of these two frameworks can be used in a scripted application.
Designing for Reusability • Provide attributes for all significant features. The more customizable a component is, the more likely it is that people will be able to reuse it. For example, if the AlertPanel component discussed in “Intercomponent Communication” (page 98) let you set the titles of the hyperlinks (say, to OK and Cancel, or Send Now and Send Later), the panel could be adapted for use in many more applications. • Provide default values for attributes wherever possible.
Chapter 6 Creating Reusable Components This declaration specifies a value for just one attribute; all others will use the default values provided by the component’s init method: Partial Declaration ALERT: AlertPanel { alertString = "Choice not available."; }; • Consider building reusable components from reusable components. Rather than building a monolithic component, consider how the finished component can be built from several, smaller components.
Chapter 7 Managing State
Most applications must be able to preserve some application state between a user’s requests. For example, if you’re writing a catalog application, you must keep track of the items that the user has selected before the user actually fills out the purchasing information. By default, WebObjects stores application state on the server. If this doesn’t meet your needs, WebObjects provides several alternatives strategies for storing state.
Chapter 7 Managing State • Storing state information on the server. With each transaction, the web application locates the state information associated with a request from a particular client. The state information might be stored in memory, in a file on disk, or in a standard database, depending on the application. Passing state back to the client with every transaction simplifies the accounting associated with state management but is inefficient and can constrain the design of your site.
Objects and State Characteristically, WebObjects takes an object-oriented approach to fulfilling any of these state-storage requirements. Objects and State Three classes manage state in an application—WOApplication, WOSession, and WOComponent. (In Java, these classes are called WebApplication, WebSession, and Component.
Chapter 7 Managing State // Java DodgeLite Application.java public class Application extends WebApplication { public ImmutableHashtable dodgeData; public ImmutableVector prices; public ImmutableVector sortBys; public Application() { super(); String filePath = resourceManager() .pathForResourceNamedInFramework("DodgeData.dict", null); if (null != filePath) { try { dodgeData = new ImmutableHashtable(new java.io.FilePath(filePath)); } catch (Exception e) { //... } } else { // ...
Objects and State The WOComponent class defines a method application, which provides access to the component’s application object. So any component can access application state this way: //Java public boolean isLuckyWinner() { Number sessionCount = application().statisticsStore().
Chapter 7 Managing State // WebScript elapsedTime = [[self session] timeSinceSessionBegan]; //Java elapsedTime = this.session().timeSinceSessionBegan(); The application object can also access session state using the same method defined in WOApplication. The WOSession class provides a dictionary where state can be stored by associating it with a key. WOSession’s setObject:forKey: and objectForKey methods (in Java, setObject and objectForKey) give access to this dictionary.
Objects and State //Java example String componentName; Context context; String contextID; String elementID; String uniqueKey; context = this.context(); componentName = context.component().name(); contextID = context.contextID(); elementID = context.elementID(); uniqueKey = componentName + "-" + contextID + "-" + elementID; this.session().
Chapter 7 Managing State Component Objects and Component State In WebObjects, state can also be scoped to a component, such as a dynamically generated page or a reusable component within a page.
Objects and State // Java DodgeLite Main.java ImmutableVector models, prices, types; MutableVector selectedModels, selectedPrices, selectedTypes; String model, price, type; public Main() { super(); java.util.Enumeration en; Application woApp = (Application)application(); en = woApp.modelsDict().elements(); models = new MutableVector(); while (en.hasMoreElements()) ((MutableVector)models).addElement(en.nextElement()); en = woApp.typesDict().elements(); while (en.hasMoreElements()) ((MutableVector)types.
Chapter 7 Managing State // Java DodgeLite Main.java public Component displayCars() { SelectedCars selectedCarsPage = (SelectedCars)application().pageWithName("SelectedCars"); ... selectedCarsPage.setModels(selectedModels); selectedCarsPage.setTypes(selectedTypes); selectedCarsPage.setPrices(selectedPrices); ... selectedCarsPage.fetchSelectedCars(); return (Component)selectedCarsPage; } // WebScript DodgeLite Main.
State Storage Strategies • In cookies. State is embedded in name-value pairs (“cookies”) in the HTTP header and passed between the client and server. Like “statein-the-page,” cookies store state on the client. • In custom stores. State is stored using a mechanism of your own design. By default, WebObjects uses the first approach, storing state on the server.
Chapter 7 Managing State State in Server Other State in Page State in Cookies Performance can suffer if lots of data is passed back and forth between client and server. State can become out of sync, especially when using frames. Client can refuse to accept cookies. Custom Storage A Closer Look at Storage Strategies To compare and further understand state-storage options, look at the SessionStores sample application. This application presents the user with a choice of storage strategies: Figure 33.
State Storage Strategies applications—changing storage strategies midsession can cause errors. For example, imagine an application that stores state in the page during the first half of a session and stores state in cookies for the second. Now, suppose that the user backtracks from a page in the second half to one in the first and resubmits the page. The application’s strategy and the actual storage mechanism won’t match, and state will be lost.
Chapter 7 Managing State • Page uniquing by implementing pageWithName: in the session object (see “pageWithName: and Page Caching” (page 138)) A significant consequence of storing state in memory is the effect on loadbalanced applications. When an application is load balanced, there are several instances of that application running on different physical machines to reduce the load on a particular server. (The online book Serving WebObjects describes how to set this up.
State Storage Strategies
Chapter 7 Managing State • Backtracking. Because each page carries a record of the state existing at the time of its creation, backtracking can make the page state and the actual state disagree. If, for example, the user make five guesses in the SessionStores example, backtracks two pages, and submits another guess, the application will claim that four guesses were made, when the actual number is six. • Frames. Storing state in the page is a problem if the “pages” in question are frames.
State Storage Strategies Field Description domain The Internet domain name for which the cookie is valid. If, for example, the specified domain is apple.com for a given cookie, that cookie is returned along with a request to any host whose domain ends in apple.com (for example, www.apple.com)—assuming the URL is within the directories specified by path. path The directories within a given domain for which this cookie is valid. If, for example, a cookie has a domain of www.apple.
Chapter 7 Managing State NSData object is then asked for its ASCII representation. WebObjects pairs this data with names it generates and creates the Set-Cookie headers of the response page. The process is reversed when a user submits a request containing cookies. The ASCII archive from the Set-Cookie headers is converted to its binary, NSData, representation. The session object and the components it contains are then unarchived from the NSData object, thus restoring the session state.
State Storage Strategies // WebScript StateStorage FileSessionStore.
Chapter 7 Managing State // Unarchive session restoredSession = [NSUnarchiver unarchiveObjectWithData:archivedSession]; return restoredSession; } - saveSession:aSession { id request = [[WOApp context] request]; // Store data corresponding to session only if necessary.
Storing State for Custom Objects Storing State for Custom Objects When state is stored in the server, the objects that hold state are kept intact in memory between cycles of the request-response loop. In contrast, when state is stored in the page, in cookies, or in the file system, objects are asked to archive themselves (using classes and methods defined in the Foundation framework) before being put into storage.
Chapter 7 Managing State • During unarchiving, an EOEditingContext can recreate individual objects in the graph only as they are needed by the application. This approach can significantly improve an application’s perceived performance. An enterprise object (like any other object that uses the OpenStep archiving scheme) makes itself available for archiving by declaring that it conforms to the NSCoding protocol and by implementing the protocol’s two methods, encodeWithCoder: and initWithCoder:.
Controlling Session State You can see implementations of encodeWithCoder: and initWithCoder: in the DodgeDemo application, in the class ShoppingCart.
Chapter 7 Managing State much state is stored. This section takes a closer look at how you manage sessionwide state. Take care that your application only stores state for active sessions and stores the smallest amount of state possible. WOSession lets you control these factors by providing a time-out mechanism for inactive sessions and by providing a way to specify exactly what state to store between request-response loop cycles.
Controlling Component State At times, a user’s choice signals the end of a session (such as when the Yes button is clicked in response to the query, “Do you really want to leave the Intergalactic Web Mall?”). If you are sure a session has ended, you can send a terminate message to the session object, marking it (and the resources it holds) for release. A session marked for release won’t actually be released until the end of the current request-response loop.
Chapter 7 Managing State Adjusting the Page Cache Size As noted in “WebObjects Viewed Through Its Classes” (page 63), except for the first request, a request to a WebObjects application contains a session ID, page name, and context ID. The application uses this information to ask the appropriate session object for the page identified by the name and context ID. As long as the page is still in the cache, it can be retrieved and enlisted in handling the request.
Controlling Component State responsibility for maintaining any needed component state. For this reason, it’s rarely advisable to turn off page caching. Using awake and sleep Another way to control the amount of component state that’s maintained between cycles is to make use of WOComponent’s awake and sleep methods.
Chapter 7 Managing State pageWithName: and Page Caching When the application object receives a pageWithName: message, it creates a new component. For example, in the HelloWorld example a user enters a name in the first page (the Main component), clicks Submit, and is presented with a personal greeting on the second page (the Hello component). Clicking the Submit button in the first page invokes the sayHello method in the Main component.
Controlling Component State // example Application.java public Component pageWithName(String aName) { Component aPage; if (aName == null) aName = "Main"; aPage = ((Session)session()).pageWithName(aName); if (aPage == null) { aPage = super.pageWithName(aName); ((Session)session().storePage(aName, aPage); } return aPage; } Note that we store pages in the session object because we want to cache these pages on a per-session basis.
Chapter 7 Managing State A WebObjects application handles a page-refresh request differently than it would a standard request. When the application determines that the request URL is identical to one it has previously received (that is, the session and context IDs in the request URL are identical to those in a request it has previously received), it simply returns the response page that was associated with this earlier request.
Chapter 8 Creating Client-Side Components
In earlier chapters, you learned about client-side Java components. Clientside components are Java applets that your application can use instead of server-side dynamic elements to interact with users. WebObjects comes with several premade client-side components. To use them you simply add them to your application in much the same way that you add a server-side dynamic element.
Chapter 8 Creating Client-Side Components destination applets are. To determine these, it inspects the visible applets on the page and looks for some special parameters. client (browser) server page Java Applet AppletGroup Controller Association Figure 37. The Principal Objects Involved in Client-Side Components SimpleAssociation objects don’t get or set values themselves; instead, they rely on the actual client-side components to do so.
When You Have an Applet’s Source Code 1. In Project Builder, add the ClientSideJava subproject to your project. To do so, double-click the word “Subprojects” in the browser and then choose ClientSideJava.subproj in the Open panel. When you build your project, Project Builder builds both the individual Java .class files and a .jar file containing the entire ClientSideJava subproject. This way, you have the option of using WOApplet’s archive binding for browsers that support .jar files. 2.
Chapter 8 Creating Client-Side Components The value for a key must be a property-list type of object (either singly or in combination, such as an array of string objects). The corresponding property-list type of objects for Objective-C and Java are: Objective-C Java NSString String NSArray Vector NSDictionary Hashtable NSData byte[] The remaining steps apply only if the applet has an action. 6.
When You Don’t Have an Applet’s Source Code 1. Declare a subclass of the Association class. class MyAssociation extends Association { ... } 2. Implement the keys method to return a list (Vector) of keys managed by the applet. See “When You Have an Applet’s Source Code” (page 144) for an example. 3. Implement the takeValueForKey and valueForKey methods to set and get the values of keys. Use Association’s destination method to obtain the destination object (that is, the applet).
Chapter 9 Deployment and Performance Issues
After you’ve written your application, tested it, and verified that it works properly, it’s ready to be deployed for use by your customers. Before you deploy, you’ll want to perform some finishing touches. For example, if you included any logWithFormat: (or logString) statements in your code for debugging purposes, you’ll probably want to remove them before you deploy. This chapter describes finishing touches that you might want to add after you’re through debugging the bulk of your application’s code.
Chapter 9 Deployment and Performance Issues Accessing Statistics If your application has a WOStats page, you can look at the statistics that WOStatisticsStore gathers. WOStats is a reusable component stored in the WOExtensions framework (which WebObjects applications link to by default). While your application is running, you can access the WOStats page with a URL like the following: http://localhost/cgi-bin/WebObjects/MyWebApp.
Recording Application Statistics // WebScript NSDictionary *myDict = [[[self application] statisticsStore] statistics]; // Java ImmutableHashTable myDict = this.application().statisticsStore().statistics; For a list of keys to this dictionary, see the WOStatisticsStore class specification in the WebObjects Class Reference. Recording Extra Information There may be occasions when you want to have the WOStatisticsStore object record more information than it usually does.
Chapter 9 Deployment and Performance Issues Error Handling When an error occurs, WebObjects by default returns a page containing debugging information and displays that page in the web browser. This information is useful when you’re in the debugging phase, but when you’re ready to deploy, you probably want to make sure that your users don’t see such information. The WOApplication class (WebApplication in Java) provides the following methods that you can override to show your own error page.
Automatically Terminating an Application Automatically Terminating an Application Unless an application is very carefully constructed, the longer it runs, the more memory it consumes. As more memory is consumed, the server machine’s performance begins to degrade. For this reason, you may find that performance is greatly improved if you occasionally stop an application instance and start a new one.
Chapter 9 Deployment and Performance Issues users to be able to end their sessions first, you might write the following code: // WebScript Application.wos id startDate; - init { [super init]; [self setMinimumActiveSessionCount:1]; return self; } - sleep { if (!startDate) // get the start date from statisticsStore { [[[self statisticsStore] statistics] objectForKey:@"StartedAt"]; } // Compare start date to current date. If the difference is // greater than 24 hours, refuse any new sessions.
Performance Tips component’s template (the result of parsing the .html and .wod files) and information about resources the component uses. If you cache component definitions, the .html and .wod files are parsed only once per application rather than once per new instance of that component. To cache component definitions, use WOApplication’s setCachingEnabled: method. public Application() { super(); this.setCachingEnabled(true); ... } By default, this type of caching is disabled as a convenience for debugging.
Chapter 9 Deployment and Performance Issues Limit State Storage As the amount of memory required by an application becomes large, its performance decreases. You can solve this problem by limiting the amount of state stored in memory or by storing state using some other means, as described in the chapter “Managing State” (page 109). You can also set up the application so that it shuts down if certain conditions occur, as described in the section “Automatically Terminating an Application” (page 155).
Installing Applications Consider implementing a batching display mechanism to display the information in the table. For example, if the array contains hundreds of entries, you might choose to only display the first 10 and provide a button that allows the user to see the next 10 entries. If the repetition is populated by a WODisplayGroup, you can use WODisplayGroup’s setNumberOfObjectsPerBatch: method to set up this batching, and it then controls the display for you.
Chapter 9 Deployment and Performance Issues NeXT_ROOT/NextLibrary/WOApps. Thus, you can install the entire directory under /WebObjects, but doing so presents a security problem if you have scripted components. Any client can access any file under the document root, which means that if you install scripted components under the document root, you are exposing source code to outside users.
WEBSCRIPT
Chapter 10 The WebScript Language
To speed the development cycle, you may want to write your application in a scripting language. The WebObjects scripting language is called WebScript. You can write all or part of your WebObjects application in WebScript. This chapter tells you everything you need to know to use the WebScript language: its syntax and language constructs. WebScript is very similar to Objective-C.
Chapter 10 The WebScript Language id number, aName; - awake { if (!number) { number = [[self application] visitorNum]; number++; [[self application] setVisitorNum:number]; } return self; } - recordMe { if ([aName length]) { [[self application] setLastVisitor:aName]; [self setAName:@""]; // clear the text field } } Instance variables are declared at the top of the script file. In the example above, number and aName are instance variables. An object’s behavior is defined by its methods.
WebScript Language Elements In these declarations, id is a data type. The id type is a reference to any object—in reality, a pointer to the object’s data (its instance variables). Like a C function or an array, an object is identified by its address; thus, all variables declared in WebScript are pointers to objects. In the examples above, myVar1 and myVar2 could be any object: a string, an array, or a custom object from your application. Note: Unlike C, no pointer manipulation is allowed in WebScript.
Chapter 10 The WebScript Language The scope of an instance variable is object-wide. That means that any method in the object can access any instance variable. You can’t directly access an instance variable outside of the object that owns it; you must use an accessor method instead. See “Accessor Methods” (page 171). The lifetime of an instance variable is the same as the lifetime of the object.
WebScript Language Elements // assign another variable to a variable myVar = anotherVar; // assign a string constant to a variable myString = @"This is my string."; Note: The // syntax denotes a comment. You can assign constant values to objects of four of the most commonly used classes in WebScript: NSNumber, NSString, NSArray, and NSDictionary. These classes are defined in the Foundation framework.
Chapter 10 The WebScript Language For more information on NSNumber, NSString, NSDictionary, and NSArray, see the chapter “WebScript Programmer’s Quick Reference to Foundation Classes” (page 187). Methods To define a new method, simply put its implementation in the script file. You don’t need to declare it ahead of time.
WebScript Language Elements • A return type of void is not allowed: // This won’t work either. - (void) aMethod:(NSString *)anArg { ... } Both example methods return a value, stored in result. If a method doesn’t return a meaningful value, you don’t have to include a return statement (and, as stated above, even if a method returns no value you shouldn’t declare it as returning void). Invoking Methods When you want an object to perform one of its methods, you send the object a message.
Chapter 10 The WebScript Language automatically defines two accessor methods: one to retrieve the instance variable’s value, and one to change the value. For example, the Application.
WebScript Language Elements aString = [NSString stringWithString:@"Fred"]; Note that a class is represented in a script by its corresponding class name— in this example, NSString. In WebScript, the classes you use include both class methods and instance methods. Most class methods create a new instance of that class, whereas instance methods provide behavior for instances of the class. In the following example, a class method, stringWithFormat:, is used to create an instance of a class, NSString.
Chapter 10 The WebScript Language // Create a mutable string string = [NSMutableString stringWithFormat:@"The string is %@", aString]; // Create an immutable string string = [NSString stringWithFormat:@"The string is %@", aString]; // Create a mutable array array = [NSMutableArray array]; anotherArray = [NSMutableArray arrayWithObjects:@"Marsha", @"Greg", @"Cindy", nil]; // Create an immutable array array = [NSArray arrayWithObjects:@"Bobby", @"Jan", @"Peter", nil]; // Create a mutable dictionary dictiona
WebScript Language Elements Explicitly specifying a class in a variable or method declaration is called static typing. Because variables and return values are always objects, the only supported data types are classes. You can specify any class that your application recognizes when you statically type a variable or a method.
Chapter 10 The WebScript Language Control-Flow Statements WebScript supports the following control-flow statements: if else for while break continue return Arithmetic Operators WebScript supports the arithmetic operators +, - , /, *, and %. The rules of precedence in WebScript are the same as those for the C language. You can use these operators in compound statements such as: b = (1.0 + 3.23546) + (((1.0 * 2.3445) + 0.45 + 0.65) - 3.
WebScript Language Elements In WebScript, relational operators are only reliable on NSNumbers. If you try to use them on any other class of object, you may not receive the results you expect. For example, the following statement compares the addresses stored in the two string variables. If both point to the same address, the strings are equal. If they point to different addresses, even if the strings have identical contents, the statement will be false.
Chapter 10 The WebScript Language The postincrement and postdecrement operators are not supported. They behave like the preincrement and predecrement operators. For example: // WATCH OUT!! Probably not what you want. i = 0; while (i++ < 1) { //this loop never gets executed because i++ is a preincrement.
WebScript Language Elements [self application] WOComponent also defines a session method, so you can do this to retrieve the current session: [self session] Sometimes, you actually do want to invoke the superclass’s method rather than the current object’s method. For example, when you initialize an object, you should always give the superclass a chance to perform its initialization method before the current subclass.
Chapter 10 The WebScript Language Modern: function submit() { // } • Method Definition With Arguments Classic: - takeValuesFromRequest:(WORequest *)request inContext:(WOContext *)context { // } Modern: //Note: no static typing allowed. function takeValues(fromRequest:= request inContext:= context){ // } • Method Invocation — No Argument Classic: [self doIt]; Modern: self.doIt(); • Method Invocation — One Argument Classic: [guests addObject:newGuest]; Modern: guests.
Advanced WebScript Note that in this last example the left parenthesis should occur at a break between words when the modern message maps to an existing ObjectiveC method (which, of course, follows classic WebScript syntax). When WebScript transforms modern to classic syntax internally, it capitalizes this character before concatenating the keywords of the selector. Thus, any of the following are correct: super.takeValuesFrom(request := request, inContext := context); super.
Chapter 10 The WebScript Language @interface Surfshop:NSObject { id name; NSArray *employees; } @end @implementation Surfshop - (Surfshop *)initWithName:aName employees:theEmployees { name = [aName copy]; employees = [theEmployees retain]; return self; } @end Do not use separate files for the @interface and @implementation blocks. They must both be in the same file. To use the class, you locate it in the application, load it, and then allocate and initialize instances using the class object.
WebScript for Objective-C Developers The following example is a simple category of WORequest that gets the sender’s Internet e-mail address from the request headers (“From” key) and returns it (or “None”). @implementation WORequest(RequestUtilities) - emailAddressOfSender { NSString *address = [self headerForKey:@"From"]; if (!address) address = @"None"; return address; } @end Elsewhere in your WebScript code, you invoke this method on WORequest objects just as you do with any other method of that class.
Chapter 10 The WebScript Language Objective-C WebScript Methods not declared to return void must include a return Methods aren’t required to include a return statement statement Has preprocessor support Has no preprocessor support—that is, doesn’t support the #define, #import, or #include statements Uses reference counting to determine when to release instance variables Automatically retains all instance variables for the life of the object that owns them.
WebScript for Objective-C Developers • You can only use the “at sign” character (@) as a conversion character with methods that take a format string as an argument: // This is fine. [self logWithFormat:@"The value is %@", myVar]; // NO!! This won’t work. It prints the address of var1. [self logWithFormat:@"The values are %d and %s", var1, var2]; • You need to substitute integer values for enumerated types.
Chapter 10 The WebScript Language To access a component’s methods, you must store the component in the session and then access it through the session. For example, suppose you wanted to rewrite the SelectedCars component of the DodgeDemo so that its database fetch code was in a compiled object and that object directly set the value of the message variable in the SelectedCars component. You’d add the following statement to the init method SelectedCars.wos: /* Store the component in the session. */ [self.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes
As you learned in the previous chapter, when you write an application in WebScript, all values are objects, even simple values such as numbers or strings. The objects that represent strings, numbers, arrays, dictionaries, and other basic constructs are defined by classes in the Foundation framework. You use classes from the Foundation framework in virtually all WebScript applications. This chapter gives you an overview of the Foundation framework classes most commonly used in WebScript.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes Determining Equality You can determine if two objects are equal using the isEqual: method. This method returns YES if the receiver of the message and the specified object are equal, and NO otherwise. The definition of equality depends on the object’s type. For example, array objects define two arrays as equal if they contain the same contents. For more information, see the isEqual: method descriptions later in this chapter.
Working With Strings Note: The configuration of your HTTP server determines the user who owns autostarted applications. Reading From Files The string, array, and dictionary classes provide methods of the form classNameWithContentsOfFile:. These methods create a new object and initialize it with the contents of a specified file, which can be specified with a full or relative pathname. Working With Strings NSString and NSMutableString objects represent static and dynamic character strings, respectively.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes Commonly Used String Methods The following sections list the most commonly used NSString and NSMutableString methods, grouped according to function. Creating Strings The methods for creating strings are class methods, denoted by the plus sign (+). You use class methods to send messages to a class—in this case, NSString and NSMutableString. For more information on class methods, see “Sending a Message to a Class” (page 172).
Commonly Used String Methods + stringWithContentsOfFile: Returns a string created by reading characters from a specified file. For example, the following statement creates an NSString containing the contents of the file specified in path: id fileContents = [NSString stringWithContentsOfFile:path]; See also writeToFile:atomically: (page 195) .
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes – substringFromIndex: Returns a string containing the characters of the receiver from the character at the specified index to the end. Comparing Strings – compare: Returns –1 if the receiver precedes a specified string in lexical ordering, 0 if it is equal, and 1 if it follows. For example, the following statements result in an NSString that has the contents “‘hello’ precedes ‘Hello’ lexicographically.
Commonly Used String Methods Modifying Strings Warning: The following methods are not supported by NSString. They are available only to NSMutableString objects. – appendFormat: Appends a constructed string to the receiver. Creates the new string by using the stringWithFormat: method with the arguments listed.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes Working With Arrays NSArray and NSMutableArray objects manage immutable and mutable collections of objects, respectively. Each has the following attributes: • • A count of the number of objects in the array The objects contained in the array The difference between NSArray and NSMutableArray is that you can’t add to or remove from an NSArray’s initial collection of objects.
Commonly Used Array Methods Creating Arrays The methods in this section are class methods, as denoted by the plus sign (+). You use class methods to send messages to a class—in this case, NSArray or NSMutableArray. For more information on class methods, see “Sending a Message to a Class” (page 172). + array Returns an empty array. Usually used to create NSMutableArrays. NSArrays created with this method are permanently empty.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes – isEqual: Returns YES if the specified object is an array and has contents equivalent to the receiver; NO, otherwise. Two arrays have equal contents if they each hold the same number of objects and objects at a given index in each array satisfy the isEqual: test. – objectAtIndex: Returns the object located at a specified index. Arrays have a zerobased index.
Commonly Used Array Methods – insertObject:atIndex: Inserts an object at a specified index. If the specified index is already occupied, the objects at that index and beyond are shifted down one slot to make room. The specified index can’t be greater than the receiver’s count, and the specified object cannot be nil. Array objects have a zero-based index. The first object in an array is at index 0, the second is at index 1, and so on. You can insert only new objects in ascending order—with no gaps.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes Storing Arrays – writeToFile:atomically: Writes the array’s string representation to a specified file using the description method. Returns YES on success and NO on failure. If YES is specified for atomically:, this method attempts to write the file safely so that an existing file with the specified path is not overwritten, and it does not create a new file at the specified path unless the write is successful.
Commonly Used Dictionary Methods the key’s value. Within a dictionary, the keys are unique. That is, no two keys in a single dictionary are equivalent. The difference between NSDictionary and NSMutableDictionary is that you can’t add, modify, or remove entries from an NSDictionary’s initial collection of entries. Insertion and deletion methods provided for NSMutableDictionaries are not available for NSDictionaries.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes Creating Dictionaries The methods in this section are class methods, as denoted by the plus sign (+). You use class methods to send messages to a class—in this case, NSDictionary and NSMutableDictionary. For more information on class methods, see “Sending a Message to a Class” (page 172). + dictionary Returns an empty dictionary. Usually used to create NSMutableDictionaries.
Commonly Used Dictionary Methods Querying Dictionaries – allKeys Returns an array containing the dictionary’s keys or an empty array if the dictionary has no entries. This method is useful for accessing all the entries in a dictionary.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes – isEqual: Returns YES if the specified object is a dictionary and has contents equivalent to the receiver; NO, otherwise. Two dictionaries have equivalent contents if they each hold the same number of entries and, for a given key, the corresponding value objects in each dictionary satisfy the isEqual: test. – objectForKey: Returns the object that corresponds to a specified key.
Commonly Used Dictionary Methods – removeObjectForKey: Removes the entry for a specified key. – removeObjectsForKeys: Removes the entries for each key in a specified array. – setDictionary: Removes all the entries in the receiver, then adds the entries from a specified dictionary. Representing Dictionaries as Strings – description Returns a string that represents the contents of the receiver.
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes Working With Dates and Times NSCalendarDate objects represent dates and times. These objects are especially suited for representing and manipulating dates according to Western calendrical systems. NSCalendarDate performs date computations based on Western calendrical systems, primarily the Gregorian. The methods provided by NSCalendarDate are described in more detail in “Commonly Used Date Methods” (page 207).
Commonly Used Date Methods Conversion Specifier Argument Type %x date using date representation for the locale %X time using time representation for the locale %Y, %y year with century (such as 1990) and year without century (00-99), respectively %Z, %z time zone abbreviation (such as PDT) and time zone offset in hours and minutes from GMT (HHMM), respectively Commonly Used Date Methods The following sections list some of the most commonly used methods of NSCalendarDate, grouped according to funct
Chapter 11 WebScript Programmer’s Quick Reference to Foundation Classes Representing Dates as Strings – description Returns a string representation of the NSCalendarDate formatted according to the NSCalendarDate’s default calendar format. – descriptionWithCalendarFormat: Returns a string representation of the receiver formatted according to the provided format string. – calendarFormat Returns a string that indicates the receiver’s default calendar format.
Commonly Used Date Methods – minuteOfHour Returns the NSCalendarDate’s minutes value (0–59). – secondOfMinute Returns the NSCalendarDate’s seconds value (0–59).
Index
Index %@ 59 .api file 20 .html file 20, 21 .wo directory, See wo directory .woa directory, See woa directory .wod file, See wod file .
Index synchronization 85, 102–104 client-side 85–86 template 82–83 URL, specifying 53 variables 118–120 in reusable components 97 componentsJoinedByString: method 200 componentsSeparatedByString: method 193 conceptual overview of WebObjects 65–87 constants, WebScript 169–170 constructors 46–50 context ID 68, 77 context, accessing 51 cookies 126–128 count method 197, 203 createSession method 75 creating new component 76–77 creating new session 74–75 creating objects 173–174 current component 84 custom objec
Index initObject:withCoder: method 132 initWithCoder: method 132–133 example 133 input postprocessing 51 insertObject:atIndex: method 199 install 159–160 instance variables, definition 165 instance, definition 165 integers in WebScript 169 @interface 181 intValue method 194 invokeActionForRequest:inContext: method 52–53, 79–80 declaration 70 example 52–53 ISAPI adaptor 26 isEqual: method 190, 194, 198, 204 isolating errors 60 isTerminating method 135 J Java support AppletGroupController class 143 applets,
Index R recording statistics 151–153 refuseNewSessions: method 155 regenerating request page 45 registerForEvents method 73 relational operators 176 release method (Objective-C only) 46 example 137 removeAllObjects method 199, 204 removeObject: method 199 removeObjectAtIndex: method 199 removeObjectForKey: method 205 removeObjectIdenticalTo: method 199 removeObjectsForKeys: method 205 request component 44 request page 44, 73, 76–78 regenerating 45 request URL 75 request, accessing 51 request-handling meth
Index stringWithContentsOfFile: method 190–191, 193 stringWithFormat: method 192 stringWithString: method 192 subclass, definition 166 substringFromIndex: method 194 substringToIndex: method 193 super 178–179 superclass, definition 166 synchronization of components 85, 102–104 client-side 85–86 syntax, WebScript 166–181 modern 179–181 T takeValuesFromRequest:inContext: method 51, 78–79 declaration 70 examples 51 teminate method 135 template 82–83 terminateAfterTimeInterval: method 155 terminating applicat
Index terminateAfterTimeInterval: method 155 trace methods 59–60 WOAssociation 71, 84–85 WOComponent 23–24, 69–71, 82–87, 105 See also components appendToResponse:inContext: method 81 awake method 77 descriptionForResponse:inContext: 81 init method 49–50, 77 invokeActionForRequest:inContext: method 79 performParentAction: method 86, 100 sleep method 81 state 113–120, 135–140 takeValuesFromRequest:inContext: method 78 WOContext 50, 69, 83 current component 84 request-response loop 74 .
|