Enterprise IT • 1:01:54
The component model is one of the most powerful features of WebObjects. This session covers the WebObjects component architecture, design for reuse, handling resources, communication between components, and streaming HTTP request and response requests.
Speakers: Brian Fitzpatrick, Kenny Leung, David Neumann
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
[Transcript missing]
Good afternoon, good afternoon, early evening. My name is Brian Fitzpatrick and I'm here with Kenny Leung and David Neumann to talk a little bit about reusable components in WebObjects. Now, there's a lot of different things that are reusable about WebObjects and in fact even reusable about this presentation.
So, you know, we'll talk about some things like some reusable slides. You know, every presentation I've done on WebObjects for the last four years has had this slide in it. Unfortunately, it has nothing to do with reusable components, but they look great. I mean, look at the stuff you can do with WebObjects.
This is a really nice slide from last year, WWC 2002. So this is another reusable slide. But we'd like to move on to some reusable jokes. Anybody who caught my presentation last year on optimizing WebObjects? Anybody? You still left? Still using WebObjects? We had a few jokes here.
We have a couple questions. This is a Q&A. So to sort of get everybody paying attention, waking up, I'm going to put a question up there and we're going to put up a couple different answers. When you see the answer that you think is the correct answer, I want to hear you clap. Exactly. Is that your rest pass? No? Okay. So the first question.
What's the longest method name in WebObjects? Now start clapping to the answer because these guys have prizes which are lovely WebObjects hats. Longest method name in WebObjects is it add objects to both sides of relationship with key. Oh, it gets better. It gets much better. Is it database context? We'll run login panel to open database channel.
That's a delegate, so it's kind of cheating, isn't it? Yeah, it's kind of cheating. Yeah, well. But we've got this one. Adaptive channels should construct stored procedure return values. Nobody thinks that's a long... You see empty space down there. You're expecting something a little bigger? We do have one more that's a little bit too long to fit onto this one screen. So, anyway. So what is the most popular WebObjects movie this summer? We have a lot of movies out this summer. - I Need Nemo. - I Need Nemo. - Oh, come on. We have the NS Matrix Reloaded.
We have Xcode 2, Code United. That was a popular one. I don't hear any clapping. NSD Bugrats? Did anybody catch that? Terminate Application 3, the rise of the virtual machine? Or is it finding EO? Okay. What's the best name for the release notes to get people to actually read them? Is it "Don't Read Me"? "Nothing to See Here"? "EOEditingContext.java"?
[Transcript missing]
Okay.
We got all that out of the way now. Now we're going to talk about actual reusable components. We're going to talk about a number of different things. But the first thing I want to point out is that this is an advanced session. A lot of people in the past have asked for an advanced session.
They want a session where we can talk about doing some stuff with WebObjects that you don't normally see or figure out the first six months, a year or two using WebObjects. So the first thing we're going to talk about is commitment. Okay, when designing reusable components, if EOF is all about relationships and reusable components are about commitment and bindings, you should strive for... Am I missing something in the background here? Okay.
You should strive for loose bindings and low commitment. What do you mean by commitment? We mean frameworks to include. You want to-- Is there something funny going on here? What am I missing here? Mostly men in this room. Mostly men in this room? Oh, well, my wife's out here somewhere. Commitment. Frameworks to include. Reusable components. If you really want people to reuse your components or you want to reuse your own components, you want to have as little commitment as possible.
You want to use the least amount of frameworks to include. You want to have the least amount of interfaces and the least amount of bindings that are absolutely necessary. So if you have a component that someone's going to drag into their other component and bind up to that, you may have 5, 10, 20 different bindings, but maybe only one or two of them are required. Or it only works with enterprise objects. Maybe that's a requirement of your component. Maybe you can just get by with key value coding.
So that's what the most important thing is, is about commitment and how to deal with the bindings. So we're going to do a little introduction now, and then Kenny's going to come on and talk about bindings and how to use bindings in the most efficient manner and smart bindings and that sort of thing.
Dave's going to come on and talk about component content. I'll come back and I'm going to talk about streaming HTTP requests. Boy, we've got something great there. Then we've got some different tips and tricks and a section we like to call Dr. Evil, which is going to talk about some things that you can do with WebObjects and the WebObjects framework, but a little on the edge. And then finally, we have a few examples to show you of reusable components. So reusable components are WebObjects GUI widgets.
If you're coming from Cocoa Land, you've used Interface Builder, you've got your pallets of different things you can use. In WebObjects, you've got dynamic elements. Reusable components involve taking these dynamic elements, composing them, modifying them to make more interesting reusable components that you can reuse either within your project or from project to project.
Reusable components are subclass as a rule of will component. And an important distinction to make is there's no difference between a small reusable component, that is anywhere from one character, to the size of an entire page. In fact, when most people begin using WebObjects, most of their components are entire pages. You can edit your reusable components in WebObjects Builder. You can also use your favorite text editor, Emacs, VI, Cat, Stickies, as Steve Hayman has pointed out in the past.
We talk about child components and parent components. When a component is within another component, that is referred to as the child component. The component that contains that component is referred to as the parent. So that's a little terminology to get straight. Now, there's no limit to how deep components can be nested. They can be arbitrarily deep.
You can have three components deep. You can go 40, 50. But as you get deeper and deeper, there's a performance price to be paid. And you would use your reusable components just the same way that you would use WebObjects. Well, string, well, hyperlink. And you maybe use my component, my string, or whatnot.
There's a number of different design patterns that you're all familiar with when writing software. And I'm going to talk just briefly about some design patterns for using components in the WebObjects component model. One thing is templates, which there's a number of different ways to deal with templates. You know that your WebObjects components have three major parts, the Java file, the bindings file, and the HTML file.
Now, the Java file, you can keep the same. If you create a component and include that into your project or your other component, but if you need the view layer to look different, if you need the template part, the HTML markup to look differently, what you might want to do is either subclass that component and create a new WAD and HTML file, or you can even, there are ways to dynamically replace the WAD and HTML file in your components. Another thing, another design pattern, which I'm going to talk a little more about, is mini components.
Now, I've done a lot of different WebObjects projects, and one of the favorite things that I've used is mini components. Now, if you put everything in a very complex page into one component, not only do you wind up with an HTML file this big and a million bindings and a whole heap of Java, which is a little harder to deal with and maintain, but you also wind up with everything's kind of mooshed together. So what you start doing, one of the first steps you do is you start dividing things out. One of the first things people do is a header and a footer.
And then they'll, or maybe they'll wrap their page in a header and a footer. People will then create a menu bar or a navigation bar component, different type of things. So mini components is a pattern where you create bunches of different components and compose them. So it could also be called component composition. So if you look up here on the screen, you'll see we have a screenshot of a WebObjects application, which has a navigation bar at the very top, and it has a QuickTime VR, or in this case, it's an image map you can click on.
So you can go look at a VR. And we've got different pop-up menus. Choose a country, choose a city, and then we've got a search box, and then below that, we also have an image map, a clickable image map of the world and another search box. Now looking at this, how many components would you think on? Who thinks there's one to five components on this page? Anyone? No one? Five to ten? Five to ten components. Anyone for ten to fifteen? Okay.
We have actually, click, about ten to fifteen components. And that isn't included. It's included the wrapper component of the HTML header and footer, whatever or not. So including all these components, binding them together, provides you a very powerful way of using WebObjects components. And a lot of these components are reusable, if not necessarily from one application to the next, definitely within this application and other sections. So it's something to think about. So now to talk about bindings, I'm going to introduce Kenny Leung from, oh, you know, it's just drawing a blank. Who are you? Banzai Research Institute. Banzai Research Institute in Southern California. Thanks, Fitz.
So bindings are really the heart of reusable components. They're the mechanism by which reusable components communicate with their parents. You can call them arguments to your reusable component or the API to your reusable component. And like all API, you should try to make them lightweight and simple. We talk about bindings being pulled into the child or pushed into the parent, the child being the reusable component, the parent being whatever it is that you're using it in.
The child is in full control of pulling and pushing of the bindings and not the parent. The parent really can't do anything about that. And I've seen even experienced developers neglect this last point. You should fill out the API for your components that way. So, in WebObjects Builder, that's the little puzzle piece in the toolbar. And when you push it, what you get is a little panel that pops up.
And you can basically document the bindings that your reusable component requires. Not only that, but you can make it so that -- mark some of them as required, make it so that if one is bound, then the other -- another one must be bound, or if one is bound, then another one can't be bound.
So it really gives you -- gives the person using it a lot of clues as to how to do it, good documentation without their having to remember what all the bindings are, especially if you've got a big one that has a ton of bindings. And I've got a little request to the WAB team to actually allow us to put help in there as well.
There are many ways of handling bindings. You see from auto synchronization to all kinds of stuff, more than we can fit on the page here. Unfortunately, there's not one way we can say is better than all the rest, except to say that auto synchronization is probably not a good idea for reusable components. Basically, the best thing to do is learn how they all work and apply them properly in the right situation. and in the interest of time I'm not going to go through all these so don't be surprised if we skip a couple along the way.
So what is auto synchronization? It's WebObjects mechanism for automatically pushing and pulling the bindings at the appropriate times within the request response loop. Bindings are pulled at the beginning and end of the three phases of the request response loop, take values from request, invoke action for request, and append to response. They're actually pulled at the beginning of take values from request, pushed at the end of take values from request, and likewise in the other two phases.
It's the WebObjects default, but it's important to note that it doesn't preclude, if you have it turned on, it doesn't preclude manual synchronization. So you have these six points where things get synchronized for you. But if you need to do it at some other point within your request response loop, you can still call value for binding, set value for binding. It doesn't interfere one way or the other with the getting of binding values. And in the grand tradition of extra long, gratuitously long method names, you can override synchronizes variables with bindings to return false in your reusable component to go fully manual.
Now, why is auto synchronization undesirable for reusable components? One thing is it's really magical. For people first coming into WebObjects, they're like, How does this work? How does it know exactly when to stuff values into and out of my reusable components? So by doing all the handling of bindings yourself, you know exactly when they happen, where it's going on, and it takes all the mystery out of it, which I think is a good thing. Another reason is it happens more often than necessary.
If you add it all up, it's six times per component for every request response loop, and that can really add up. For display only components, you can usually get away with just one pull per request response loop, and there may be a lot of bindings that, depending on the values of other bindings, that you'll never grab, so you can get away with just not doing any synchronization on those bindings.
The other thing is you may have to worry about side effects on your accessor methods. You know, if you increment something inside an accessor method or something that you really only expected to get called once during a request response loop, now it gets called three times. So it's just more stuff for you to worry about.
The third and probably the most important bit here is that the order in which bindings are pushed and pulled is indeterminate. So if you have some kind of behavior or value that actually depends on the values of two bindings, like if binding one is null and binding two has a value, or if binding two is null and binding one has a value, you do something. When your accessor method gets called for, say, binding two, you can't be sure that the value for binding one has the right value at that point.
So I'm going to go on and talk about accessor methods with cache as one of the techniques for handling bindings. If you look at the examples that come with WebObjects, you'll see that a lot of them use this technique. And it's not rocket science. It's very simple. We use caches to improve performance, and we flush the caches at the beginning of a pending response.
Now, there's a good reason for doing it at that point, but we're not going to get into Take a look at a little code example. I'm going to try to use my wimpy little laser. I don't know if you can see it here. We're sharks with lasers coming off their heads when you need them.
So... Here it's very simple. We just say if binding equals null, then binding equals value for binding binding. That's how we return the binding. In the set binding method, we say set value for binding to push the value back up to the parent. And in the ped response, to empty the cache, we just say binding equals null.
As an extension to this, we can have default values for bindings. This is really good in keeping with the low commitment part of philosophy. If the component itself provides a default value, it's one less thing that the consumer needs to provide. And again, it's very simple. We just say if after checking -- after doing value for binding, we check again to see if the binding is null.
And if it is null, we just do set binding. And as in the previous example, set binding will just push our default value back up to the parent if it's bound, which is -- Which is a good thing, you know, the parent will need to know what that value is.
Next, we'll talk about page-level bindings. The typical way in which we see this is you've created a beautiful input component. It has a flag on it. You can have it either in a display mode or editable mode, and you want to drop a whole bunch of these things into a page. And you'd like to control them all by just throwing one switch on the page.
But, you know, it becomes a pain to bind up editable to all of these little components. And, you know, it's error prone. It's another extra thing to do. And if you nest them inside other components, you're going to have to propagate that editable flag all the way down. It's much more convenient to just have the component crawl up to the page that it's in and ask for the editable flag itself, a little implicit thing that it automatically knows about.
We can still allow manual overrides by explicitly providing a binding to one of these. So if you want, for instance, to have, for whatever reason, to have one of the fields not be editable while the rest are, you can easily control that. Similarly, you can have session and application level bindings where a component can just go to the session or the application for a flag or some value and figure out what to do.
Looking at our example here, so we check if we have a certain binding by using hasBinding, and if we have the binding, we return the value for binding. This is our manual override. And then if we don't, we just return root value for key for the flag that we're looking for. Now, root is just a little recursive method I'm not going to show here that just crawls up, calls parent continually until it gets to the top.
and again with the low commitment philosophy, we catch NSK valid coding unknown key exception so that if the page we're embedded in doesn't actually implement editable, everything is still cool and we just keep on going. And I'm going to turn it over to Dave to talk about component content.
Dave, you want to start? Okay, before component content came around, there was this thing called the switch component. And the switch component existed to allow you to create reusable components that had a region of dynamic content, something that you as a component designer didn't provide and you wanted the consumer to be able to provide this thing.
It had and still exists, I shouldn't say had, it has some... The WebObjects component architecture is a complex design that requires the existence of some other reusable components. If you have a page and you use this reusable component and you want to use some customized stuff, you've got to have this other component around to switch into it. Also, your switch component defines a set of bindings. Your reusable component design says I have binding type A, B, C, and D.
That means any component that you provide to customize, to switch in, also has to adhere to those limitations. So later on in the history of WebObjects, something called component content came around, and it let the parent define anything it wanted right there in the template. And there was no constraint on the dynamic area. You could do anything you wanted, and there wasn't even the need for passing bindings because the customized stuff was defined right in the parent directly.
Now, having said that, dissing the switch component, let me just say that it is actually still useful for certain things. You might want a component inside a framework to express itself in a certain limited number of ways, and you want to just get some type of polymorphic effect where you just have certain discrete kinds of components that do one particular thing and do it in that particular way just inside your framework.
There's also the situation where you created a reusable component that had this dynamic capability and you didn't want the consumer to have to customize anything. To them, you wanted it just to look like a black box. And the other one that's still relevant today is the need to have more than one dynamic region.
And it's to address that one that I want to introduce this concept called multiple component content. I'd imagine anyone who's used real component content has probably wanted to have more than one of these things that they could put in there so the parent could define more than one template, and in which to customize the reusable component.
And this concept I'm calling multiple component content removes this type of constraint. And in an example app that we'll be demoing in parts and that you'll be able to download, there's a source for a couple dynamic elements that implement this concept. And one's called RC component content and the other's RC template.
So I wanted to give you an example of where this might come in handy. On the screen here, we've got a page template. Almost every WebObjects application tends to have something like this. And the typical way this would be implemented today would be you'd have a component content for the body, and you might switch components for the header and for the menu. And what I'm saying here with multiple component content, the parent page that incorporated this template reusable component could define all three of those regions right there inside the parent itself.
So what does this look like from a development perspective? I've got on here the definitions for a reusable component. We've got the component.html and the component.wadfile. And this is a trivial example, but I just want to illustrate what's going on. So I've got a table and I've got two cells. One's got a top template and one's got a bottom template. And the reusable component.wadfile, the declaration file, has instead of one will component content, it has two RC component contents. And there's one new thing here.
Will component content didn't have a name, but multiple component content does. In this case, I've named the first one top template and the other one bottom template. And what this looks like to the consumer, the parent, they put one of these reusable components on the page. And you may recall for will component content, I don't need the nested elements.
That you see here. There's only one element, so I don't need one nested template to define it. Anything between the opening and closing tags of the reusable component is enough to define the customized content. But in this case, we've got more than one. So in this example, you see two things up there.
But imagine there were four or five or more defined. And in the example below, you see in the parent.wadfile, we've got two RC templates. And they have a template name of top template and bottom template. And this is how your parent tells the reusable component, I want this content to go here and I want this content to go there. Okay. So, let's go to demo.
I'm going to not show so much as just introduce. This is the example that you'll be able to download that has the example code. This is an example of a page template that defines a look. It's a complex formatted table. And I've got content here in the header and in the left and in the body that is all defined in the parent. The table itself, everything you see on the outline with this sort of Aqua effect is in the reusable component. And to better identify what is dynamic in terms of the component and the page, let me show you this one.
with the same reusable component but different content inside both of the cells. There's also a notion of what this allows you to implement something or more easily implement a concept I call view inheritance. Don't have time to talk about this whole sort of abstract thing now, but maybe we can talk about it afterwards or in the Q&A. There's also the notion of you can have conditional content.
This is an example of a reusable component that has two templates and the reusable component decides to only show one of them based on some conditional. And there's some other examples here that use component content, but I just sort of wanted to give you a little overview of where it's been used and illustrated its uses inside the example here.
Back to the slides. Thank you. And just to sort of review what's in multiple component content, why you might like this, it allows you to do away with a switch component, so you can have just your parent, you can have your three regions of dynamic content, and you're pretty much done. There's no other components that are needed, and therefore you get less complexity in this type of solution. So, let me move on to streaming requests and responses, where Brian will come up and take care of this area.
Thanks, Dave. So before I start talking about streaming request and responses, who in this room has used a non-streaming WoW file upload and run out of memory in their machine? Anyone? Who's asked for this streaming adapter for the last few years? I've been one of the people asking for this, okay? Yeah, Francois. Not you, Francois. We now have streaming file uploads, and it's all thanks to Carl Su and Francois Jouel. Let's give them a big hand, please. All these guys.
Carl almost did himself physically harm by working so hard on this. He worked hours and hours and hours. His poor hands. We now have streaming requests and responses. For those of you who are relatively new to WebObjects, in the past, if someone uploaded a file to your WebObjects application, that was pretty big. Let's say someone uploaded a 50 megabyte file into your application. The WebObjects adapter in the web server would suck it all in, and it would shift it over to your WebObjects application, which would have a copy of this 50 megabyte file in its request object.
And then, when it went through and did take values, it would create another copy of this 50 megabyte file for you to just muck about with or do what you wish, which you could then shoot to a file, a database, another server, that sort of thing. With this going on, you pretty quickly ran out of memory, garbage collection or not.
So now we have streaming requests and responses. When someone uploads, you can use a reusable component. Now, this is a component that is way reusable. We'll file upload. Depending on what you bind to it, you can... You can get the standard no streaming WebObjects file upload. Bind to the data binding. You get just what you used to have, which is fine for a lot of different things. If you know people are only going to be uploading small objects or small files and that sort of thing.
You can use the stream to file path binding, which allows you to just simply specify a path, and the file will get shot off to that. You can use the output stream binding or the input stream binding. So there's been some confusion about which one does what. So we'll start off talking about stream to file path. Actually, I believe there's an issue or two with stream to file path, but that's being worked on right now. You provide a path. WebObjects streams the data to it.
It's just that simple. Come up with a simple Java line string, and your data is going to wind up there. You don't have to create any stream objects. You just come up with a file name. You can also set the overwrite binding if you want to make sure that the user doesn't overwrite an existing file.
And the other neat thing about this is that, you know, how Kenny said earlier that you don't know, it's nondeterministic, which order the bindings in a particular component are filled out. However, this makes sure that the file name binding is set first for you so that you can take a look at that binding and perhaps come up with a different output stream, I'm sorry, a different file path to write to based on that.
Input stream versus output stream. So output stream is the easiest way to take advantage of streaming requests. The data is streamed for you during take values. You have to, by the time your action gets a hold of the request, the data is already where it was supposed to be. So piece of cake, you're ready to go.
However, you need to create the output stream. So you have to come up and create a Java output stream, which might be to a file, to another server, to a database, whatever not. It's up to you. And the other nice thing about this is you can have more than one file upload on your form, and it can be in any order. You can have text boxes here, file upload, more text boxes, buttons, multiple submit, that sort of thing.
So if you really need a lot of control about data that someone's uploading, you might want to use input stream. Now input stream is really fascinating because you are sort of taking part into the whole take values from requests. You're really getting in, I'm sorry, you're taking part in processing the request.
You're getting in and handling part of the take values section. So what you do is you set up this input stream, and then you read from it. WebObjects points the data at it, you read from it, and then you decide what to do with it. Now this is really fascinating because what you can do in either a component or a direct action is you can get a hold of this input stream and say, hang on a second, I want to make sure that nobody's sending me up a copy of Oracle 8.
You get your request object, then you get your multi-part iterator object, and you can ask it how many bytes are remaining in your request. And it'll tell you with very close exactness, and it's not exact, about how much is left in your request. So that's a great thing for people I've talked about in the past of having issues with someone mistakenly uploading something really huge. Other thing to remember with this is that you can only use one file upload. and you can't use multiple submit.
So you get more control using input stream. Maybe you don't want to write anything in full. Maybe you want to process the data or send it to another server. So you can do all these different things with your input stream. Now, one of the things I want to point out is that you can use these as a component action or component action, as some people say, or you can use them as a direct action.
Now, if you use a direct action with an input stream, you can use the WoW multipart iterator, which is documented beautifully, to go through, to basically do the take values part yourself. You get ahold of this iterator and you say, "Give me the next thing. Give me the next thing." It'll hand you all the form values and then it'll hand you the file upload, which you can stream off to somewhere, and then you can continue going, more form values, another file upload.
So that you should only use with direct action. That's the WoW multipart iterator. Really great stuff. So streaming responses. Okay, so if streaming requests weren't enough, these guys decided to go ahead and implement some streaming responses. In the past, if you had a file to download to the user, for example, dynamically created graphic, a JPEG or a PNG or a GIF or something, what you would do is you would override appended responses in your component. You do set content on the response. You set your content type, and then you shuffle it off, and you're done with it. However, that means that, of course, you have to have in memory the entire thing that you're going to stream down at the client.
With streaming responses, you create an input stream, you assign it to a WoW response by using set content stream, and you return the response and you're done. It's just that easy. And your memory is going to stay at a constant rate. So that's it for the streaming request and responses. Again, thanks to Francois and Carl for the hard work on that.
Got a couple topics, and Kenny's going to come up here and give a couple topics. What I want to talk to you is about something I've seen by looking at various code bases over the years. People have difficulty sometimes creating reusable components because of, they trip over what I call just initialization of certain things.
And the crux of the problem comes because you start creating pages, and then later you may start creating reusable components. And even though they're the same thing, and that they both inherit from one component, there are differences in how you interact with them when you're creating them. So with a page, you create it, you set state into it, and then you return it.
And with a reusable component that appears on the page, the system is doing the creation, and bindings are the things that are being pushed into it, and you don't have direct control over it. So the question becomes, when is it safe to initialize supporting structures? This is more than just getting bindings here. It's creating that list that's driving a pop-up button. It's filtering something, a bunch of singletons, just creating a bunch of stuff basically one time only creation. You don't want to necessarily do it over and over again.
In creating these supporting structures you may need bindings, you may not. It may involve going to the database or it could be expensive. So you only would want to redo it unless it was absolutely necessary. So I'm going to actually give you a solution, the one that I prefer, the way I've approached this problem. And that's just to construct things lazily.
This is a pattern used throughout WebObjects and EOF. It's not just for performance. It's something I found simplifies this whole problem. So basically the way it works is it's an extension of a pattern that Kenny talked about earlier. A list of stuff. If it's not there, create it. And if it is there, just return it.
Now, you know, why go to the trouble of having that method with that type of a format when there's a constructor laying around? I just want to sort of go over some of the things where I've seen people try to do the same thing in different places and some of the pitfalls with that. So why not a constructor? Well, one reason is when you're in the constructor, you don't actually have access to the bindings.
So suppose you needed access to that, then you couldn't put it there. If you didn't need bindings, you still would probably want to do it in the thing I suggested rather than this because you might create objects unnecessarily. You're in the constructor. The page hasn't rendered at all yet.
It may turn out you don't need half the things that are on the page, that could be on the page because they're being hidden by conditionals or something. And then another point there, Another point there is, what if you need to change the list later? There's issues there with cache and validation since the constructor is after all called only once. The other thing is, well, OK, fine, I'll put it in Awake, but you still have some of the same problems. Again, bindings aren't available.
Probably the next best place to try and put this sort of thing is in AppendedResponse. But again, you might create objects unnecessarily because if you put it in AppendedResponse, you need to do this before you call super. So the reason-- well, I guess I want to-- one more thing to talk about here.
This is a workaround I've seen. Just don't do this. But anyway, this is something I've seen. I just want to highlight it. If you've seen it in your code, maybe you should pull it out. People want to use that constructor really bad. They want to put the stuff in the constructor, but they don't have access to bindings. They just say, I know what I'll do.
I'll take this stuff and I'll put it in the session, and then I'll put these things in the session in my page, then I'll return my page, and then the component will construct itself. It'll pull this stuff out of the session, and hey, I don't got any problem.
I've avoided the whole deal with not having access to bindings, and my constructor's only called once. And the downside to this is I've got a more complex session. It's less reusable because now you've got all this external coordination that's required. The page that's returning this thing has got to know something about the components that are on the page that you're returning. And again, you have some of the other limitations I mentioned on the previous slide.
So to summarize the advantages of lazy initialization, instead of coordinating, you let your reusable component coordinate things itself. Construction is deferred until bindings are available. That means the only time you would ask for a list of states that are populated in a pop-up button that you fetch from a database would be in either take values from request, invoke action, or append a response. And those are also the places where bindings are available. So that problem is kind of solved.
And if the list is never needed, it's never created. So this is one of those rare situations where the thing that is good for performance is also good for making your code as simple as possible. And the fourth point there is a bit subtle. You get easy cache invalidation.
Instead of you going, every time you make a change, explicitly changing something or rebuilding it every request and append a response or some other place, all the change agent does, the code that makes the affecting change, all that code does is nulls out an instance variable. And if the new list is never needed, it's never constructed. And more importantly, from a simplicity standpoint, as long as consumers are only asking for the accessor, and they're never actually asking for the instance variable, then the consumer never worries about what's going on underneath it. So.
Getting to this next topic, topic number two. I call this thing the mysterious take values failure. I couldn't think of a better name for it, and I even kind of got criticized for this, but maybe someone will give me a better name. Anyway, let me just summarize the problem here. Some but not all the changes are missing. You fill out some stuff on the page, you submit the page, and some stuff in this text field shows up, and this checkbox shows up, but these other things aren't there. Okay, that's weird.
Number two, on occasion you see exceptions thrown in the take values from request process. Writing take values from request, your code isn't even called, and you're like, is this bugging WebObjects? What's going on? And then the third point there is, and this is the kicker, you've noticed that you've rearranged elements maybe sheerly by accident, and the problem goes away.
So like... What's going on? To illustrate what's going on, let me give you a more concrete example. Let's assume a very simple page. You've got a checkbox, you've got a conditional, and inside that conditional is a text field. And it turns out that the setting in the checkbox controls whether or not the text field is visible.
So it's checked. The user sees the checked checkbox and they uncheck it. And they type some stuff in the text field. They hit submit, and what happens on the server is the server extracts that value from the checkbox. And as far as the server is concerned, the text field doesn't exist anymore. It's hidden. The user sees it in the browser, but as far as the server is concerned, that thing's gone. So it's not going to ask for the value.
The value is in the request. Everything went over OK. Everything was fine on the browser. It's just that the page just at the very last minute went, no, I'm not going to pull that. So the solution to this would be rearranging the page. You might just-- if you put the checkbox after the text field in this example, then it would in fact get the value in the text field and the value in the checkbox. And to summarize the basic condition of the problem is if you are doing things and take values from request, if the user is submitting changes which change the structure of the page, you could be headed for this problem.
So there's two solutions to this. There's the brittle solution, which is, well, I don't have a lot of time, so I'm just going to take the checkbox and I'm going to move it down here. Done. I'm going skiing. I'm going to do this. I'm going to do this. I'm going to do this.
I'm going to do this. I'm going to But it's going to get chewed out on Monday when the design people rearrange the page and everything looks better to them and your app doesn't work. Or worse, someone did this in design and they didn't even bother sending it through QA because they didn't change any code, so hey, there's no big problem. And these exceptions are flying all over the place and you've got to come home from Tahoe. So that's no fun.
So what I suggest you guys do is if you have things like the checkbox example, take that state, put it in a holding variable, and take values from request in your reusable component before you call super, extract from the holding variable and put it in the ultimate storage.
That way if you're retrofitting this back onto an app that may have more than one action, you put the change in one place and all the rest of your code on the page doesn't have to change. If you only have one action, then it's okay to put this kind of thing in the action method if that's more convenient. Getting on to the next topic is Kenny.
So the next topic is obtaining values from objects. It seems deceptively simple. Why am I even talking about it? Typically you run into this when you have a component that displays a list of objects or takes an array of objects for a binding, so it's trying to display a list, a custom pop-up button or a table component or something like that. And the problem arises, I think, because people try to encapsulate too much into their reusable component.
The whole idea is for it to be functional, so they try to insulate the consumer from the innards as much as possible. So what beginners typically do is they have a binding for the array of objects, and then they have a key binding, which they take in, and then as the component -- as the reusable component iterates over the list, they call value for key on the object to get a value to display.
As it turns out, this isn't very flexible. It's better to make the consumer provide the item and display string binding instead of a key. The advantages being the objects being displayed then don't have to actually respond to key value coding because you're not calling value for key into it. WebObjects has another neat trick to do key value coding on objects that don't actually respond to key value coding.
And also the parent is free to use custom methods to generate the value. So if you want to derive some value off an attribute of the object that's not already in the object, this gives you a lot more flexibility. Let's take a look at an example here of the not-so-flexible situation.
So we have the list binding and the display key binding in the parent where you use it. In the reusable component, we're repeating over a label. And in the WAD of the reusable component, we have value equals display string for the string we want to display, and we're doing value for key here in the reusable components The more flexible version is we make the consumer provide an item, an item binding, and now the display string, instead of being a constant, it says display string, so bind to my method display string. And the HTML stays the same. The important thing here is the WAD. You see that item, the item binding in the repetition is now caret item, which means it's pushing that item back up into the consumer every time during the repetition.
And the display string is also caret display string, which means instead of using my method to get the display string, use my binding value of display string. And in the parent here, you see it's returning the name bracketed by square brackets, so a little example of derived value.
Now, if you didn't want to have a custom value for the display string, you can just here in the parent's WAD, you can say display string equals item.name instead of display string, and you can get rid of the display string method in the parent altogether. It makes things lighter weight for everybody.
The next tip is using WoW component content in tables. It's kind of an extension of the same mentality as before. People tend to, when they write their first table component, have dual repetition inside their table component. And they repeat all the cells within their reusable component. Then what ends up happening is, well, they want this column to be left justified and this column to be right justified, so they add a justification binding.
And then they want one to have bold font, so they add a font binding. And then they want another one to have a larger font size, so they have a size binding. And it eventually gets to where... you have an infinite number of bindings to try to configure your table, and it's still not as flexible as you want it to be.
So the solution is to put more work onto the consumer and have the consumer provide the table cells themselves in WoW component content. And this allows the parent to do anything. You can put images in your cells, hyperlinks. You can make multi-line cells, colored cell backgrounds, whatever it is you want. So taking an example -- or taking a look at the not-so-flexible version. Whoops.
We see here that the list is passed into the reusable component and the parent, passing in headers, display keys, display align, display style, and then the reusable component has the dual repetitions, the row repetition and the column repetition with the TD tags and the TR tags being repeated.
In the more flexible version, We see that now the parent has a lot more stuff in it. In the HTML, it now is bolding the first column and centering the second column and right aligning the third column. And we have a finite list of bindings. And the table, the reusable component now just contains the TR tags but not the TD tags. And this example is a little bit broken, forgot the wool repetition tags.
But it maintains control of the TR tags so it can still do things like alternate row colors and highlight a row for a selected row. Okay, that brings us to the Dr. Evil segment. You know, sometimes there are some techniques that are so handy that you just have to use them, even though you know you're going to go to hell for doing it.
So the first one is the parent talking directly to the reusable component. I said before that the child is totally in control of communicating with the parent via bindings. Of course, as in all things, that's not quite true. What we can do is at the beginning of a Pender response we can do set value for binding this to a binding value. Now, then whatever the parent has bound to that binding value takes on the value of the subcomponent, then the parent can start talking to the subcomponent.
You might want to use this in cases where no number of bindings is flexible enough. You just need to be able to talk directly to the object. And it's important to note that the value is not available until the child starts generating its response. So you may want to do your communication like inside a set method or something like that, or after the child starts a Pender response, it may get a binding which will signal to the parent that it can start now talking to the child.
As a fallout of this, you can do something that's also otherwise impossible. Allow two sibling components to communicate on the page. If -- as the page is generating its response, the first sibling will push itself into a binding. Some other component further down the page can pull the binding and suddenly you have two siblings talking directly to each other. Be careful when doing this.
The next topic is array bindings. A lot of times you have a lot of bindings that are just simply arrays of string constants. And you don't want to write a whole bunch of little bits of tedious code to create arrays of string constants because the syntax in Java is almost as bad as it is in C.
So what we can do is just use a little trick, use a method called -- we can call it array binding named. And it just checks a binding to see if it's of the type NSArray. It just passes it on through. And if it's a string, then it just assumes it's a comma-separated list and uses components separated by string to pass an array back. And now I'm going to bring Dave and Fitz up and -- And we're going to talk about the rest of these.
Okay, one more thing and then we'll get on to just kind of go into the examples a little bit and this will be the close of the formal part of this sucker. I want to talk about smart bindings. This is just a name I'm going to come up with. I'm really bad at naming things, so anyway.
I want to address a situation that you may or may not have. I've run into this situation where I've had hundreds of stuff on the page and I just need to do some trivial thing. I wanted to like hell to stick it in the declaration file, but we don't do that in declaration files, so you end up having a whole bunch of trivial methods to do that sort of thing. The kind of thing I'm talking about is like an example we'll see up there. You might have a path.
You might want to append something to the front. You might have a lot of low strings and you might end up having the same basic method, but it takes a lot of time. You might have a lot of arguments and you have like a gazillion different constant arguments you need to pass to it.
Now, the solutions to this type of miniature problem is you can create a little component that performs the intervention and then you're not adding code to your page, but now instead of having a low string, you've got your special trivial string that you've got everywhere. That's kind of unsatisfying. The alternative is dozens of trivial methods, but there's one other alternative called the smart binding. To illustrate what that means is I want to give you an example from something I had to deal with.
I had this page and it had a customer's order history. And therefore there were an enormous amount of totals, money totals on the page. And I ended up having to have literally hundreds of methods like those up there. Order detail subtotal, blah, blah, blah. And all these guys did was turn around and do value for key path on the page, got the value, and then they did some currency conversion on it.
And so what I was able to do is I was able to do some key value for key path. This is the way that all the key value coding happens from your component into everything else. You might override it and do certain special stuff. Like in this case, it looks for native currency and the at sign inside the key path. And if it finds it, it does some special processing. Now, there's a version of this kind of taken to its logical, you know, logic, but it's a little bit different.
This is an obnoxious extreme called Woe OG&L. I believe it's part of a certain project. But anyway, even if you don't go all, you know, use that technique, this can be quite useful. Imagine sticking something like this and a lot of similar things in an abstract component that is just used, you know, throughout the application and then, you know, you've done away with lines and lines of code, trivial code.
Okay, so now if Kenny is going to hell for what he did, I'm sure I'm going to be submitted to something much worse like having to write VB code for the rest of my life or something for this one. This is sort of just like plant a seed in your head about some of the things you can do to really abuse the WebObjects framework.
WebObjects components, the dynamic elements that ship with WebObjects, really know how to display themselves. You can do, like WoeString, it can display a string. WoeHyperlink knows how to display a hyperlink and how to provide a link and all the jazz that gets you to another action in your WebObjects application. You can actually develop your own components that sort of subclass Woe components. So, for example, up here in the screen we have WoeString. You can make MyString or MyRepetition or MyImage and that sort of thing.
And here's an example. You can make these components so that they know how to edit themselves. So if you take a reusable component, say MyString, for example, and you set it up in a little conditional so that if it's in display mode, it'll display itself just like you would see when a user's looking at your page in your app.
But edit mode would allow the user to maybe edit the binding, the component, change the content of whatnot. And finally, you could even... You have another mode that would write itself to disk so that it would know what to do. You say, write yourself to disk. And it's MyImage. And it would point to the image that someone had configured it to point at in edit mode.
Okay? So that's... And last but not least, and this is what I did, is I created this whole tree of components. So each one had MyString, MyImage, et cetera. And I linked them together. And if you add a little pop-up of other components, you can sort of allow the user in edit mode to add more components and add a repetition.
And then add other things with HTML around it. And what you're essentially doing at this point is creating WebObjects components in a page on the fly. And then archive them all in XML, stick them in the database. And you can pull it out and edit it again at some point right on an HTML page. The example that I'm using here is I created an application that basically allowed people to create websites.
So it's really on the border of abusing WebObjects, I'd say. But, you know, it's one of the things that you can do. So, Ken, we've got a little bit of time to look at some examples. You've already seen some of mine, so I want you guys to show one of yours.
Got a couple examples here of the table component here. Oh, look at that. So this is an example of a table component that uses WOL component content for its columns. And as you can see, it's got row highlighting, but you can still have images and bold or anything you want.
This is actually showing -- I'm sure you're familiar with the movie database. So it's actually, you know, able to show a too-many relationship here. Let's see, where are we here? Oh, here we go. Where we have more than one item across too-many relationship, and we've got multiple rows going on.
and another one is an EO validation framework where the validation messages that EOF spits out aren't the easiest to show in your UI, but this is a high commitment framework that involves a lot more other objects and makes you commit to using like a subclass of EO editing context in order to do this kind of stuff. But you can make error messages that show up right beside the fields that are being entered, and these are actually bubbled up from the EOs themselves.
I've got a couple of simple little reusable components here that are just more of examples of little widgets or whatnot you could come up with. I don't know if Steve Heyman's here, but this is one I got from him, which is really a lot of fun. SQL Logging.
So you could turn that on and off with this little widget. Sort of a helper to help your programming. So you notice it's currently true, and if you look up there, you'll see that we printed out a little bit of SQL debug stuff. And turn it to false, and all you see is false. So it's something you could drop in, have it show up only in development mode, and that sort of thing.
So an example of a helpful widget. And also a reminder that sometimes it's useful to develop little tools to help yourself in developing an application. This is a great one I got from David Black, who works in my group here, which is a reusable calendar component, which I've made really big, and now I'm showing it on a really small screen. This is a great example of loose bindings. He's got about a million different bindings for this calendar component, but all you're required to do is bind it.
So you can bind in an entity and say, hey, this particular attribute is a date field. And in this example, I've selected August 1999 in the movies database because it has two separate movies occurring in that month. And you can tie actions, which I haven't done, to the movies themselves, or the objects themselves. So you can go look at them or get further information from them. And you can tie an action to the date and go do further stuff with that.
And one last quick little reasonable widget I'll point up here is not this one. It's this one. It's a button widget. When you're writing a create, read, update, delete type application, when you're doing a lot of dealing with data, that type of stuff, you find yourself putting the same four buttons in a page or maybe three buttons or one button. So what we did is we created this button bar that when you look at it in HTML, it looks just like the top one right there. It's like all these different buttons.
And then you just bind action methods from your parent component into that, and then it'll go ahead and show it. So below that, you see we only bound cancel and save. And those went ahead and only showed those buttons. But it's the same exact component that shows the price on that screen. I think we're over now, so I think that's it. Yeah.
I forgot to mention Project Wonder. One more thing. We forgot to mention Project Wonder. If you're not familiar with it and you're doing WebObjects programming, you should get yourself to a web browser as soon as possible and check out the reusable components that these guys have implemented from low commitment to high commitment stuff and the woe OGNL stuff. And the frameworks, a lot of the stuff.