WebObjects • 1:13:40
This session provides a technical overview of WebObjects for new developers, highlighting the key aspects of its architecture, technical advantages, and relevance to web application development. Topics include a discussion and demonstration of WebObjects tools, design and flow of a typical WebObjects application, and a review of deployment scenarios.
Speaker: Steve Hayman
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
What day is it today? It's a holiday for Canadians, right? We don't really have to be here. We have the day off. We're going to be working next Monday. But I thought that since it's Victoria Day, which commemorates the birthday of Queen Victoria, it's a national holiday in Canada. This traditionally marks only six more weeks of winter in Canada on Victoria Day.
So I'm hopeful that the sound is on on this computer so that you can all rise and sing with me, "God Save the Queen."
[Transcript missing]
I want to show you the tools. I want you to understand the titles of the other sessions, and I want to talk about what is the deal with WebObjects 4.5.1.
It's an application server. I don't like that term, but that's what we're stuck with. It vends applications with, usually, web interfaces to the internet. But it's more than that. Most importantly, it's a collection of frameworks that do a whole lot of really good stuff for you that we'll see in a few moments.
For instance, you write apps, and they run on this square thing here, and they vend interfaces by collecting data from a bunch of different data sources, by manufacturing these objects, by exploiting relationships between the objects, and delivering a variety of different UIs to the end user. It's a developer tool. It's got a steep learning curve, but that's okay, because that means you learn a lot in a short period of time.
WebObjects works with Java. By the way, because it's Victoria Day, we'll be pronouncing it Java for the remainder of the session. And we'll be saying, "Project Builder." in the Canadian way. Works with a variety of databases, a variety of different UIs, a variety of different web servers. Open, open, open, open, open, open, open.
Where can you use it? You can develop, as Ernie mentioned, Windows continues to be a development platform, but I think the experience on Mac OS X is awful darn good. You can deploy on OS X, on Windows 2000, on Solaris, on HPX, theoretically on anything with the right kind of Java 2 environment. And you can mix and match these things as needed and start small on one little server and grow to a big hog in deployment.
You might start with one application running on a little server like this, and then through the ease and miracle of the WebObjects deployment tools, grow to a big scary complicated thing like this where you've got several copies of the same app there and several over here and multiple servers and multiple databases and so on. The hard work of managing that kind of scalability is done for you. I should do a survey here. Put up your hands if you hate it when they stop to ask you to put up your hands. People hate that? Okay, we'll keep going.
Key ideas. Web components at the front end. Components that manage, that are responsible usually for HTML. Enterprise objects at the back end that contain data drawn from databases, but they're kept apart and bound together at runtime. These components typically can... Excuse me. Let's just take a second. Okay. Hello. Oh, hello. Fine. Yeah, okay. All right, I'm going to say Panama. Okay, say hi to Regis.
Where were we? These HTML templates, come on, this is serious. These HTML templates contain this one special WebObject tag that's really a marker that says, here's where something good's going to happen. Here's where we're going to send a message to another object to cause something to happen. Steve Hayman And on top of that, there is a separate bindings file that defines the meaning of each of these tags, and a whole lot of pre-written objects that participate in this whole process.
These components at the front end typically emit strings, often HTML strings, sometimes plain text. They could be binary image data, they could be Apple script commands, they could be virtually anything. Steve Hayman They can be non-HTML components, they can be PDF-based. We have a partner, ReportMill, who's exhibiting over in the show that has a tremendous PDF-based reporting solution that really works great with WebObjects.
We have a partner in Europe, WAPObjects. We do XML natively, and I'm going to show you some XML stuff if all goes well later in the demo, for which I have 72 minutes and 30 seconds. I've got a great clock here, and I like that scoreboard. I like that scoreboard up there. Did you see there was a scoreboard to count how many mistakes I make? I mean, they could put those up for the visiting team or something.
Enterprise objects at the back end. These are the objects that implement your business rules. They're typically named after things in your business, like customers, students, courses, and so on. We have an adapter that draws the data for these things out of a data source, and we have these model files that pick a particular adapter from the vast array of adapters that we have now, and fetch data from some data source and deliver certain kinds of objects to your application.
They also automatically manage, in a very slick way, relationships between objects. You're going to see me go completely crazy with the relationships a little later. But this back end Enterprise Objects framework part is the real gem. These are pure business objects that have no notion of the fact that they are rendering HTML or rendering PDF or sending out WAP.
They simply respond to messages and deliver back an answer, and something else creates them from the database. The Enterprise Object isn't even really aware that it was fetched from Oracle or Sybase or Frontbase or whatever your favorite actually is. It's all completely managed for you in a very clean way.
These are all bound together by your WebObjects application that locates these tags, sends a variety of messages, takes the results, stirs them into the component, sends it back to the end user with literally a million and one hooks by which you can customize this entire process at runtime.
along with some advanced session management. Every WebObjects application for free has a session object that you can extend as needed. And this session object contains whatever you want in there, knowing you know that WebObjects arranges to have one session object for every distinct user who's coming to your application. You can extend this session object to manage a shopping cart or to keep track of what a user's been doing. And WebObjects sorts out the thousands of requests that are coming in and delivers them automatically to the correct session objects.
There's also some runtime monitoring tools. The Monitor tool manages that huge deployment. Remember that ugly slide I had with all the instances all over the place? Monitor takes care of making sure that they're all running, that they're all healthy, gives you statistics, restarts them as needed. Well, let's see how this actually works. I want to do a little diagram here and show you the sequence of flow of control of a WebObjects application. It's the internet up there.
And we have a web server and maybe several app servers in the database at the back end. I understand the internet has grown. I was going to put four iMacs on it this year instead of three, but we ran out of time. So just to elaborate once again what the various platforms are, that web server could be anything.
It could be virtually anything. We have an adapter that plugs into the web server and takes requests coming in from the user on their web browser and routes them to the appropriate application. And through that web server, the responses from these applications are delivered back to the end user. We have special plug-ins for a variety of popular web servers, the Netscape server, Apache, IIS. We have a generic CGI plug-in if you're running some other peculiar web server. Web server? Web server, pardon me.
And the application server has... A limitless now that is Java 2, a potentially limitless collection of machines that you could deploy the application on. Anywhere there's a Java 2 environment. This is a major step from last year. Last year we had to tell you that you could use HPUX or Solaris or Windows NT or Mac OS X server. Now you can use virtually anything with the appropriate Java runtime.
The adapter at the back end, in the past we had several different adapters, one for every distinct database, and there was a whole mishmash of which adapters ran on which servers, and a lot of restrictions that prevented you from getting, for instance, the SQL Server if you were running on Mac OS X. A lot of other combinations didn't work, but now that we've got JDBC as a pure Java way of moving the SQL commands back and forth from the database, we can talk to all the databases on all the different platforms.
So let's suppose we had a really simple application here, and we're going to follow the flow of control here to give you an idea of the processing that's going on. I'm picturing some sort of beginner application where I type my username in there, and then it fetches some info about me and says, "Hi, Steve." Well, there's really three steps that are going on here. The WebObjects application is going to take some values from that initial request.
It's going to notice that you typed S. Hayman in a form field. It's going to invoke some sort of an action, some sort of logic that says, all right, we got this submit button. What do we do now? What page do we go to? What processing do we do? And then it's going to generate a response, a stream of HTML that's going to come back to the end user. How does this actually happen? Well, a user would submit a request to a web server. The adapter on the web server would find one of many different instances, many different identical processes representing your application, and forward the request to the right one.
Your session object in there would find the WebObjects component that generated the initial page, the component that put up the "What's your name?" page, and it would study the various form values that came in. We seem to have received a text field, someone has typed "shayman" in the text field, and according to our instructions, we need to bind that to our username variable. The requesting component, then there's another step that goes through.
It figures out which action to invoke. The submit button is connected in it by a means I'll show you to perhaps a specific Java message being sent to a specific class back in the application server. That class might be a method called, that action might be a method called handle login here. Returns another component.
Steve Hayman So there'd be some Java code associated with this. They could do whatever business logic you want. I want to fetch the customer with the username that we just got, and I want to return some other page, and I want to put the customer's name in the session. That kind of thing is a fairly common paradigm. That action returns another component.
That other component is the thing that's going to generate the response to the end user. So the session loads the response component, another one of these things with WebObject tags in it. Steve Hayman It studies them. It finds the tags. It identifies what it needs to do. Steve Hayman It's going to use these to replace in this component so that it can generate the response.
In this case, it's noticing I've got a thing here called a, I've got in my HTML file, I've got this tag that says name equals username, and in this extra file, I have a definition that says username, it's a string, and you send the message customer to the session object, and you send the message first name to that object. Steve Hayman Whatever comes out of that, replace this little tag with it. Steve Hayman And all that's, that may cause various objects to be fetched from the database, all transparently.
Steve Hayman Via this enterprise objects framework. Steve Hayman We might in this case need to load some sort of an enterprise objects model that says, oh, by the way, customer objects are coming out of the cust table on Oracle. Steve Hayman And the enterprise objects framework automatically figures out whatever ugly SQL it has to generate. It sends it to the database. A bunch of rows come back from the database, and they're converted into enterprise objects.
Steve Hayman And this is all happening while you wait. It's all happening without the need for you to have any intervention here. This is a very seamless process. Steve Hayman So a customer... Steve Hayman A customer object is created with the results of that fetch from the database and populated with some data. We've got this model set up that says customers have a name, and they have an address, and they have a first name and a last name and a relationship to some other things. The object is created automatically.
We need to send the message first name to that customer object and it responds, "Steve, hey." Coincidence. And that response is substituted back into the WebObjects template. You can see it used to say WebObject name equals username and now that's replaced with this single string, Steve. So the stuff that's actually going out to the end user has no evidence that it's ever actually been through this entire WebObjects process here.
Then this session sends the plain HTML back to the user, and they are happy, happy, happy. Here it comes. Welcome back, Steve. But it's actually a fairly elegant process when you get used to it. I mean, it seems like 300 steps when I describe it here, and it seemed like 10,000 steps when I was making this slide.
Most of those steps just happen automatically for every WebObjects application. It's just one of the many great things that you get for free with this environment. And we call that the request-response loop. Request comes in from a user, and a response is generated and sent back to that user. And if you look into the WebObjects documentation, we all heard how swell the WebObjects documentation is becoming, you'll see a variety of methods like take values from requests, or invoke action, or append to response.
And these messages are automatically delivered to various components in your application, if they wish to receive them. And they can all participate in this and add their own little bits of HTML or modify state in some way as the result is going back. So that request-response loop was considerably more important to WebObjects developers one year ago, because if you wanted to do that more than 100 times a minute, you had to give us $50,000. Now you just give us $700. You can do it. as many times as you like. What a deal, what a deal.
You'll note from this that the SQL and the HTML are kept as far apart as possible. This is really a fundamental tenet of WebObjects. We keep database logic over here, database access stuff over here. We keep user interface code for drawing UIs over here. We keep business logic in the middle. And there's no need for you as a developer to worry about writing HTML yourself. We have tools that can help you do that.
Steve Hayman Or generating SQL yourself. Again, we have tools, our modeling tool that builds that model. They all figure out how to do that. Unless you want to. And that's one of the other great things about WebObjects is that if you want to, you can override virtually every one of those arrows on that last presentation and cause something special to happen in your case.
Frequently, not necessary, but a great thing to have in the bag of tools as we move along. Steve Hayman I need a brief drink of water here. Excuse me. Steve Hayman Is there really 100 degrees in South Africa? Steve Hayman Sacramento today? I mean, isn't that like the boiling point of water? How do you stand it down here? So let's talk about the tools.
Project Builder, WebObjects Builder, EOModeler. WebObjects Builder is one of the more interesting ones that you can learn all about in session 603 on the introduction to WebObjects tools. It recognizes the fact that you need to create a whole bunch of these WebObjects components in an application. And a component typically contains some HTML, like we just saw, with these WebObject tags in them. And that's, it's a directory called, let's say, main.wo with a file in it called main.html.
Then there's a second file called the wad file, love that name, the wad file, that defines the meaning of each of these tags in the first file. So you see, we're keeping anything even remotely resembling business logic out of the HTML. Just this one little tag that we put in the HTML.
Hands up, everyone who says, how come you didn't write the closing slash WebObject tag on this little example? All the, yeah, all right, all my buddies over here. Why did the font would have been too small if I did that? Technically, WebObject name equals string, and then a closing slash WebObject tag. Closing tag. You can learn all about that.
Are we going into, like, that level of detail in any of the other sessions? I don't know. But there's typically a Java class associated with each of these as well. So my main component, for instance, there's really three files associated with it. An HTML file, a WebObject declaration file, and a bit of business logic in this Java file. Java file, really? Do you really prefer that? I can't believe it. And a bit of logic that you as a developer write that defines what happens for some of these tags.
When we click on place order on the hyperlink over there, it sends this message, and it adds something to a shopping cart, and it takes us to a checkout page. You write logic like that in a Java file. WebObject combines it at runtime with these HTML and WAD pieces in a stream of often plain HTML is sent back to the end user. That would be a simple component. You're going to create a lot of these in a WebObjects application. Usually one for each page, often one for little subcomponents of the page.
You can have interesting components from your buddies and drag them into the application and reuse them in effective ways. You can have components that wrap themselves around other components to enhance what the inner one is doing. And we provide components for a bunch of common UI elements out of the box, but you typically write lots of your own using the WebObjects builder tool. Now, how do you actually make these components? They're all files, okay? You can use whichever your favorite tool is for editing these things.
But, you know, there are sort of professional level tools as well. And I don't know why you couldn't do it with CAT, although Unix hackers, maybe we'd rather use DD. You know, you could use that to create a component. All right, let's show that. But you can also use any visual HTML editor you like.
Some of them, particularly Go Live, have excellent support for managing WebObjects tags as well. And we have our own tool that we think you'll like. Now, nobody says you have to use WebObjects Builder, but it's pretty nice. Engineering has done a nice job on this thing. So this is what WebObjects Builder looks like when it's editing one of these components. And you're going to see this in excruciating detail in a few minutes here.
You have a view of some HTML in the middle with little taggy things in there that represent objects you've dropped into this HTML application. Up at the top, you have an inspector that tells you the properties of the currently selected thing. In this case, I've got that click here hyperlink selected, so you can see the properties of a WO hyperlink object at the top.
At the bottom, you have an object browser that shows you what attributes and methods are available in the collection of objects that your application currently contains. You draw lines. I can tell here that my main component has an application variable, a session variable, a product variable. It also has a place order method. WebObjects Builder has figured this out by looking around at the other tools to see what you're doing. I would like it when the user clicks on that hyperlink.
To send the message place order back to my main object so I can figure out how to get to the next page. Well, you do this by drawing a line. It doesn't look exactly like that. That was the closest I could come in PowerPoint. But you draw a line from the method that you want at the bottom to the object you want to connect it to at the top, the hyperlink in this case, and you choose a property of hyperlink objects.
Hyperlinks have a string that they can contain, and they have a direct action name that I really must read the documentation about sometimes. And they have a bunch of other properties here that are available. But I want to connect it to action, which is certainly the most popular one of all the hyperlink methods. This is the method you connect to if you want a hyperlink to actually do something.
And having done that, you'll see at the top the inspector reflects that particular change. So WebObjects Development with WebObjects Builder is an ongoing process of drawing lots of these little lines, connecting things from here to there, picking through objects in your browser down here, designing your HTML visually up here, and saving it all as one of these main.wo components. So you can do that with WebObjects Builder, or header.wo, or catalogitem.wo.
If you like, you can also work in raw mode. If you're really excited about typing raw HTML, you can dive into that with WebObjects Builder, and it will give you a view of the text of the HTML file and the actual text of the wad file if you insist on that. Occasionally that's handy.
You can also use palettes to organize your stuff. These first two over here are palettes that come with WebObjects. There's, I think, five that come with WebObjects now. I'm a bit of a palette pack rat, and you'll see some of my others later. You can create your own palettes with useful objects on them, like the amazing pluralizer that we saw last year, or a shopping cart, or a buy button, or a localizer bar. Write these little things once and put them on a palette. Then you can reuse them in WebObjects easily by dragging and dropping.
Sure, I was wondering what that one in the middle is. It's not working right now. I really wanted to show it to you. That's a shame. We'll give it a shot. If we have lots of extra time at the end, we'll give it a shot. Another important tool, EOModeler.
This is really an editor for EOModelD files, or if you want to be incredibly pedantic, EOModelD directories that contain a bunch of files. One of these object models is full of information that describes how to connect to a particular data source, how to retrieve values from certain tables in that data source, what kind of objects to make, what kind of relationships to have between them. And EOModeler is really a graphical editor that lets you set all this stuff up.
So this is one that's kind of finished for a CARS database that you might have. And hidden inside this EOModel is a lot of useful information that you've set up. There's database connection information that tells you the particular database that you want to talk to. In this case, we're talking to, you know, that's not even right.
That's the way to get to the real one. I made that last night. I looked at my slide and I thought, oh, geez, my old one was wrong, and this one is not really any better. But you'll see that in a moment, because we're going to make an EOModel. And you'll see what it actually looks like. There's also information about entities and tables built in here. An entity is a kind of a thing, a general class of things that come out of an EOModel. The table is the particular database table they come from.
We can see in here that the MDL table in, let's say, our Oracle database that this thing is connecting to, every row in that is going to correspond to a vehicle object. I'm not stuck with ugly schemas with incorrectly spelled table names in the data. Not that that ever happens. But in the database, I can put a nice, meaningful view on it.
I want vehicle objects to come out of the MDL table in Oracle. There's also detailed information about each of these entities. The vehicle object, you can see it's got a bunch of properties. It has a base price and a loaded price and some image JPEG data. And those things all correspond to certain columns, certain columns in the Oracle table that we're getting this stuff from.
For instance, the base price of the vehicle corresponds to the PRMin column in Oracle. So once the Enterprise Objects Framework has manufactured one of these vehicle objects for you, you can send it the message base price, and it's going to go, oh, okay, here you go, returning the data from that column of the Oracle table. There's also relationship information down here at the bottom. Vehicles have a related maker object.
The Corvette object is related to the Chevrolet. Some of the relationship information in the bottom half, we can see that there's maker objects corresponding to a different table, and EOModeler maintains these relationships, sometimes one-to-one. A car has one maker. Sometimes they're one-to-many. Chevrolet makes a whole bunch of cars. And all that information about how to actually do those SQL joins is hidden in this model and is something you can exploit very easily later with WebObjects Builder.
EOModeler can manage some fairly complex relationships here. You get a diagram view that you saw in the previous presentation that lets you see what relationships actually exist. You can even draw new ones that might not be actually defined by the database. And my favorite part of all this is what we call key value coding. It's this idea that you can make up these little expressions. Vehicle.maker.name. Ask the vehicle object for its maker. Ask that object for its name. You get a string like Chrysler.
Vehicle.packages. Give me the list of all the packages that go with this particular car. You send these simple string messages with these dots in them. You send even fancier ones with this at sign notation. They can do averages and sums and maximums and minimums. And that's that patented key value.
Is it patented? It's patented, isn't it? Software patents are evil. But this is a good one. This is a good one. This is a good one. Sorry. Sorry. I forgot where I was. But not this one. This is a great software patent. And because it expresses this string. It's a simple concept that no one's thought to do before.
A.B.C.D. as a stream of messages in a, I was going to say language independent way, but that only mattered last year when we were doing Objective-C and Java. But in a nice neutral way that lets you specify how to traverse this graph of objects and how to get results out of it. You'll see this exploited in WebObjectsBuilder when I get to that in a moment. I tend to go nuts with these things. I made up one when I was working on my demo.
I made up an expression like that that had seven dots in it and two at signs. Which was a personal best for me. I don't think I've ever come up with a reason to have two of these at signs in a key value coding expression. Has anyone ever had two at signs in key value coding before? Am I the first? Oh, geez.
But thank you, there you're not. But it was so complicated I looked at it, I couldn't even understand it after I'd done it, and I thought, well, maybe we better not do that in today's demo, so we'll try to keep that part simple. Let's do a really brief EO Modeler demo.
If I could have demo screen three here, you can see that I'm working on a machine that's protected by this secret shroud here. I think this is our new 18 and three quarter inch monitor that hasn't been released yet, so you can't actually look at it. But I'm looking at a great picture here. So I want to build a new model using EOModeler here.
[Transcript missing]
I don't know. Something about electrical votes. I don't really know what those are. But it seems like a great database to kind of work. Maybe we can write a business rule that decides who the winner is and kind of speed up this process a bit here. I'll tell you one of the great things about WebObjects 5, we have simplified your choice of database adapter. JDBC or none.
I love the Nunn adapter, but I think today we use the JDBC adapter. So, one adapter that lets you connect to a variety of data sources in a nice cross-platform, database-independent kind of way. You need to have what they call a Type 4 JDBC driver for your particular database installed in a certain spot on the system. But since those are pure Java classes, you can do that on any machine here. The fun part is in remembering the clever syntax for this URL that connects you to that particular database.
This is my least favorite part here. JDBC colon, oh God, what am I doing? Openbase colon slash slash localhost slash US elections. That's a URL that describes how to use JDBC to load a certain kind of driver, get to Openbase in this case, and fetch information from the US elections database running on this machine.
These plugins are little helpers because I gather JDBC isn't just quite rich enough to find all the information that we need from a remote data source. So we have little additional classes that help out here. And now you're prompted for what kind of information from that database do you want to actually incorporate in your model? I don't have any stored procedures to worry about. I'm going to do custom enterprise objects later, but we'll deselect those and look at the rest of these.
Of all the tables in your database, which ones do you want to use? Well, I've got a table for candidates, and I've got one for elections, and one for votes, and well, let's use all of them. What the heck? Now, EOModeler wants to be a nice citizen and work with the referential integrity rules that you've specified for the database. You know, I always hit next here because I don't know what this is all about.
I should look that up, you know. There's a reason I'm in sales and I'm not actually delivering the consulting services. It's probably safer for everyone that way. But here is our EO model that's just been created. And this is a view like we kind of saw a few dozen PowerPoint slides ago.
It says that we've got campaign objects coming from the campaign table and party objects coming from the party table. And you can actually look at these in here if you want. There's a little data browser where you can say, fetch me all the party objects that you've got in the database. A whole bunch of them. The America First Party and the Farmer Labor Party and the... Oh, you have a Liberal Party down here. Oh, isn't that interesting? I thought that was a bad word.
There's also, for instance, there's a candidate object, and you can see that the candidate object has a first name and a last name and a home state, and a couple of relationships. A candidate is related to a party. So-and-so ran for the Republican Party. A candidate has a one-to-many, indicated by the two arrows, a one-to-many relationship, or a list of campaigns that this candidate has been in.
Steve Hayman And there's other useful tables in here. There's an image table of photos of certain people, but I might like to add a relationship that's actually missing here. I'd like to be able to get from the candidate object to the picture of the candidate object. So I'll add a new relationship, not currently defined in the database, to this particular model.
And in the inspector, you can give it a little more detail about this. I want to go over to the, from the candidate table to the image table, and it's a one-to-one thing. We're going to join the image ID here and the image ID there, connect. And now that I've done that, every candidate object I get, I can now send it this message image, and it will automatically fetch the picture of that guy for me.
and it actually does it in a delayed way. We have this incredible deferred faulting. You should really go to some of the advanced EOF things and learn about this. It's hilarious. But the way we can keep stuff from being fetched until it's actually needed. These engineering guys, they've done a lot of work to minimize the hits to your database. So this is, I'm editing a document here and I wanna save this. Let's call this, put it on ye old desktop here. This is my elections.
[Transcript missing]
Kind of like the ice capades with all this stuff sliding in and out. It's actually much more powerful and extensible than the old Project Builder. I admit it takes a little getting used to, but I found that actually after I read some of the documentation about Project Builder, I liked it quite a bit more than I did before I read the documentation. This is essentially your development environment.
You compile things in here, you add resources, you check them into and out of CVS if you want. You can hear all about that in other sessions. I'm going to use it minimally later. Oh, now we're going to have another demo. That's great. Great. We had one slide in between those two demos. I thought I could cool down a little bit more first.
Can I have this thing back, please? Let's build a project. I want to make a new project. We have all these wizards that certain people feel they need to use, but we're going to actually choose a plain, unassisted WebObjects application here. What do we call this? Woe is me. How about that? I want to make a simple application that lets us browse for presidential candidates.
The idea is going to be I type part of the name Hayman, and I can see if anyone named Hayman has ever run for president, which I'll tell you in advance none of them have. But we can try other things as well. So, Project Builder coordinates web components in your application. Here's a main.wo that we were talking about before. It's a plain, empty little one that doesn't do very much. It coordinates classes. We've got an application object here. Oh, big font.
Here we go. An application object that doesn't really do anything other than to say, hi, welcome to Woe Is Me, and a session object that will be shared by all users. This is really all the code there is in this application. There's a few lines of these trivial classes here ready for you to extend as needed. But I want to start by working on this main WebObjects interface file here.
So this is that editor we were talking about before. If you like, you can think of this as just a simple HTML editor, Explore, Exploder? Okay, Exploder, why not? You can fool with the fonts and you can make things bigger and you can bring up a color panel and be sure to go to the session 957 on using the color panel.
: There isn't a session. I like that because this takes me back to the old Next Color panel. It's so fun to see these things still here. And if you want, this is just editing HTML. I haven't really put anything very interesting in it. And if you wanted to, you could pop over and just look at the raw HTML and fool with it in here if you wanted. Nothing to this one yet.
But it gets more interesting when I want to put dynamic objects, which are what a lot of these little buttons are up here, into my application. What we really want to do here is have a form. That's a form, going to be rendered as a form on the user's web browser.
We'll put in someone's last name. We'll type part of a last name in the text field and a submit button. I want to do a legitimate survey here. Has anybody in the history of the web ever felt the need to actually click on the reset button?
[Transcript missing]
Now, let's actually arrange to fetch some of these candidate objects. Now, these tools talk very nicely. You'll recall that we had our modeler define a candidate object with a first name and a last name and a relationship to a party. And if I drag this little object out here and into this view, it's going to add my object model to the big woes me application. And it's going to add what we call a display group to this particular component. And a display group is this total Swiss Army knife object that knows how to fetch a certain kind of object. In this case, candidates.
It knows how to collect the criteria of what candidate you want to fetch. Last name is like this. It knows how to send them back to you in batches. Here's the first 10. Here's the next 10. Here's the next 10. So all you need to do is draw some of those lines to tell the objects in the UI, in the top half, what messages should be sent to the objects back on the server to coordinate all this fetching.
So one might start with, let's have that submit button send the message, "Qualify data source." Draw a line like that. Now every time a user sees this submit button in their web browser, it's going to send the form back to my application and send the message, Qualify Data Source, to the display group.
And the display group is then going to collect some candidate objects defined according to my wishes. This display group also knows the various properties of the object it's fetching. So here's all the properties of candidates, and you can hook them up here. I want the candidate's last name as we're fetching it to be drawn from there. By the way, I want all the iServices guys up here, I want them all to cough if I miss anything obvious. Like if I forget to save something, could you all just cough a little bit and then I'll just remember to save it? Thank you.
Well, we could go with this. We could go with this application. We could save it and we could run it. And what would be one slight problem with this application?
[Transcript missing]
Let's put in a table. WebObjects has this little table thing with an idea of, if you want, a second row that repeats over and over again. So I want to have one row of this table for every candidate that comes back.
And I can ask this display group, give me all of the displayed objects. on that repetition. It's a common design pattern. You have a repetition associated with something that's going to be done over and over again. So we're going to get one row of this table for every candidate that was fetched.
It's also a common design pattern to use a special object to go through the table, kind of an iterator object. So I might want to come down here and say, I'd like to add a candidate object of type can. I don't even have to type the whole thing. It's type can. I want to create a candidate object that's private to this particular component.
Steve Hayman And that candidate, it's got a first name and a last name, but if I make an association like this, item, this object will be set once for everything that came back on the list. If I fetch 37 candidates, I'll have 37 rows in the table. I'll actually have 38 rows because this is a title row. Name, and I'll fill these in later. Well, if I click on this button here, these are WebObjects strings. These are the simplest possible objects in the entire WebObjects framework. They send a message, they get a result, they take the string, they put it into the HTML.
Well, I can have those send a message like first name to the current candidate object. Oh, there's too much junk up here. First name to the candidate object. You draw a line like that. Last name to this other string object. And this is probably worth actually trying this to see if it works. If it doesn't work, we'll just say goodnight, it'll be great.
But this is a good starting point here. This will actually display candidates. It will fetch a list of candidate objects, it will iterate through them one at a time, and send the first name and last name to each one. Get on with it, I can hear everyone saying. So we come back here to Project Builder, we compile, always a good opportunity to have a little drink of water.
compiling the various Java classes, it's making a big honkin' jar. What a WebObjects application actually is, it's kind of a complicated directory with like your .html files and your .wad files, and somewhere in there, a jar, a Java archive of all of your classes. Then there's all these other frameworks somewhere else in the computer that themselves contain jars and other resources.
And when you run a WebObjects application, you're actually launching this shell script that looks all around, that constructs this humongous class path to find all the objects in all the jars all over the place, and runs your main class to get the application going. And as a convenience, it also launches your web browser, see there's the class path by the way, you didn't believe me, but look at that, holy mackerel, I'm glad I don't have This is actually going to launch my web browser and have it hopefully display some of these candidates for me here.
Oh, there's my fantastic form. Let's compare that with what the original actually looked like. Everybody whose last name begins with H. There's a whole bunch of guys whose names began with H. How many people can identify Austin Holcomb?
[Transcript missing]
Well, let's find out. Given that we have a candidate object, it's fairly easy to add another string, one of these strings. Let's ask the candidate for its party and ask the party for its name.
I'm now working my way through that object graph. I've descended through a couple of levels down here. And what's actually going on as I'm doing this back in the WAD file is there's now a string called string3, and it's getting its value by sending the message party to the candidate and by sending the message name to that thing.
[Transcript missing]
But by walking through this graph of objects, you can put up some pretty interesting data pretty fast on the screen.
And I'd like to take advantage of another relationship that's defined in this database. You'll see that each candidate has a thing called campaigns. That's a list of all the campaigns that they were in. You ran in 2000 and '96 and '92 and '37 and 1776 and whenever else they had elections. I'd like to display all of those campaigns for each of these candidates. Because that gives me -- let's put a nice little table on here. We've got to be neat.
Elections. Which elections was this guy actually in? Well, let's put in a handy repetition object. See that little loopy thing there? That says, let's just go over some list, just like we did with the table, and do something over and over again. Let's loop over the candidate's election objects, like that. Let me create another little object here called an election. This will be a little private instance of the election class.
[Transcript missing]
Now at this point we have to actually pause and compile because in all that it added a whole line of code over here. It added this line that declared an object called election. So we'll just stop. We'll recompile. Have another drink of water. Close this browser. It'll open it again in a second here. Our lovely WoeIsMe application.
Look at that class. I just love that class path when it goes by because it reminds me how much work WebObjects is doing for me. Look at all that stuff it's picking up that I didn't have to describe. You have a certain amount of patter when you're doing this here. Hey, H.
Oh, look at all these guys that ran all these different elections. Somebody ran in 1892. My database only goes back to 1892. I'm sorry. I could not get the complete database done in time. Maybe next year we'll go back to the Magna Carta and have every election since then.
For now, we can see, oh, I recognize a couple of these guys. John Hagelin of the National Law Party and Warren Harding. He was somebody, wasn't he? And Benjamin Harrison. Didn't he win? I don't know. We'll get to that later. But it might be interesting to click on some of these elections and find out a little more information about it. I gather that 2000 election was kind of interesting. A little news about that filtered over the border.
So it might be useful to have a page where we can display some details about a particular election. This gives me an excuse to introduce the idea of a component that does one thing and that does one thing well. I want to make a little component in WebObjects Builder. I'll make a new one.
And actually, you know what? I got two ways to do it. And the other way is better for reasons that are not worth explaining right at this point in time. I want to make a new WebObjects component inside Project Builder. For anyone who's wondering why I do it this way, take a look at Radar.
Election Details. And, you know, you should go to the Project Builder session to figure out what the heck is going on with all these target things. I think that's the one I want. I don't know. Is there coughing going on over there? No coughing. Good. I'm all right. I've created another component and I've added it. - To my application. And the idea of this one is gonna be, it's gonna have its own private election object. Let's create another one. And let's remember to set it, 'cause we wanna set it from the first page.
The fabulous election of some year. And we're going to display everybody who ran in this particular election. Another table. You don't have to talk, you can really do this pretty fast. Each election we want to go through all the campaigns associated with that election. We want to have a campaign object on this page as well, because these are separate pages, separate objects.
And for each campaign, that's going to be my list. I want to display the first name and the last name, just like we did before, of the candidate relationship. I've got a lot of relationships in this database. First name and last name. Let's display the party because it's so easy.
It is. Stop laughing. It is easy. You'll love this. Party, the party's name. And let's put titles on it because my mother might be watching the DVD and she'll wonder why I didn't put titles on here. Candidate. By the way, I'd like to say hello to everyone that's watching the DVD in the future. Hello, people in the future with the flying cars.
How are you? How is WebObjects version 14? Are you looking back at this and going, that was so primitive, I can't believe it. How did my children turn out? Did they go to college? I hope so. Can I expense their tuition now? Can I expense their tuition with that because I mentioned them? No, I don't think so. Pari, party.
Thank you. I spelled party wrong. And let's get fancy here. Let's display, whoop, no, not up there. Let's display how many votes each person got, because this really gets into borderline abuse of this whole key value coding business here. But if you dig deeply into this kind of stuff, you can say for each, where are we here? For each campaign, I'm gonna add up, take all the votes objects and display them there. But I don't really wanna list all the votes objects. What I wanna do is, is throwing this little token that says, "Sum." Don't list the things on the right hand side, add them up. That's going to add up how many votes each guy got.
All that is a nice object that can display everything about one election, provided we tell it which election we want. One could do that on the first page. Remember the main page? Remember how we had a hyperlink or a piece of text displaying the election year? I can make that into a hyperlink by clicking on that little button which wraps this thing inside a WO hyperlink object.
And hyperlinks actually send an action message back to the application when they're clicked on, just like my submit button did. But I want this one to send an application of my choosing. Show me all about this here election. How long can an identifier be in Java? I don't know. It's at least that long. And I'll tell it to go, oh, I just typed E and it knew I had a page called election details in there already.
and we'll arrange for that hyperlink. "Show me all about this here election" to be called for every one. These are going to be hyperlinks. Even though there's 30 election years on the page, they're all sending the same message back to WebObjects. WebObjects knew how it made this page, so it can easily just figure out which of all those 35 election objects is the one that sent me this message. This is really a powerful concept. You're not encoding junk into the URLs yourself as you generate these pages. You're letting WebObjects do all the heavy lifting of sorting out these collections of objects and indicating to you which one was actually selected.
Save that, save that, come back to project-- oh, no, wait, what are you doing? Sorry, wrong application. Save that. Okay, here we go. Steve's going to try to type a line of Java code without making a mistake. Here's my main application. Here is my nice show-me-all-about-this-here election method that I just asked WebObjects Builder to create for me.
You can see what it's doing here. It's looking up the page called Election Details, and it's returning that page. That page will be blank if I don't dive in here and rescue the situation. Well, I'm going to tell the next page.
[Transcript missing]
Oh, is there any hope that I've done all that without making a mistake? Didn't hear any coughing over here.
Oh, not the sneeze! Oh no, not the sneeze! That was a secret signal for something that I've forgotten. Okay. Let's try running this again here. How come no one's asked why I'm running the classic Internet Explorer yet and not the Carbon one? will become clear in a moment.
It's part of my fascination with XML and my shock and horror at how some things aren't implemented as widely as you hope when you start designing your WWDC demo. Thank you. That will become clear in a second here. Here's a bunch of guys. They ran in all these elections. Tell me about the 2000 election.
All these guys ran in the year 2000, and I've totaled up their votes. Well, that table, that's not the most attractive table I could possibly recommend. You know, you don't believe me, this is a real database. Tell me about 1952. Who here voted in the 1952 election? Bob, did you? No? Okay.
Well, the 2000, that's one that I remember, the 2000 election. And now that I've got this page going here, we'll look at the details page. And the first thing I might do is to take that string that's representing the number, and in the inspector, one can say, don't just pump out the number, pump it out with commas, because that just looks so nice. Makes a change like that. It's coming out with commas.
Steve Hayman Whoo, yeah. You can take a, you see this little path down here? This is how things are nested. I've got a string inside a table data, inside a table row, inside a WL repetition. I could take that table data and inspect it and say, you should horizontally align everything to the right, because that would probably look better. That does look better.
You can even come in here and say, let's add in this first cell an image object. Remember I added that image relationship about 23 minutes and 11 seconds ago in the demo? That was not for no reason. Try translating that sentence. Remember, my candidate object has a relationship to an image object. Images have some data, and they have a MIME type that just says whether they're GIF or JPEG. I happen to have a database table full of images here.
Conveniently. Oh, that's better. How do you like that? Would you vote for this guy? Well, a lot of people voted for some of these guys. And to my naive view, I might think that since this number is greater than this number, but what do I know? I don't know.
I don't know anything. I have a Canadian math degree. We do it a different way up there. So you know what, I'm kind of a visual guy. Not only am I a rugged outdoorsman, but I'm also kind of a visual guy. And I would like to leverage some work that's already been done in this area. How many of you have heard of SVG from Adobe? Scalable Vector Graphics. Looks a lot like PostScript in many ways, only it's XML. It's a way of describing an image and sending it to a browser, and then the browser is going to draw it for you.
I want to draw those little maps like they have on election night with all the states colored in. Wouldn't that be cool? I've already got in my database information about, you didn't see the electoral, there's an electoral votes table in there as well, but how many electoral votes each guy got. Wouldn't it be cool if I could hook up the list of who won electoral votes where to something that knew how to draw a list of states? Wouldn't that be cool? No? Oh, come on, please. Thank you. Okay, thank you.
Well, too bad that part's not working. No, no. Actually, no, it is working. It's not going to work yet because I have to add a couple of frameworks to my project. Frameworks are collections of objects that already exist. We give you some. I wrote some in my spare time, and I entered that on the timesheet appropriately.
And if I add them over here to—I happen to have—I got this FireWire disk. I love them FireWire disks. Boy, oh boy, because I've got conveniently over here some frameworks that have just been hanging around waiting for the right time to be used in a situation just like this. Let me add three of my favorite frameworks of objects I've personally written in the past to this application. Actually, you know what? Let me quit that.
Okay, now I'm going to do this. We'll discuss that later. I want to add them, and once again I look at all these little targets and I go, oh man, the application server? I think so. The project builder can build different targets. It can build a collection of things that go for the web server, like static GIF images and stuff that belong on the web server. But in this case, I'm adding frameworks to the actual binary. And because I've done that, I can take my little election details component, go back into WebObjects builder here.
And take advantage of some palettes. Remember I talked about -- oops, pardon me. That's one app on the screen at the time. How's that? Remember I talked about palettes? These little handy collections of pre-written objects that other people have written. You get a bunch of these with WebObjects. None of them draw maps, but they do a number of useful things.
This one does -- you know, one of the great things about WebObjects is that this product is so sophisticated that here's a whole palette full of objects. I have no idea what any of them do. But it comes with WebObjects. It's great. It's Smil. This is -- whoa, Smil. What is that? Synchronize multi -- is there a session on that one? Let's hope so, because this isn't it.
But let me -- In addition, I've got some palettes of my own. I'm a bit of a palette junkie, and I've got a few of these guys. There's one, and we'll open him, and we'll open this guy, and these are sort of related to those frameworks. These palettes are objects that I've collected over the years that do various useful, interesting things. I've got some little JavaScript doodads, and I've got a thing that makes words plural that was the big hit of WWDC 2000. Thank you very much.
Steve Hayman But, oh, wait until you see this. These draw maps. These take SVG files back on the server, which you can create with Adobe Illustrator or a bunch of other applications. They're just text files that describe polygons. Line, line, line, line, line, line, line, line, line, and then you give it a label. Montana. Line, line, line, line, line, line, line, line, line, line, line, line, line, line, Indiana. This line and this other line, Michigan. And if you make one of these things up... Two polygons.
If you have one of these things in SVG, I wanted to find an excuse to use this Xerxes parser that we've put into WebObjects 5. This is an XML parser from the Apache project. And so I wrote a little thing that would parse one of these SVG maps using this parser, which is so easy, it's unbelievable. And every time it saw a polygon, it would look at the name of the state, Montana.
And it would consult another list. Is Montana on my list? Okay, I will fill it in. If it's not on my list, I'll leave it outlined. And I put a bunch of these things together on a palette like this. I've got one of Canada, one of the US, one of Europe. I've got one of North America, which I might as well use that one since I am thinking about my comrades back home on holiday today at the beach.
[Transcript missing]
Wee! Let me draw the... Oops. Wee! There we go. That's an object that will draw maps of Canada and or the United States, provided you tell it, you bind it in WebObjects Builder to something else that knows about a list of regions. This is why I love key value coding.
We're going to go in here, we're going to take the current campaign object, take all of its electoral votes objects, ask each of them for their state, ask each of those states for its state name, and bind that to our selections list. Can it be that easy? People come up to me and they say, Steve, can it, what? What? Thank you, Steve.
Oh, we, well, all right. Oh, I bounded the wrong thing. Pardon me. Thank you for coughing. Selections. What's wrong with that? There we go. I put two of them in. Oh, my mistake. I got-- yeah. This time? There's this little validation window in WoBuilder that will tell you when you design a component, you can say, this is a required binding.
This one's optional. And this thing will check when you save them. And here I was panicking, and it was right. I did have one in there that was unbound. Thank you for the coffee. Did I save this? I saved this. Project builder will build this again. I added the framework, so they're going to find the code to load this SVG parsing thing.
This is why I'm using classic Internet Explorer. SVG plugins are only available for certain browsers, not including the new carbonized Internet Explorer. That's why I'm using this classic thing here. We'll start this. This is all going to be very anticlimactic if this doesn't work, which is a strong possibility at this point. launched the application. Its class path is even more complicated now because it includes three of my frameworks and all them little doodads. And I'm going to open this up here. That looks good.
Tell me about all the guys named, I don't know, Bush. Oh, there's two of them. Okay. Tell me about this one. Tell me about the big election of 2000. Oh, this is getting complicated now. It's loading up all these SVG things, it's loading the Adobe SVG plugin, and for each guy that actually has electoral votes, it's filling in that thing with the necessary states.
But you're saying, Steve, they're all the same color. What can we do? Well, remember part--did you happen to notice in my EO model that parties had a color? You can ask the current--where are we here in my object graph? Campaign, ask the current candidate for his party, ask the party for its color, tell the map to use that color. Oh, wait, wrong one. Here we go, quick.
I still can't really tell from looking at who the winner is. It looks to me like there's more red pixels on the screen. Is that how it works? Is it like by square miles? How do they do this? But I might want to, this might be a good opportunity to write a little object that can solve this problem for us once and for all. So let's return to this EO model. And, uh, just a moment, I must have closed it. Let me reopen this EO model here. And we talked about the idea of business logic in these objects.
And so far, all the objects that I've got defined here are what we call generic records. They're just simple containers. They store some data, you can send them a message, they respond with the data. But they don't make any decisions. They don't implement any logic. But I might like to take a couple of these and make Java classes for them to be added to my project.
And we'll come back here and actually add those files to the project itself. It's now created campaign.java and election.java. And I want to make them part of my project. I'm going to look at this panel again and go, uh, yeah, OK, that one, all right. And if we look at the election object,
[Transcript missing]
I want to write one method that sorts everybody according to electoral votes, because I understand that is sort of how this works, right? And I want to write a second one that takes the sorted list and returns the guy at the top of the list. And you all thought I was kidding about using stickies for development.
There's a method that returns the winner. It asks for all the sorted campaigns. Here's a method that sorts the campaigns by this key, sum up the electoral votes for each guy. Save those. Let's build that. Steve Hayman What have I done? I've just added two additional methods to the election object. If you look back in WebObjects Builder over here, you'll see that we're going through elections, and the election now suddenly has this winner property. These tools are talking back and forth.
WebObjects Builder has discovered that there's an additional method available to election objects. You can send the message winner, and it returns a campaign. You can send the message candidate to the winning campaign and figure out who that was. You can put something up here that says your winner. Last name.
First name, last name. I think I, did I compile that while that was happening? I don't remember. I think I did. Never hurts to compile it again. I want it really compiled, you know? I want the bits to stick to the disk. Cosmic rays could be entering the auditorium here and messing this up.
is going to launch again here. Lots of chatty error messages here. If you'd like, you can turn on a variable that has all the SQL that's being sent to the database spit out here. That's fun to read. Actually very useful for debugging. Sometimes you just can't figure out why is this so slow, and it's because you were fetching the same object too many times, or you weren't batching things in an effective, efficient way that EOF lets you do. It's all those H guys again.
John Hagelin, he ran in 2000. Who's, uh oh, wait, wait, oh, he's close, don't look at that, wait, hang on. Alright, I'm gonna tell you something. I've got this other monitor here. I've got a sticky on here to remind me what to do, and right there in bold it says, "Save the EO Model." And I forgot.
[Transcript missing]
Hopefully this is worth it. Did we know who the winner is? This isn't news to anybody, is it? I mean, did you read the papers? I hope so. Is Gore still in it? Is there still a chance? How long does this go on? I'm not sure. Four years. Four years, yeah.
Here, 2000 election. It's fetching a whole bunch of things. Your winner, George W. Bush. It evaluated that custom business rule to add up electoral votes and decide who had the most. And in fact, so long as it's done that, remember I added a method called sorted campaigns. We could take that table there, instead of going through all the unsorted campaigns, we could ask the election for the sorted campaigns, and that, what am I doing here? That repetition would look that much better.
[Transcript missing]
So I think I've shown some relatively interesting concepts here. The idea that you can have business objects, and that was a pretty trivial rule. I was just sorting something and taking the first one. But you can implement much more complicated business rules, and you frequently do with WebObjects in your own application.
Students, are they eligible to graduate? Well, we check, have they paid their parking fines, and have they returned all their library books? Did they pass all the tests? Does the supervisor still say they're okay? You can implement that kind of logic when it's appropriate in these middle-tier business objects. All this stuff is being done in a database-independent way.
None of these objects are even aware which database they were coming from, which means you can do one last moderately cool thing here. Remember I made this EO model here that said let's talk to the US elections database and let's fetch candidate objects in elections and so on? Let me take that out of my model. And we got my FireWire disk here. I'm bringing a different EO model.
I'm going to bring in another EO model and put it back in the same place. And we'll start this application again here. Oops, we'll compile it and start it again here. Maybe I had to do that. So I've dropped a totally different EO model in here, totally different, fetching from an entirely probably different database.
It could be an entirely different database than the one that we're using here, it could be. But we don't know because we just put an object model in there, and the object model has all the information about how to actually fetch things. So once this thing gets going again here, let's... This time fetch all the candidates.
Oh, wait a minute. Who are these guys? Stockwell Day Reform Party. What is this? Different database. Oh my god. Tell me about that election. Wait, wait, wait, wait. Hold your applause. Here it comes. Your winner is Jean Chrétien. Oh, he won all those seats. And Day, he won all those ones out west. And the Black Quebecois, very popular out there. And NDP seemed to have some large chunk of northern Manitoba.
So this application is completely ignorant of what data source it's actually using. It all revolves around that EO model. I told it to use a different database. It could have been a different schema. And I could tell you it was a different schema, and I wouldn't have to show you, and you'd have to believe me, but it was the same. But it made the same kind of objects with the same relationships.
And the complete separation of back end and front end of interface, these SVG map drawn objects at the front end, these data bearing objects that are coming out of OpenBase or FrontBase or Oracle or how many people added the IBM number and the Informix number together on that graph? It could be any one of those databases. And you see the separation of the back end and the front end enables you to do some pretty interesting things here.
How many people are wondering what the heck happened to Nunavut on this map? Canadians are going, "There's no Nunavut on the map." The Americans are going, "What? Who?" Had a little problem with one polygon. Can I go back to my slides, please? I want to finish up with a few more concepts here.
Oh, thank you. Nobody said you had to use HTML. I was using SVG here, which is a form of XML that's sent to the client. We have some pretty cool technologies that let you build pure Java applications, including Java Client. I would certainly urge you to go and see the Direct-to-Java Client. I believe there's two Direct-to-Java Client sessions. And the Direct-to-Web -- pardon me -- go and check out the report mill and see how they're delivering PDF in sort of a similar way here. Talk to guys like me about how we did this XML thing.
And take a look at some of our assistants. We have Direct-to-Web, which takes an EO model like I just made and makes you a full-featured application that's pretty much done that you can tweak through this very interesting rules engine, which you can learn about at the Direct-to-Web session.
Direct-to-Java Client, the same sort of thing with a Java Client interface. And for deployment, we've got a good session on deployment that tells you what the heck is going on here. How do I keep all these arrows going? What is the role of the WebObjects task demon that runs on each of these machines to keep an eye on everything? How does it communicate with the WebObjects task demon? And then we have the WebObjects adapter through the firewall.
What are these messages that are going back and forth? Well, we have a whole architecture and a tool called Monitor that lets you describe how many applications you're running and where. And it sort of lays everything out for you. It starts them up. It gives you a UI like this where it will start three copies on that machine and two on this machine and inform the adapter on the web server about what's going on. And generally, it works pretty well.
All right, it always works pretty well. I'm sorry. This stuff works great. Engineering has done a heroic job in migrating this stuff to Java. The fact that it works at all, considering where they came from this Objective-C code base to where it is now, it's nothing short of miraculous. We have a number of, how many people here are going to all the WebObjects sessions? The people here from the whole track, well, that's great. You're going to love all of these. These are all great. These are all great.
And what is the deal with WebObjects 4.5.1? Well, Mac OS X Objective-C only. You don't want this unless you already have a WebObjects project that you want to bring to a Mac OS X machine. If you're starting something new, you want, you definitely want WebObjects 5. You do want WebObjects 4.5.1 if you're going to bring a product to, if you're already using 4.5 on one of the other platforms as well. You can move that along. The only thing that's really missing is support for Java on Mac OS X.
Steve Hayman With this product. We still support Java and Objective-C both on Windows NT and Windows 2000 and Solaris and HP UX, just like before. But this is it. We swear this is the last time we're doing an Objective-C release with WebObjects. We're no more fooling around here. We're not going to.
So if you're starting something new, I really urge you to look at WebObjects 5 because 4.5.1 is for people migrating existing projects along. Moving from 4.5 to 5, pretty easy if you've got a project. We've got a whole session on that. The APIs are pretty close. Learn more. A couple of WebObjects training classes that you can use.
A week-long class on development, another week-long class on more development, and another three-day class on deployment. Excellent, excellent classes taught by our iServices technical training guys. Feel free to come and see us in the lab in room K in the other building, which is on the ground floor. Play with all this stuff.
I'm going to try to have my demo running on the machine. I'll try to have that set up if anyone wants to see what the deal with that SVG mapping thing was and why none of it was missing. Maybe you can help me put it back in there. And there's lots more sessions. They asked us to put up the most relevant sessions on these slides.
I couldn't really think what they were because they're all good. From this point on, I have the advantage in doing the technical overview that all this great stuff is following behind me, and I can refer you to virtually any session that's coming up on WebObjects. Who to contact? Tony, Bob, iServices guys, a whole bunch of URLs.