WebObjects • 57:05
This session covers improvements and new features in the WebObjects 5 Frameworks, as well as issues with migration from WebObjects 4.5. This general session will be helpful to all developers interested in getting a head-start with WebObjects 5. It requires some knowledge of WebObjects.
Speakers: Melissa Turner, Francois Jouaux, RD Willhoite
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Hi, thank you for joining us. I'm glad to see a good number of you found your way back over to the conference center to catch up with the rest of our sessions. Our next session is going to be moving to WebObjects 5, so I'd like to introduce Melissa Turner from the engineering team to come up and start the procession off.
As Tony told you, my name's Melissa. I'm one of the WebObjects deployment engineers, and I'm going to be your presenter for the next hour or so. First, we might as well get it out of the way. Yes, I'm an engineer. Yes, I'm female. Sometimes it happens. Thank you.
This is the session 6.05, Moving to WebObjects, and... I hit the wrong direction. This session assumes that you have some knowledge of WebObjects. We're primarily going to concentrate on some of the conversion issues for those of you who have a WebObjects 4.5 or WebObjects 4.5.1 application that you want to move to WebObjects 5.
We're going to cover some of the benefits of moving to WebObjects 5. We're going to cover how you would go about migrating an application to WebObjects 5. And we're going to talk about some of the new improvements and some of the features in the WebObjects 5 Frameworks. I am not going to cover anything in-depth. I'm not going to cover EOF or Java Client. We have entire sessions devoted to those. Some of them, I believe there's one following this. I recommend it highly. But remember, anything that I don't cover is going to be covered elsewhere.
What is WebObjects 5? This is a question we've gotten from several people. WebObjects 5 is essentially WebObjects 4.5.1 ported to Java. It has the same feature set. It's got essentially the same APIs as WebObjects 4.5. There's a few exceptions that we'll talk about later. On Windows, it uses the 4.5 developer tools that you're all familiar with.
We have a new project builder, as you all know, on 10, and we have integrated with that. EOModeler, WoBuilder, and the rule editor have been aquified, but other than that, they're pretty much the same. For those of you who want to do split deployments, the WebObjects 5 monitoring tools are capable of dealing with and managing WebObjects 4.5.1 applications, and we have some new features.
What are some of the benefits of moving to WebObjects 5? Well, there's a number of them. The big one for a lot of you, and I know this has been a concern, is that WebObjects 4.5 used an older version of the JDK. That's over. WebObjects 5 uses the JDK 1.3.1, actually, I believe. For those of you who are on Windows, you'll notice that we do still install a 1.1.8 JRE. This is purely for the use of our tools. You should not use it. You should just pretend it isn't there.
The big thing about moving to the JDK 1.3 is that it allows you to integrate with a lot of the new and third-party tools that are out there. Development environments, debuggers, optimizers, a lot of tools that you didn't have access to when you were writing in the bridge Java environment. And it makes it a lot easier for you to integrate with third-party products, because as we all know, there's a lot of mindshare in the Java world. There's a lot of people producing packages to do everything from control robots to do reporting.
You now have access to all of those packages. And because we've moved to JDBC, you'll also have extended database connectivity. This means that you no longer have to wait for a database company to come out with a set of native client libraries on whichever platform it is you'd like to deploy on. Most database companies ship Type 4 JDBC drivers, which plug into our JDBC adapter, and things should work much more easily.
You can do development on Mac OS X or on Windows as you could in 4.5.1, and we also support deployment on those platforms plus Solaris. One of the other big features of WebObjects 5 is that it's much easier to develop on one platform and then move your application to another platform. There's no issues with remembering your LD library path, there's no dynamic shared libraries issues, things go much more smoothly. And we've had some performance improvements. Ernie talked a little bit about this a couple of days ago.
We did some benchmarking comparing WebObjects 4.5.1 with WebObjects 5 on Windows, Mac OS X, and Solaris. And lo and behold, we discovered that we did a good job of converting to pure Java. We're faster on all platforms. On Mac OS X, we're about 22% faster than a comparable app written in pure Objective-C. This is not comparing against Bridge Java.
This is pure Objective-C. We're about 22% faster on Mac OS X. We're even better on Windows. We're about 51% faster. And on Solaris, a platform that I know a lot of you deploy on, we're over 180% faster. So, we're very happy with that, and we think you will be, too.
So now that we told you that, yes, there are some serious benefits to moving to WebObjects 5, a lot of you are going to have the question, should I convert or not? And people who should convert are people who have Objective-C or WebScript apps that are very early in their development phase, or people who have existing bridge Java projects that they may be in deployment or they may be in development. It's very easy to port bridge Java to pure Java. And anyone who requires access to more Java standards or to third-party products should also consider moving to WebObjects 5.
People who should not consider, or at least should be seriously contemplative about moving to WebObjects 5 are people who have Objective-C projects that use a lot of low-level Objective-C. If you're using categories, if you're using posers, if you have Object-C message send anywhere in your code, you may want to think twice about migrating because it means you're doing things with the Objective-C dynamic runtime that cannot be done easily in Java.
If you've got a lot of basic C code, if you're using lots of third-party C libraries, you're doing a lot of nasty pointer manipulation, you may also want to think twice about it because that's a more complicated conversion. And if you've got an app that's already in production and it's not being updated, there is an old engineering rule of thumb that I learned when I first started programming. It's, if it ain't broke, don't fix it. If you're happy with your application, it's making you money, you don't need to change it, by all means, don't.
Next question, once you've decided to convert, is how do you go about converting? We provide a tool called Java Converter that basically allows you to... Simply and programmatically convert your WebObjects application from 4.5 to a pure Java environment. On Windows, this is located at nextroot/library/webobjects/java/applic ations/javaconverter.woa. On Mac OS X, this is at system/library/webobjects/java/applic ations/javaconverter.woa. It claims to be a .woa, but it really isn't. We're just leveraging the packaging.
You run it from a shell inside the .woa directory, and it's a fairly simple thing to do. You enter your command script plus the full path of the project directory or files that you want to convert, and you hit return, and we take over from there. If you want to migrate using the Java converter, there's a few ways you can do it.
If you want to convert on a file-by-file basis, you can take an individual C, Objective-C, or WebScript file and convert that to pure Java. Or you can convert an entire project directory at once. Or if you're feeling a little bit more constrained, you have code that's possibly in the nastier areas, you may want to consider doing a hybrid project and migrating first to bridge Java on a file-by-file basis, and then once you have all of those done, moving them to pure Java.
Or you may want to move your entire project first to bridge Java, and then to pure Java. This could give those of you who have lots of categories and posers and that kind of thing a little bit more time to do your conversion without having to disrupt your application.
Some of the advantages of using Java Converter that we don't touch your original source code, we lay down a parallel set of files as the ones we converted. If there's a conversion problem in the converter, we clearly describe the error in your code, in the new code, as a JC error, a JC warning, or JC info. We also print the transcript, a little warning that something happened, so you can just go off and search and find out what the problem was.
We've tested the Java Converter against most of the Objective-C frameworks we've got. We've tested it against WAF, we tested it against EOF, EO Control, EO Access. We converted many of our examples using it. We've done a bunch of internal code that you will never see. It's extensible with customized top scripts if there's something that you need it to do that it doesn't already do, and it's a lot faster than manual conversion.
What I can say is that when we did, before we had the Java converter, we were converting by hand, and we were managing to do about 300, 350 lines a day. Once we got the Java converter in play, that jumped up to 3,000 to 4,000 lines of code a day. You can spend an awful lot of time moving brackets around.
Some of the limitations, though, are that we cannot convert your EO model file. You're going to have to go in and manually change the adapter and possibly add or remove a little bit of data. We don't change any of the APIs that you've put in your WAD files or in any of your other archive files. And if you have Objective-C code that relies on posers, categories, that kind of thing, we cannot fully convert it. We can create helper classes that will take the place of your category, but you're going to have to go through your code.
And in any place where you were calling a method that was in the category, you're going to have to redirect it to use the helper class. C code, as I've mentioned, we can change the C function invocation to a method call, but we can't translate whatever's on the other end of the method. And we can't determine which new API you should be hooking up to, so you're going to have to do that by yourselves. And the conversion process does take you about 80% of the way there, though.
And I'm sure a lot of you are going, yeah, right, it can't be that easy. So I'm going to call for help. I'm going to call Francois Jouel up, and he's going to convert one of the examples that we shipped with WebObjects 451 right here on stage in front of you.
Hello, welcome everybody. So, some people know me already. I already did last year's presentation on Java Converter and I will attempt the app. Impossible today. I will convert here with no net to protect me. An application we are shipping. Well, we used to ship in 4.5. So, do we have the window? Okay.
So, as Melissa said, Java Converter is a terminal-based tool. And I am going to go execute it. I have here a ThinkMovie application. I cannot open it because it's a 4.5 application. But trust me, it's here. I'm going to go in the project directory. Here is the ThinkMovie application.
Now, in my Java Applications folder, I have the Java Converter application. And inside the .joa, as Melissa said, there is... The Java Converter Tool So to use the Java Converter Tool, I just make it point to my Think Movies application. And I have my cofers. Cofers? Gofers. Gofers? Yeah.
Okay, it started. Now I can go have a coffee. I don't have to type anything. It will generate the classes, the Java classes. It will create a new project, copy everything in a new directory so that it doesn't stomp on existing files. And that's it. Well, I think that's it, but only 80% of the work is done. I'm going to do manually the last 20%. So here I have file merge. Do most of you know what FileMerge is? It's a very powerful UI-based GIF tool. And I'm going to compare what I had originally and the output of the Java converter.
Okay, I have both of them here. So you notice that it changed quite a bit of files. But if I look at these files, there is mainly one difference. And we'll look at the files where there are more differences, but for example, over the file with just one difference here. All the Java converter needed to do is to change import statements. No big deal. Let's look at a more complicated file. What does this one do? Just some package renaming here on the second change. And this one is even more complicated.
So here we have the case of an API change that Java Converter Did for you, actually, this instead of returning a component, we now return an interface. And here are some warnings that Java Converter put in for you. And in this case, the warnings are not very useful because the syntax was correct in the first place. And here there were some changes that Melissa will talk more about later on. NSGogorianDate has been replaced by NSTimestamp. And all the APIs and class names have been changed accordingly.
More on this time stamp changes. OK, and you can trust me. Most of these are just the same. Right? You trust me? Yes. Okay, so now the next step is to open the new converted project in the new project builder. So I'm going to click on "import pb.projects". This is one of the wizard that project builder comes with. And I'm going to point it to the converted project.
Are people coughing on purpose? Okay, so that's it. I have my classes here. My components, everything is ready, even the frameworks are here. So one good thing about conversion is that it enables you to do a lot of cleanup. Because Objective-C and the bridge were really lenient, you could go along and have a lot of inconsistencies. And you'll notice that most of the changes I'm going to go and do now are to fix inconsistencies. Here's a framework that we didn't use that was there listed, so I'm just going to remove it. One framework I do need to add is the JDBC Adaptal Framework.
Here. And I'm not as good as Steve Heyman, so I'll just select all the targets. Here, I put it at the right place, it looks better. What else? I have a new model and I'm going to open it because I know I need to do some changes in there. Java Converter does not fix the e-models for you. I will go and switch adapter. This is the JDBC adapter. You have the non-adapter. I don't recommend using the non-adapter. Use the JDBC one. It won't take you far.
Now here, another thing that I found that was inconsistent in this model is that we had a lot of packages, business logic server, and we never referenced these packages anywhere in our project. So why keep, and actually Java will refuse to run our app if we keep these packages. So I'm going to get rid of them.
Now if I inspect one of these, at this point I should be able to go and fetch it. My OpenBase database is running and I can look at entries. So, if I go and look... I think I have something else to fix. Yes, here. One tricky point in the EO model is that... Most of the number classes cannot be resolved automatically by the JDBC adapter. So here you see that the value type for number is set to an int, and that's correct. But here for big decimal we have no value type. So this has to be fixed to the capital B.
This is the type in the model, this is the type in Java at the end when I run the application, the class, and this is the type, the intermediate type set up by the JDBC adapter. If you have questions about that, I recommend going to the advanced EOS session.
Is there any more of these? This number... There is one more, I have to find it. It is... in the movies. Number, big decimal, here, this one. It needs to be fixed. No, I won't forget to save it. Leave it open just in case I forgot something. Okay, now I think I can build. Let's see what kind of errors I get.
[Transcript missing]
So I'm just walking through it like you would if you're a developer. So I will know the app compiled, so I'm now starting the application from Project Builder. And it will start Internet Explorer.
OK, so here I had an error. And I'm going to go try and figure out what's wrong. It's saying that it was not able to create the page main. I can close this one. Let me go to the terminal. So when you cannot create the main page, it means it's pretty bad. And I know where it is.
If you remember during the file merge conversion, when I used file merge, There was a change done here on this line. And Java Converter is clever enough to recognize an application and to insert a main function so that the application can be started. Except here, it was not able to recognize it because there was a complete package specified. It was not clever enough to recognize that this is actually what application. So I need to add this main function myself by hand.
So all this main function does is forward. So call the main call to our own main function. I will save and stop that and recompile.
[Transcript missing]
It seems to work okay. I mean... Boy, I hate this movie. I won't enter a review, but I still hate it. Let's add a test. See if the features of this app work.
Okay, so there is another problem, which is to be expected. And the problem is in this... New NSDictionary here and the page is... what page was this? A display video page. So let's try to look at this display video page. So this Play Video page doesn't have an NSDictionary, but takes a mutable dictionary. So I'm just going to go fix that, and that will be it. Once again, I don't know how the bridge could live with this, frankly. But pure Java doesn't take it.
[Transcript missing]
There. Actually, an old one there, too. Okay, so that's about all it takes. So, as you see, 80% of the work was done. The last 20% interesting part was left to you on most of what we did was cleaning up an imperfect model on an imperfect application in the first place.
So, as you all write perfect code, you should have much less problems than we do, even in our examples. If I may, I will just do one last thing and open up again the window where I did the conversion. And if I just type Java converter, I see the... The set of parameters that can be passed to it.
You have a flag to stop the conversion at the Bridge Java application. So if you're converting from Objective-C to Bridge Java, you can do that with this flag. You have a flag When you are using Objective-C conversion to specify extra headers, to resolve macros and so on, you can also give special instructions to the precompiler. And you can specify your project directory, an Objective-C file, a BridgeJava file, or a WebScript file.
And then there is a description of all the other flags. So one point I want to make that Melissa didn't is that the bridge Java conversion will only work on Windows NT because, as you know, WebObjects 5 does not run bridge Java applications. And WebObjects 4.5 on Mac OS X does not run any bridge Java application either. So while you're on Windows NT, you can use Microsoft's converter from Java to C#, and you get a 64% conversion to C#. That will be it. And give back the mic to Melissa.
Thanks Francois. So as you can see, most of the problems you're going to run across in doing conversion of applications are, well, many of them are going to be your own fault. Now I'm going to talk about what you're going to see in your code after conversion has happened.
You take the Java converter, you run it, and as Francois showed you, we do some stuff to your original code. There's two general classes of things you'll see afterwards. There's stuff we've put in specifically to help with conversion, and there's stuff that is new in our frameworks and is intended to be ongoing.
We've added some convenience classes to help you port your code to pure Java: NSComparator, NSBundle, WoeTimer. These are things that often have equivalents that, you know, you could write Java code to do what they do, but we figured we'd save you the trouble. We've left some classes like NSCoder and NSCoding in, although they're now completely abstract. We removed a few things: NSRunLoops, NSUserDefaults, and we changed the validation mechanism to be more in line with the way Java works.
NSComparator is a pretty simple class. It encapsulates NSComparisonResult from Objective-C. We only use it in a couple of places. We use it in NSArraysSortUsingComparator method, and it basically sorts the elements of the receiving array into a new array. We use it in NSMutableArraysSortUsingComparator method, which sorts in place the elements of the array.
If you're writing new Java code, you may want to consider making any classes that you're going to be sorting comparable. This will have sort of two things. Comparable isn't an exact match to NSComparator, but it does allow you... to create one really simple comparator to use in these things that simply defers to the comparable methods on your underlying objects.
NSBundle is going to be pretty familiar to those of you who work with the Objective-C. It corresponds to the directory where related resources are stored. It still has some deprecated APIs to help people who are converting from 4.5. And we've extended the functionality to handle properties files and we have some new APIs for finding and loading resources. For those of you who are using it in 4.5, you should note that the Java class loader does not support the concept of dynamic class loading, so there is no concept of loadable bundles in WebObjects 5.
We've renamed and deleted some stuff. Most of it shouldn't worry you very much, but just so you know that it happened, we renamed NSTimer to WoeTimer, and we don't use it for session timeouts anymore. NSRunLoop has been removed. For those of you who get into decompiling code, we have a private WoeRunLoop that we use for Woe application-specific stuff, but you should not be trying to use it. And we've removed NSArchiver, which was the concrete subclass of NSCoder. We'll talk a little bit more about that when we talk about serialization later.
User Defaults is one thing that took a fairly serious hit. We've actually deprecated the User Defaults class itself, although the sort of concept of defaults exists in a class, NSProperties, that we'll also talk about later. Some of the default names, now property names, have been deprecated. Woe Debugging Enabled, EO Adapter Debugging Enabled, NSProject Search Path. They're still there, but they do different things and they may not be there for long.
And some defaults have been renamed. Woe CGI Adapter URL is now Woe Adapter URL, and Woe Should Send Lifebeat is now Woe Lifebeat Enabled. We'll talk more about properties and what they've become later. And we had to change the validation mechanism. To review, for those of you who have had 4.5, but you wrote those methods a long time ago, validation methods in 4.5 took a pointer to the target object as their parameter. They returned an exception object.
If, for some reason, the target object was invalid, and if coercion was necessary, that would happen as a side effect on the target object. Well, having side effects on target objects that are passed in as parameters isn't something that Java's really good at. A lot of Java's value classes are final and immutable.
So we had to change that. So validation methods in 4.5, once again, they take the object as their parameter, but instead of acting by side effect, they return the valid value for that parameter as the return value. So validation methods in 4.5, once again, they take the object as their parameter, but instead of acting by side effect, they return the valid value for that parameter as the return value.
So validation methods in 4.5, once again, they take the object as their parameter, but instead of acting by side effect, they return the valid value for that parameter as the return value. And if for some reason that parameter value was invalid, they throw an NSValidation validation exception. If they do return null, that should be interpreted as coercion to the null value in Java. Note that the Java converter doesn't take care of this for you. You're going to have to go through and look at your validation methods and figure out what they really should be returning.
Here's some examples of method signatures in Objective-C 4.5 Java and 5 Java. The first one is pretty simple. It's a validate street address. It takes a pointer to a string, and you can see that it returns an NSException. 4.5 Java looks very similar because we're going through Java wrappers to actually use Objective-C classes underlying the Java. Again, we pass in a string, which is down there in the bridge, interpreted as an NSString, which can be mutable if it needs to be, and we return a void. Or, we don't return anything, I suppose would be a better way to put it.
That would be that one. And the final one is the correct way to do this in WebObjects 5. Again, you see that we're taking a string parameter value, but also see that instead of returning a void, we now return a string and throw a validation exception. That's pretty much all there is to it.
And now on to the new and interesting stuff. We're engineers. We don't know when to leave well enough alone. We have to constantly add new stuff to our products or we get unhappy. So we've added some new stuff. We've added a bunch of time classes, NSTimestamp, NSTimestampFormatter, NSTimeZone. We've added NSSocketUtilities to help you with creating sockets. We created a new class called NSLog and, as I mentioned earlier, NSProperties.
We've done some stuff with NSLocking, which some of you may be familiar with. We've changed key value coding around a little bit and we've moved to Java serialization. We've also done some stuff in other, you know, less central WebObjects packages like Woe Mail Delivery, Woe Smile, and Java Plot.
Why NS timestamp? This is a question that we've had several times already at this conference. We've had it from people who saw the beta. We've had it from people who, you know, immediately download, install the WebObjects developer stuff from the CD you got. We wanted to basically give you all of the functionality that was in NSGregorianDate in our WebObjects 5 product. And we ran into some issues in the JDK.
First off, for those of you who've looked at it, you know that their time zone class does not contain historical information. And as we were trying to implement that, we ran into some other assumption conflicts with the way we were implementing time zone and the way their date classes worked. So we needed to create a time class to work with our time zones.
Why didn't we call it NSCalendarDate or NSGregorianDate? No great deep reason. We wanted to show that it was descending from Java SQL timestamp. And to a certain extent, the word calendar is already in use in Java. And given that our timestamps don't work at all in the same way, we didn't want to introduce any possible confusion. One thing to remember is that you really shouldn't use our stuff with their stuff. It doesn't work too well. You will see weird behavior.
NSTimestamp, as I said, is a subclass of Java SQL Timestamp. It replaces all uses of NSCalendarDate, or for those of you in the bridge Java world, NSGregorianDate. It provides most of the same functionality that you saw in 4.5 or 4.5.1, and EOF maps database datatypes into NSTimestamps. Something that has changed noticeably that may affect a few of you is that we have a new reference date.
We've moved from January 1, 2000 UTC, which was the Objective-C sort of time zero, to January 1, 1970 UTC, which is the Java and Unix standard time zero. We've also added a timestamp formatter to, well, format timestamps, subclass of Java text format. It doesn't really do much, although one thing that you might be pleased to hear is that it's capable of dealing with Objective-C pattern specifiers, as well as Java pattern specifiers. And it's a little bit heavyweight, so if you've got an application that formats timestamps into strings in a number of places, you may want to consider creating one timestamp formatter and sharing it amongst all the stuff.
We've created NSTimeZone. As I mentioned earlier, this allows you to have a correct historical and geographical context for your time. It's a subclass of Java Util TimeZone. It's built using the standard zone info files that you get from, by FTP, from lc.nci.nih.gov. This basically lets you, and there will be a till about this later, you can, if those files change, you can download the new versions, compile them, and drop them into WebObjects to get the new zone info. And it should only be used, as I mentioned, can't reiterate enough, with our time classes. Don't try and mix and match with Java.
NSSocket Utilities is a fairly simple class that we added to let you specify connection timeouts, and if socket creation fails, it will throw an I/O exception. Without the utilities, there can be a problem on some platforms where failing to create a socket will hang your system indefinitely, and we kind of thought that was a bad idea.
It's fairly simple to use NSSocket utilities. Here's an example of how you'd create a socket using the standard Java way. You see you've got your constructor taking an address, a port, a local address, and a local port. This is the equivalent in using NSSocket utilities. It's a factory method that takes an address, a port, a local address, a local port, and a connection timeout measured in milliseconds. And notice that we catch the exception, which means there's no socket and we have to deal with that somehow.
NSProperties, as I mentioned earlier, replaces NSUserDefaults. It's basically a wrapper to the standard Java properties mechanism, which you can see defined in Java UtilProperties. It's a convenience class for merging application properties with standard system properties with framework properties and all that kind of lovely stuff. For conversion, people who are converting, a lot of the methods that were on NSUserDefaults are still around on NSProperties.
What are properties? Where are properties? Properties can be read from a number of sources. There's a set of standard system properties that come with your VM. There's user-specific properties stored in hot Java properties. Your frameworks can have their own properties files. Your application can have a properties file, and you can specify them on the command line.
We use the standard Java conflict resolution mechanism, which states that the last property read is the one that gets used. They're read in this order. It's worth knowing. More details. Properties files must be named properties, and they must be located in the resources directory of your framework or your application.
They're in the standard Java properties format, which is that they're in a file. Each property is on its own line. Each line has the format. Property key equals property value with no spaces around the equalizer. If you want to specify the properties on the command line, you use the standard Java-D flag, although we do also, in a deprecated fashion, support the old Objective-C format for command line arguments.
NSLog, I mentioned. This is a class that we're actually pretty excited about. We think it's neat. We think it should be very useful to most of you. There's actually three classes involved. There's NSLog, which is a static class that allows you to interface with the WebObjects logging system. There's Logger, which is an abstract class that defines sort of the core functionality in which you should subclass if you want to do your own logging mechanism. And we provide one concrete subclass, the PrintStreamLogger, which will basically log your output to a PrintStream.
Why do you want to use it? Well, there's a few reasons. It's set up to allow you to control the scope and granularity of debugging. You can set up debug groups and debug levels, which will allow you to say, if you have an application that does... HTML generation has business logic and has database access. You can separate by debug groups logging in each of those areas, and you can turn only one of them on at a time if you want.
Or you can use debug levels to say, well, I'm in development, but I don't want to have to worry about touching my code when I go out of development. So I want all of this logging to happen at one debug level, but once I move into deployment, I want to set a different debug level, and I'll only see really critical stuff. You can redirect the output however you want by subclassing logger. We provide the print stream. You can set it up to do email or anything else you really want.
If you decide that you want to turn on verbose logging, it will also print out the timestamp at which the logging happened and the thread that did the logging. This can be useful if you're trying to track down synchronization problems. And there's an issue, known issue, with Java Runtime Exec, which is that if you launch a child process using Exec and then don't pull data out of the child process's out and error streams, then your child process will eventually hang when its buffers get full. Again, we don't think freezing is good.
Here's a sample of how to create a debug group. It's pretty simple. You'll notice that it's long and that we're left shifting by 40. The first 32 bits are in use by internal WebObjects logging stuff. The other 32 are open for you to use however you'd like to.
The second bit is an example of how you would pass in a command line parameter to enable debugging. Here's your command line. Basically, you read in the property. Standard Java, this is how you read properties mechanism. If it says you should be debugging, then enable the verbose debugging on the debug out and error streams. Enable debugging for the group that we defined earlier, and set the level to informational. This will print out everything in that debug group.
It's fairly simple to redirect the output to a different directory. Again, you pass something in in the standard Java properties format. Again, you read a standard Java system property. If the property is there, create a print stream pointing at that file and set as appropriate. Here we show setting NSLOG debug. You can also set NSLOG out and NSLOG error. If you want, you can set that to null and no logging will happen at all.
Hi, my name is RD Willhoite. I just want to get this out of the way to begin with. I'm not female and I'm not French, but I am a WebObjects engineer, so it does sometimes happen. Today I'm going to be telling you about a different manner of interacting with the WebObjects application server. As Melissa alluded, I will be talking about NSLog. I'm also going to be talking about the Willmail Delivery class, which is not new to WebObjects 5, but has been revised slightly. Now it uses the SMTP client class in Sun's standard class libraries.
I'm going to show you two different forms of email integration. The first thing that I'm going to show you is sending of WebObjects components to a hypothetical customer. The second thing that I'm going to show you is sending of critical error messages to a hypothetical system administrator. For demonstration convenience, I'm going to be using the same email address for both the customer and the system administrator. Obviously, this wouldn't be the case in real life, but I only have one web browser here. I'm sorry, one mail browser here.
Also, in order to clarify the demonstration, my application copies some of the images from the Think Movies example, but it isn't actually the Think Movies example. It's just a partial mock-up. I'm not sure if we're going to be able to make the source code for the demonstration available, but I didn't want to confuse you if you do have a chance to look at the source code. As many of you may know, the WoMail Delivery class is capable of emailing a message to a customer. You can use this as an alternative mechanism for interacting with the web application server. Let's take a look at our project.
We are going to be looking at the application class, and more specifically at the constructor for the application class. One of the most interesting things that's happening in the constructor, which is going to be invoked at startup time, so we're going to magically see an email appear in our mail browser, is that we're invoking a direct action called send email form action.
If we go and look at this direct action, We see that it's very simple. It really only does one thing: compose component email. So we're going to be sending an email using a page component called email form to a pre-specified recipient. I'm not going to show you the source for the page component. You'll see the results of the source when I launch this thing. So let's fire it up and see what happens.
As this thing starts up, I wanted to mention that I'm doing some of the configuration on the sly of the SMTP host used by WoMail delivery, as well as the recipient and sender and all that stuff, using command line arguments in Project Builder's launch panel. So that's how it's finding out all of this information.
So it's started. Let's go and look at our mail browser. And we see that our friendly WebObjects application has sent us and email, and this is a list of movies that we can rent. Each movie is represented by a hyperlink. I'll choose my favorite one. I don't know if any of you can guess which one that is.
For some reason IE wants to insert itself. I don't know, I think Microsoft is wanting to get on stage with me. But anyway, I'm going to go back to the project to show you what's happening behind the scenes before we see what happens, what the result of clicking on the hyperlink is. So if we go and we look at the direct action class again, clicking on the hyperlink actually invokes a second direct action called rent selected movie action.
And this action does two things. The first thing that it does is that it sends a confirmation email to our hypothetical customer. This is essentially the same thing that we've just done, so that's not especially interesting. The second and more interesting thing that we do is that we do a bit of investigation as to what movie we've got. And we see that the application has come back to us and... It's given us the confirmation email, but uh-oh, we've received a system error.
So this is intended, obviously, for the system administrator, not the customer. It's an atrocious cinema alert. Apparently the... Apparently the WebObjects application doesn't like my choice of movies. Going back to the project, let's see if we can answer the question, how is this email being sent? So we saw here that we're actually checking what movie we're selecting. This thing isn't emailing it every time. I don't have anything behind the magic curtains here.
All that it's doing is it's invoking the Appendlan method of the error member of the NSLog class. And you can see that it's just passing a string. And the string, I happen to use HTML because it looks nicer in the mail browser. Because we have nice HTML rendering in mail.app.
But you could do any string. Obviously it doesn't have to be HTML. But the real question is, how is the email being generated? This is not really clear here because as Melissa mentioned, our default loggers, which are the print stream loggers, spew things to the console as well as to specified files. So.
What's happening here? What happens is that the logger class is actually an abstract class as she mentioned. And you can subclass it. As a matter of fact, you can insert this thing into the NSLog class, which is the broker for all of the logging interactions. You see here in the declaration that we're extending NSLog's logger inner class. And if you look at the class initialization, you see that we are initializing all this stuff using those commands. command line arguments that I mentioned before.
We create a new instance of the MailLogger class. We set the error member of NSLog using this new instance, which you saw before. The local variable is called error. That's the mail logger instance. So, unfortunately, this doesn't really tell us how the email is being sent. To understand that, we need to go and look at the AppendLin method. There's a lot of code here. This example is complete. It's a simple example, but it is a complete example.
We're not going to be talking about all of the accessor methods and all the rest of that jazz. As you can see here, it's hard to see with a big font, but I'm actually in the AppendLin method now. This is an abstract method. I've implemented it here, but instead of using print streams, I'm using the SMTP client class in order to email the messages.
I've already mentioned how this is different from the default logger. Why you care about this is that in Java, it's still useful to log things a lot of times, and unfortunately, it's still necessary. The debuggers can be pretty decent, but sometimes it's unavoidable when debugging things to log things to understand what's happening.
One of the nice things about this is that you can use the default print stream loggers, which is really just equivalent to System.out.println and is just as easy to use. You get all the same capabilities, but you don't have the problems that Melissa alluded to, and you also don't have to comment the things out and recompile.
You can just leave it in there, and you can turn off the loggers. You can even configure that at runtime using some command line arguments. I'll refer you to the documentation for more information on those command line arguments. This is just a demonstration of one of the new features, NSLog, in WebObjects 5, but I hope that this demonstration encourages you to take a look at the whole product.
Thank you for your time. Thanks. Well, on to more stuff. That was interesting and fun, and I've still got less interesting stuff to deal with, so please bear with me. NSLock. This should be familiar to a lot of you who were working with Objective-C. There's three classes, NSLock, NSMultireaderLock, NSRecursiveLock. They all conform to the NSLocking interface. This basically says that thou shalt implement the methods lock and unlock.
Mostly they're here to facilitate conversion from WebObjects 4.5, but they also are a little bit more complicated and a little bit broader than the Java synchronization mechanism. So they can coordinate locking of objects over a longer period or over a more convoluted code path, and they can allow developers to do things that are kind of hard to do using just synchronize. A good example of that would be the multireader lock. Java's synchronization method doesn't distinguish between reading or writing, so it always locks the object that you're looking at.
But if you're writing your application, you may know that 99.9% of the time it's going to be a read, so it doesn't really matter if multiple things are looking at the data at the same time. So you may want to use a multireader lock, which will end up only locking the object when you're trying to write to it.
Key Value Coding, a lot of you are probably going to recognize that name from previous versions. It's a unified way to access properties of different types. It can access things that are in methods, private methods, public methods, instance variables. NSKeyValueCoding is EOKeyValueCoding split up into a number of pieces.
There's four abstract interfaces that define the various methods in key value coding. There's an error handling interface, and there are some default implementations that we provide. The first interface is generic NSKeyValueCoding. This is the very basic, if you want key value coding behavior, you must implement this interface. It defines value for key and take value for key.
It has a subclass, NSKeyValueCodingAdditions, which implements value for key path and take value for key path. The methods storedValueForKeyPath and takeStoredValueForKey were defined and split out into EOKeyValueCoding. Again, that's a subclass of NSKeyValueCoding. And finally, there's EOKeyValueCodingAdditions, which defines the methods values for keys and take values from dictionary. This basically allows you to implement whichever pieces of the key values you want. So you can use the key value coding stuff you think you're going to need in your application without having to implement any of the rest of it.
In each interface, we define two static inner classes. There's the default implementation, which is a convenient way to get at the default behavior if you want to add key value coding to a class. And there's a utility class, which is a convenient way to get the default key value coding behavior for any class, whether or not it implements the key value coding interface.
As I mentioned earlier, we've gone to Java serialization. NSCoder and NSCoding are abstract now, and we've replaced our use of them with the native Java serialization scheme. We've left them in place in case you had subclasses of NSCoding that you wanted to continue using. Any classes that implemented NSCoding are now serializable in Java.
If you want to see an example of how Java serialization works, have a look at the persistent session store example that we shipped with WebObjects 5. What are the advantages of doing this? Java developers don't have to learn a new archiving scheme, which is a good thing. The Java runtime framework does all of the work. It takes care of graph traversal, it takes care of cycle analysis, all of that stuff. We don't have to worry about it anymore. We can concentrate on making WebObjects better.
WOMail delivery, as RD was talking about earlier, is based on sun.net.smtp.smtp client. This is a protocol that doesn't support CC or BCC, so people who are CC'd will also end up in the to field. But it does allow mail pages to submit forms or to see pictures because, well, absolute URLs are generated.
JavaPlot. Some of you may recognize this from previous versions. It's now AWT-based, which means that all AWT fonts are available and that images are anti-aliased. There's been a number of bug fixes and some improvements. Unfortunately, it's now subject to limitations of the AWT, which is essentially that if you want to use it, you have to have a Windows server running. This is a limitation that should vanish when 1.4 is released later this year.
and the WoeSmile Framework. Some of you may remember that we demonstrated this at WWDC last year. It's now part of the official WebObjects product. For those of you who don't know, S-Smile is the synchronized multimedia interface language. It allows you to create smile content. Smile is defined by W3C specification.
It allows you to generate dynamic multimedia content, which can be played with QuickTime Player. It's integrated with WebObjects Builder for a drag and drop experience. And it allows you to lay out your multimedia project not only visually, but also temporally, so that you can specify not only where things appear on your multimedia application, but when various pieces of it start playing, if you have streamed content.
And I think we're done. In summary, WebObjects 5 is pretty much the same as WebObjects 4.5 and 4.5.1. We haven't changed an awful lot. We've added a few things. We provide Java Converter to help you migrate. And we've added some new stuff to encourage you to move from 4.5 to WebObjects 5. I think that's all I have to say. Unfortunately, I can't play guitars and I don't sing very well, so I can't live up to James Dempsey's yesterday. And I think I'd like to call my QA team. Actually, I think first I'm supposed to mention the lab.
And it's open until 6 most days this week. And I'm supposed to encourage you to vote for WebObjects is the best app server. Here's some of the other things that you might be interested in, some things that have changed between WebObjects 4.5 and WebObjects 5. There's a direct-to-Java client, XML, later this afternoon, and deployment has changed a bit. And if you have feedback, and I'm sure you will, there's the feedback forum on Friday. and a list of people to contact. There's Tony, who's our director, Bob Fraser, our marketer. There's iServices. Lots of URLs up there.