Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2004-639
$eventId
ID of event: wwdc2004
$eventContentId
ID of session without event part: 639
$eventShortId
Shortened ID of event: wwdc04
$year
Year of session: 2004
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC04 • Session 639

How to Test and Debug Your Cross-Platform Java Application on Mac OS X

Enterprise • 51:26

In this session we show you critical techniques for building fully platform-independent Java applications that can be deployed effortlessly on Mac OS X and other OS platforms. We demonstrate tools for diagnosing and troubleshooting your Java application, and provide pointers to the resources that Apple provides the Java development community.

Speakers: Tom O'Brien, Barry Langdon-Lassagne, Matt Drance

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Happy Wednesday. Thanks for coming. I'm not actually speaking in this session. I just wanted to give a quick introduction. My name is Matt Drance. I work in DTS, and I'll be coming back at the end of the talk to talk a little bit about DTS, what DTS does, in case some of you don't know about it. But I just wanted to introduce you because I think that this is probably the most useful Java talk this week, as far as you guys are concerned, aside from mine tomorrow.

But when you guys are out of here in an hour and a half, you're not going to have to go read any documentation or download anything at the end of the day. You're going to know everything we know about debugging, analyzing, monitoring Java applications on the Mac. And I think that's something that a lot of people have been waiting to hear about. So without further ado, I would like to introduce Tom O'Brien from the product engineering team. Thanks, Matt.

You're in the right talk if you're a Java developer who wants to deploy your Java on Mac OS X, but you want to find ways to avoid cross-platform compatibility issues that you might run into. or if you want to know ways to isolate problems that you find running Java on 10, or report problems back to Apple when you think it's Apple's bug.

So how are we going to approach this? The talk is going to be in three parts today. First, we're going to show you coding techniques and tips for getting the best cross-platform behavior out of Java. Second, we're going to show you testing and bug isolation techniques that help you find problems using the tools available to you on Mac OS X. And third, we're going to tell you how to write an effective bug report. So let's get started with the first section.

Java is positioned as a cross-platform development and deployment environment, and that's true. And its catchphrase is, "Write once, run anywhere." Everyone has heard that. But in the finer levels of detail, the platform independence isn't an automatic thing that you get for free. Your application may run great on one Java implementation on one platform, but the same code running on another platform may run well, but not in the exact same way at the finest level of detail. You may not even be aware of all the areas that have subtle differences in Java implementations. We're going to highlight some of those today.

How are we going to approach this? Well, first we want to have you thinking about it in a slightly different way. We want to show you the tips to get the best cross-platform behavior out of your code. And the things we show you today are applicable to all Java implementations. Even though we're going to be focusing on Mac OS X, we're not trying to do it in a platform-specific way. We're trying to show you general techniques that allow you to run equally well everywhere without doing something platform-specific, if you can help it.

will help you be aware of the areas where different platform implementations can differ so that you can adapt to those differences, or again, design in a platform-neutral way so that you don't have to adapt. So let's move on to an example. The anti-aliasing settings for text and graphics vary from platform implementation to platform implementation. And in fact, on Mac OS X, for applets in the browser, users can set whether anti-aliasing is on or off as a preference. So it varies from run to run. So you can't guarantee that it's on or off in any particular situation.

Here, just to remind you, here's the same code drawing aliased and with anti-aliasing on. And you'll notice that line rendering gets much smoother in the image on the right, but it also changes the appearance. And this may matter to your application. So what should you do? If it matters to your application, you should set and check the anti-aliasing settings explicitly, rather than assuming that they're on or off. Here's how to deal with it for text only. And this is using standard Sun Java 2D APIs to deal with the rendering hints. Here's how to do it for both text and graphics. And these are just, again, standard Sun APIs in Java 2D.

Moving on to a more specific example. For anti-aliasing for text, in the swing Aqua look and feel on Mac OS X, text anti-aliasing is on by default. And this is in order to fit in better with the other Mac OS X applications and match the Mac OS X Aqua guidelines. It improves readability of text at small point sizes, but text metrics are likely to be different between aliased and anti-aliased text. And you see here, this is the same code running with anti-aliasing on and then off.

You notice that not only does the appearance of the text change, but the length of the text changes. And so metrics that you gather with the setting in one position aren't valid when you switch to the other position. So how do you deal with this? Once again, check and calculate things rather than hard-coding or coding. Here, again, is a standard-sun API for dealing with, in this case, calculating the string length of a particular string rendered in the current rendering context with a particular font.

And this tells you how long that string is going to be right now. It's referred to as width, of course, because it's graphical, but we think of it as string length. So you can find out how many pixels wide that string is going to be right now when it's rendered on screen and deal with that appropriately if it matters to you.

Moving on to other metrics issues. Control sizes for Java implementation widgets vary across platforms. The same controls rendered on Mac OS X using the same code running on other platforms don't have the same appearance, the same font, the same size. And this is a standard change that happens from one platform to another that is intended to fit in with the platform look on that particular native platform.

But it makes it fragile to hard-code widget and font sizes where you've gathered information based on the behavior and metrics on one platform. So how do you deal with this? Once again, there are APIs that let you check rather than hard-coding based on what you've measured on one platform. For widget sizes, the Sun API is the same as the Java API.

To get the preferred size of a component is relevant here. For fonts, you can find out what font you got back for a particular default font, and you can find out the metrics for that font, again, in the current situation and the current rendering context and deal with it. And we already showed you how to calculate the string length in the particular rendering context that you're in right now with the particular font you're running with right now.

A more general approach for dealing with the fact that UI metrics vary among different implementations of Java is to use a layout manager. The layout manager will arrange the UI for you based on the situation that's happening on your platform right now. This has the additional benefit, if you're even on just one platform, of handling what happens when you localize strings to other languages. They tend to change length. Localizing out of English into other languages often tends to make for longer strings that may not fit into fixed bounds that you've already picked.

And the layout manager will deal with that gracefully for you. In order to discover whether you have successfully made your code metrics-independent and can flexibly deal with different platforms, you should try your code out on multiple platforms. If you're using this example here, this is something that's running in the Java implementation on Windows. And if we use the same code and hard-set the window size based on what we measured that it fit into on Windows, you notice that the button and even more the label at the bottom are the same.

You can see that the buttons are clipped because those don't fit in the look on Mac OS X. However, if you use a layout manager and then pack, it all fits in nicely and looks great. For more details on the Layout Manager, you can go to the Sun website and pick up more information about this and other topics.

Another UI thing that varies between Java implementations and is especially important on Mac OS X is that the window resize user interface is in a different location, again, in order to fit in with what fits on that particular platform. On Mac OS X, the resize box actually takes up space in the window content region in the extreme lower right-hand corner, and that's intended to tile in with the scroll bars that are normally on the lower and right-hand edge of the window.

But for Java code that's coming from other platforms, that may end up covering up content that's in the extreme right-hand corner of the window. You notice in this sample application, the extreme right-hand button is covered up by the resize box. So how do you deal with this? Well, there's several different approaches.

The general approach would be, if you didn't crowd your UI so that the extreme lower right-hand corner of the window is important, it may open up your UI and make it look cool anyway. That may fit in with what you plan for your application. If you're using a layout manager, it's within your control. And if you're using a layout manager, it's within your control. So you may have to use an empty placeholder component to hold out space underneath the grow box in order to make this work. Another alternative on Mac OS X is to use this Mac OS X system.

[Transcript missing]

This may end up being one of the cases where you actually have to hard code something for a particular platform. There may be situations where there's no way you can design your code in a really platform-neutral way and you really have to do something special for Mac OS X.

I want to emphasize that you want to do this only if you really have to. It's kind of a last-resort thing. You really want to design in a platform-neutral way if you can, but if you have to, this is the way to deal with it on Mac OS X the right way. You want to get the OS name system property, lowercase it, and then find out whether it starts with Mac space OS space X. Tech Note 2110 has more details about this approach.

Again, I want to say that if there are APIs that you get at specific metrics, you want to deal with those APIs. If you're interested in specific behaviors or metrics on that platform, ask for those specifically rather than trying to infer them from being on Mac OS X. Things may change from one implementation to another, or in some cases may even change from one to another, as we saw earlier.

So what have we dealt with? Well, the general way is to design your code in a platform-neutral way. And the way you confirm that you designed in a platform-neutral way is to try your code out on multiple platforms to see whether your assumptions work. This will help you discover inadvertent platform dependencies. In addition to the metrics issues we were talking about earlier, there's other things that you may be inadvertently depending on that you don't know about that you can try.

For example, if on a particular implementation there are special characteristics

[Transcript missing]

and Matt Drance, the two of you, will be presenting the first session of the Java

[Transcript missing]

In the current situation, we've been hard-coding them based on a previous platform or on a previous run. If all else fails, we will show you something platform-specific. We showed you the right way to build a Java application on Mac OS X.

We have Barry Langdon-Lassagne, who's going to show you some tips for building full-time Java applications. Thank you, Tom. Good afternoon. Welcome. Thanks for coming. I'm going to talk about two things in this portion of the talk. First, I'm going to talk about JUnit and how you can integrate Java into Mac OS X.

and David Dorn, are here to talk about the problems with Java. and David That's great. So you already know what JUnit is. It's an open source framework for incorporating unit...

[Transcript missing]

recently made available, and it's available on both Tiger and Panther.

[Transcript missing]

One is here you can see I import the unit framework.

And at the beginning of my class you can see that I have Tom O'Brien, Barry Langdon-Lassagne, Matt Drance Download JANET from janet.org and install it in your class path. Be important as well. Download JANET from janet.org and install it in your class path. Be important as well. I'm not going to go into detail about this. This is all standard. And then back down below, in my target, test target.

I thought I had-- I can try to bring it up a little higher. Sure. I have a slide that has bigger fonts, too, for that code. and you notice the output. In Xcode currently, the output from AMP happens over pain. So this window, and if you notice, the lower pain has a slider. And let me just open that up so you can see. Here's the compile target .

And then, I'm going to change the font size on this slide. At least I don't know where the settings are. This is the output from the test target in my build.xml.

[Transcript missing]

And then a stat crawl from the point of failure. So let me move over to my test code, which is in my test file.

The name of the failing method was TestForceFalseFailure. And I used the JUnits method to assert true. And for purposes of the demo, I set that to false so that we would get a failure. I'm going to change that to true. And then I'm going to run it again. And you'll see a little bit different behavior. Again, this time you can see in the compile target, it actually does compile because I changed my test case.

In the test section you can see all of the tests ran and all of the tests passed. And because the tests passed, it was able to connect to the jar section and then execute the code. And here's the application running where we show alias versus anti-alias text, which you saw in a previous slide. So that's JUnit running inside Xcode on Mac OS X. So back to slides.

The things you need to do. One, you need to write tests. You've got to write tests in order for them to run. Number two, you need to get a copy of JUnit and put it in your class path on your machine. On the demo machine, I put mine in library Java extensions. There's lots of different ways to add to your class path. And then third, you need to modify your build.xml file to execute JUnit. And this, on the screen, you see a very simple-- a minimal way of executing JUnit tests.

And then here, I've added one more argument to the JUnit command, the Halt on Failure argument. And if Halt on Failure is set to yes, then when you build with your ant project, if there are any test failures, then it will stop at that point. You'll get a failure and you know, your build will be considered to have failed. If you set that to no, it'll run the test, but it'll go on and build and run. So again, it's your choice.

The way you design projects, whether you want to set that true or false. I'd recommend true. Down at the bottom, you can see just the beginning of my jar target, and the default template for AMP-based projects For the depends clause set to compile, I've modified it to be dependent upon test so that it would execute the test as part of building the project.

So that's JUnit. Tests are integrated into your development process. You write your tests. It's a really nice way of integrating testing into your development process. It works really great with Xcode. I've been using it for a while now. Other IDEs, Eclipse, and Maria also support JUnit. It's cross-platform. There's a large, active community.

Most of you raised your hands, so you already know a lot of this. And for more information, go to JUnit.org and read the documentation there. So the other part, when things go wrong. Sometimes it's a problem in your code. Sometimes it's underneath you. Sometimes it's out of your control, and I'm going to cover both of those areas.

So I'm going to cover several things. I will show you some Mac OS X tools for isolating problems. Many of the tools-- well, some of the tools are specific to Mac OS X. Many of the tools are cross-platform tools you may already be familiar with. I will mention when I'm using a tool that's cross-platform, just so that it's clear. And the goal is to give you the knowledge you need to fix the problem, or if the problem is outside the scope of your code, in order to isolate it and to report an effective bug.

Let's go to a demo again. I'm going to do a little bit of role playing here. I am a developer fairly new to Mac OS X, and I'm starting to bring up my projects on the Mac. And Tom here, Tom is the expert, and I'm going to be calling him . So let me get this stuff out of the way.

Okay, Tom. I've written a little simple program. It does some painting. It has two separate threads, and both of the threads paint to the screen, and it's supposed to animate in between the two threads. But it doesn't animate. It's just sitting there. So you know Mac OS X. What should I do here? Why don't you try Activity Monitor? TOM O' Okay. Let's try Activity Monitor.

Oh, Thread Painter. There's my Thread Painter. So what am I looking at? This is showing you the state of all the processes that are running for you in Mac OS X. There's Thread Painter, and it looks pretty quiet. It's using no CPU, or essentially no CPU. So your application is basically stopped. OK.

So I can tell my application doesn't seem to be doing a whole lot. So let's find out more about what's going on inside Java right now. If you send a kill-minus-quit signal to that Java process, the VM will dump the state of all the threads that are running. Tom O' Okay. So I guess I need terminal.

Is that font big enough? Can you guys read? So kill minus quit, this is standard on Unix platforms. I send kill a quit signal with the process ID, which I can see here is 629. It should dump a stack trace out to standard out, but Tom, I don't see anything.

TOM O' Well, how'd you launch? How did you launch? I double-clicked the jar in the finder. Ah. It's going to end up in the system console. So go look in the system console. OK, let's take a look at system console here. This looks kind of like a stack.

Thread dump here. OK, look, I see this is some old debugging output from my application. I can see it-- Thread dump here. OK, look, I see this is some old debugging output from my application. Thread dump here. OK, look, I see this is some old debugging output from my application. I can see it-- Found one Java-level deadlock. Sure enough, it looks like I found a deadlock in my code. Let's take a look at my code. Threadpainter.java line 70. I'm going to open up Threadpainter and Xcode here. I'll go to line 70.

And there's my odd thread, and there's my even thread. And I have synchronized this even thread with an outer lock and inner lock, and-- I have an interlock and an outerlock on the odd thread. Looks like you've set up a classic deadlock. Did you do this deliberately? Oh, what do you think? Usually it's not quite this straightforward, but you get the idea, the tool, how to use the tool to find this type of problem. Let's go back to slides.

So the tools that we just used, you saw kill minus quit, you saw activity monitor, and kill minus quit. Kill minus quit works cross-platform. If you're running in terminal, if you're executing from the command line, you can also do control backslash and get the same information. If you're on a machine, you can do control break and also get the same information. So up on the screen, the little sample you see, I used top to get the process ID, and kill minus quit for that process ID to dump the stack trace.

And it pointed out one of the slight points of confusion, especially for people new to Mac OS X, where does the output go? If I was running in terminal, as you would expect, the output goes to the terminal right where you are. But if you're double-clicking a jar, or if you have a .app application in the finder, the output is going to go to the system console, console.app.

And similarly, if you're running in Safari, you have an applet in Safari, the output's going to go to console as well. Unless you have turned on the Java console using the Java Settings plugin, the Java Settings application, in which case the output goes to the Java console, which also has some other debugging tools that you can take a look at.

There's a help screen that shows up when you first invoke that console, useful for debugging applets. Lastly, if you're running-- if you're executing your code from Xcode, you'll see the output right in the run log. OK. So let's go to another demo. Same role. I'm a developer. Still getting my sea legs here on Mac OS X.

I had some of this stuff so that it's not distracting. And I have another little application I call Drawing Loop. And it does some animation. This time it does do animation. See, it's working. and I can turn on and off the box numbers. Each square has a number associated with the slider, the J slider down here at the bottom. But Tom, I have a problem here.

When I drag it all the way to the right, it just kind of stops responding. And then if I resize, it gets even worse. And there's that rainbow cursor. So I just saw Activity Monitor with the last one, and I can remember these things. So I'm going to look at Activity Monitor again and see what it tells me.

So here, look at this. This is very helpful. Drawing loop is hung. Activity Monitor, at least, thinks my application is hung. And I'm using a lot of CPU. So now what should I do? Should I use kill minus quit again? Get a stack dump? JOHN MCCUTCHAN: You'd find out what state the Java threads were in, but we have an even cooler tool for this. It's new this week. It's Shark for Java. BRYAN LAMBERT: That's right. JOHN MCCUTCHAN: So go launch Shark. BRYAN LAMBERT: I was at the VM performance talk yesterday afternoon when Christy demonstrated Shark.

So I do know a little bit about Shark now, because I just saw a demo. So let me try it with my application. So there is one piece of setup you have to do in order to use Shark. And you might have seen it in some of the output. In fact, I think in the console, it'll still say it right here.

Here, picked up Java options. I have set -x run shark in order to give shark the data that it needs from the Java runtime for it to do its magic. So shark is a profiling tool. You can use it to isolate bugs. I'm just going to do a time trace here. And I'm going to start it. And it's sampling what's going on in my application there in the background, the one with the spinning rainbow cursor.

Now let me stop, and it will produce this nice report. So this tells me where I was when Shark was sampling my application, where I'm spending time. And at the very top you see C:\SurfaceData Finish Lazy Drawing. That's probably not very readable. This one, the one at the top, is the one where the most time is being spent, where Shark sampled the most times. So I'm just going to open it up and see what I can learn from here.

This is a stack crawl. The leaf is at the top. And as I drill down, you can see I spend a lot of time in AWT, which was called by Java 2D. And then I get down to these blank ones here. But I recognize these-- drawRacks, fillScreenWithRacks, paint as my code. That's my code executing there.

knows about Java. The other tools that you may be used to using, such as Sampler or Sample on the Command Line, they don't have this kind of intimate knowledge of Java. Now, Paint, Fill Screen with Rx, Draw Rx. I want to go take a look at my paint routine. And Tom, maybe you can help me because you're an expert. See if there's anything here I'm doing that might be causing that rainbow cursor. So there's my paint method. Right here, down at the bottom.

Barry, you want to tell me what extreme count mode is? BARRY LANGDON- Oh, yeah, extreme count mode. Yeah, I just recently added that. When I drag it to the right, it's supposed to fill the screen with rectangles. And that's actually right here, fill screen with rects. And maybe I set the bar a little bit too high.

This is a dual processor D5. It can handle 10,000 runs of 10,000 rectangles, can't it? Eventually. Eventually. Yeah, actually, this is not hung. Even though Activity Monitor said it was hung, it would eventually return, but it would take a while. And I said it such that it would take a while. It's usually not that straightforward. So back to slides.

Here you saw, again, Activity Monitor. The CPU level was really high that time, so you did get some interesting information from Activity Monitor. You could have used Top in that same situation and seen similar data, and Top is cross-platform, at least for other Unix machines. And I showed you Shark, a great tool, recently enhanced, to tell you a lot more about Java. And there's a Shark Talk this Friday I'd like to tell you about, and you should go. Christy is giving the talk, and that's at 3:30, and I don't know the room name, but it's session number 307.

Oh, Sanjay and Nathan are giving the talk. And the talk is not specific to Java, but the techniques that you learn there should be useful for Java as well. So did I go back to demo already? OK, this is my last demo. Let's hide some stuff here. Oh, and so here's a little tiny tool, a little tiny technique. If you hold down the mouse on the icon, Force Quit comes up as an option. And if you don't see Force Quit, you can hold down the Option key to force Force Quit. It's a nice way of getting rid of your frozen app.

OK, my last app here, Tom, JNIwrapper.jar. This is a little piece of Java that calls a little piece of native code. So I can bring it up here. And when I click on this button, at this point it will call my native library that I've written, and it crashes. So what should I do? Should I click Submit Report here and send the bug to Apple? TOM WALSH: Hold on. Just hold that thought. We'll come back to that. Just put that aside.

[Tom O'Brien]

All right. Let me move that out of the way here. So what should I do with this application? Well, you said it was needed code that you're calling? TOM O' Yeah. Well, if you don't have source available to you, your best debugging tool that you have available would be GDB. So why don't you try attaching to it in GDB before the crash? TOM O' That actually brings up a very important point. Sometimes you do have source. If you have source, Xcode is the way to go. Single step in Xcode, trace these.

But there are lots of different situations where you might not have source. You might have a third party native library. You might be on a customer's computer trying to do debugging with what's there. You might be on a test machine in your labs. Lots of different times you won't have source, and so you want to use other tools that are available too. And you said GDB. I know GDB. So let me launch the app here. I'm not going to press the button yet. I'm going to use top this time. See what process it is. It looks like process 654. Copy that. And I will do a gdb attach.

I'm not going to teach you GDB. I'm just going to show you a tiny bit of GDB. Being aware that it's there and that it's useful is the main point here. GDB is now attached to my process. I'm going to tell it to continue so that my application has control again. And now I'm going to press this button. And you can see GDB immediately catches the crash.

So here I can do a thread apply all backtrace. Yes, there are shortcuts for this. And now I have a dump of all of the native threads that are running associated with my application. Many of these are Java threads like the event thread. But at least one of them should be my code. Let me go back up to the top here.

It looks like it could not access memory on thread 0xf603. And that's right here. So it's pointing to line 29 of my code. So sometimes you don't have source code. This time we do. So we're just going to take a quick peek. at my little JNI line. And we will go to line 29 in Xcode.

And here, Tom-- well, it may be fairly clear to you, but here I have a pointer and I'm dereferencing it. But oh, look, just above here the pointer got set to zero. TOM O' How could that have happened? Yeah, that could be a problem. And if you've ever debugged C code, you probably know that it's not that straightforward usually.

Sometimes it is. Sometimes it is. So why did you want me to set this window aside here? TOM O' Well, the Submit Report button has hiding behind it something very similar to what you just got in GDB, which is a native crash report showing all the native threads that were running at the point of the crash, including a little bit more helpful stuff pointing you to the exact thread number that crashed. So it's containing basically the same information you got.

And you sometimes get this if your application has a user interface. That's the basic rule, that you'll get this crash report window. You can copy and paste this information into a bug report, or you can use it for further isolation on your machine. TOM O' So now I can send to Apple? Sure.

Go ahead. TOM O' Well, you know, I just reported to Apple my own bug. So you probably shouldn't do that if it's in your own code. Let me point out, sometimes you'll get a report. Somebody says, my application crashed. And you said, well, did you grab the stat crawl? And they say, no. Those stat crawls are actually saved on your machine. And in this case, it's in my home directory in library log. folks.

And inside Crash Reporter, you see a java.crash.log file. This contains the log that you just saw on the screen for all of the crashes that have ever happened for this user on this system. And you may have noticed as I was navigating here, I went past a folder full of a bunch of Java native crash logs. And they have a PID associated with them. If I look back here at my GDB output, process 654 was the one that had crashed. And so that would be this one here at the top. And let's just take a quick peek at that.

If you're reporting bugs, this file can come in handy in isolating where the problem is. In this case, you see here, this is a Java stat crawl from the point where it crashed. And up near the top, we were in Java, and at the very top, it called a native method. So that's the point at which it kind of jumped out and left Java. And that's the limit of the information that the Java VM can give you about the crash.

There's also a little helpful reminder here at the bottom, and this has helped reduce some of the bug reports we get. It says, the exception above was detected in native code outside the VM. And it's usually accurate, maybe not always, but what that usually means is it wasn't Java crashing, it was something else crashing. It may have been a native library that you had written. It might be an OS bug. It may still be something that you'd want to report. I just wanted to point out that little detail. Okay, back to slides.

I guess the font could be a little bigger. So what tools did we use there? GDB Attach, GDB Cross-Platform, handy tool. We used the Crash Reporter window as a bug isolation tool. And you saw where I had found some of the crash logs in my library logs folder.

What have we learned here? This is a summary. First, in the first crash demo, in the first hang demo, I was spinning. The CPU was low. I found that out by looking in Activity Monitor. Could have used top, PS, similar techniques for finding that out. I did a kill minus quit to get the information. Control backslash also works.

In the second example, I had high CPU usage, which I saw from Activity Monitor. And in this situation, we used Shark. If you don't have Shark, you should download it. You want to get the latest version of Shark, both for Tiger and for Panther. The download is available on developer.apple.com tools slash performance. Do I have it right? Okay. And you could use kill-minus-quit in this situation. You would get some information that may help isolate it. The detail that you get from Shark is a lot finer grained, a lot more detailed, a lot more useful.

And then the last example, the crashes in native code. We used GDB. We also looked at Crash Reporter and the Java logs, as you just saw. But there's one more thing relative to that last one. What if it crashed and you didn't have a native library? What if there was no native code on your side, if it was pure Java? Well, pure Java shouldn't crash, right? It's not supposed to crash.

So sometimes you find a bug in Java, or perhaps in the OS, below that. So what do you do in that situation? Well, you probably want to get working right away. So the first thing you would want to do is find a workaround, or maybe see if you can get by without that specific piece of functionality. There's a very active developer community out there. The Java dev mailing list is the best way to get in touch with that.

How many people here are already on Java dev? Little less than half. Highly recommend Java Dev. You should sign up at lists.apple.com. It's a free mailing list and very active community. They can often help you find workarounds. Apple engineers are on there. Don't consider writing to Java Dev as being the same as logging a bug report.

And if you do get a crash, we do want you to file a bug report. And we don't want you to just file any bug report. Part of the reason we're giving you all these tools and techniques is so that you can file a great bug report, which leads me to the last part of the talk, where Tom is going to tell you how to do such a thing. Click. TOM O' Thank you.

So when you find a problem that you want to report to Apple, the best way to get that information to Apple is to log a bug report. Apple's radar database is the way we track hardware and software issues that come up and The best way we track hardware and software issues that come up.

As Apple developers, your way into the radar database is through the bug reporter web page that Barry just mentioned. He also talked about sending email to Java devs so you can find a workaround or discuss your problem with other folks. Apple engineers are often present there, but their presence isn't the same as filing a bug. So you need to use the official mechanisms to get your bug report back to Apple.

The crash report window that we just saw is intended mostly for end users, though we saw how we could use it to find out more about isolating the problem. But just clicking send report to Apple is intended as an end user technique. You guys have more powerful techniques, some of which we've showed you, in order to isolate the problem further in better ways. So what's in a good bug report? There's three major areas that characterize a great bug report. A good problem description, clear steps to reproduce, and technical information that gives the context for the problem that you found. We're going to go through each of these in turn.

First, the description of the bug that you found is a summary of what happened. First, what you expected to happen, and then what actually happened. And if you have to explain why you expected what you expected to happen, you can spell that out too. But you want to contrast those two things so that we know what you were really expecting. This is a modified excerpt from a real bug report.

You notice the developer has summarized the problem by setting forth what they were doing and what problem they ran into. And you also notice that they referred to a screenshot, which is an invaluable piece of information in bugs that end up being graphical, because it really does tell the story in a great way.

The second component of a great bug report is clear steps to reproduce. You want specific step-by-step instructions that a naive user could use to reproduce the same situation you ran into with little or no knowledge of your product or your particular problem domain. If those steps don't always end up having the problem that you ran into, you should indicate approximately how often it takes to run through those steps and hit the problem. Again, another excerpt from a bug.

You notice the developer has spelled out numbered steps of what you should do in pretty clear language, and has also contrasted that with what the computer was responding with. And a common way to do that is to use an ASCII art arrow, but there's plenty of other ways to make that clear.

The third area for context of the problem that you ran into is the technical details. And this breaks down into three further sub-areas that we'll go through. First, more detail about the failure. We saw how to capture crash logs. And in most cases, both the Java and the native stack crawls are important here for crashes that you run into in Java.

In the cases of bugs that do or don't involve a crash, any exceptions or messages that end up in the console leading up to that problem are also useful in isolating the problem further, and so you should include those. And we saw that for graphical issues, the screenshot is an invaluable piece of information in spelling out the story of what's going wrong.

The next subcomponent of technical details is the software configuration that you're running on. The Mac OS X version you found it on, the Java version you were running with, both of those in detail. And if it only happens on some Java versions or some Mac OS X versions, spelling those out and saying where it does and doesn't happen is useful in isolating the problem further.

Additionally, if you have access to Java implementations on other platforms, contrasting the behavior of the same steps or the same test case on those other platforms is also useful in tracking down the problem further. In the special case of swing bugs, saying whether the problem you see happens with the Aqua look and feel or with the metal look and feel or both of them is useful information because those are two different implementation paths. And another excerpt from a bug report summarizing the software config.

You notice the developers detailed the Mac OS X and Java versions. They've regressed with a previous version of Java to say whether it did or didn't happen. And they've even compared with Java on another platform. You notice the developers detailed the Mac OS X and Java versions. They've regressed with a previous version of Java to say whether it did or didn't happen.

And they've even compared with Java on another platform. Tom O'Brien, Barry Langdon-Lassagne, Matt Drance You notice the developers detailed the Mac OS X and Java versions. They've regressed with a previous version of Java to say whether it did or didn't happen. And they've even compared with Java on another platform.

You notice that they've compared it with a platform where it doesn't occur, and you notice they've also referred to the Apple System Profiler information that they captured. The Apple System Profiler can do kind of a brain dump of the entire configuration of your machine down to really fine levels of detail, most of which aren't usually relevant in Java bugs, but you never know. So it doesn't hurt to throw it in, but it's also useful just to have this brief summary of your configuration that I described with the CPU type and monitor configuration and other basic things like that.

We're into the fourth part of the three that I originally promised. The fourth part is great bug reports have a test case. A test case is self-contained steps to reproduce your problem. If we have a test case, it means that Apple knows that they're trying to reproduce the exact same problem that you originally found, because they're running the same test case that you ran to show your bug. Ideally, your test case shouldn't require user intervention. That's not always the case, but if your test case can discover whether the bug is present or not all by itself, that's really great.

A test case that can be run from the command line that's been whittled down to a simple public static void main test or is in the form of a JUnit test is a great way to present that. And if you have a JUnit test that can determine pass or fail all by itself, it may end up being put into our regression harness internally so that we run it periodically on upcoming builds of Java, and your test case will live on in immortality. Here's a reference from a real bug. You notice that the person who originally filed the triangle bug referred to a test case.

So let's recap what's in a great bug report. First, a clear description that contrasts the actual and expected behavior. Second, simple steps to reproduce that a naive user could go through to get to the same situation that you originally ran into. Finally, technical details, the crash logs that we showed you how to gather earlier, any messages to the terminal or console, any exceptions are useful to include, and the configuration information that we broke down, hardware and software configuration, comparisons if you have them with other versions of Java, Mac OS X, or even on other platforms. And the single most important part could be the test case, the self-contained steps to reproduce your problem that guarantees that we're talking about the same bug that you are.

Getting back to the triangle bug, the triangles draw just fine now in case you were worried. So where have we been today? We showed you techniques for doing platform-neutral Java coding when it's possible using the APIs that are available to you from Sun's Java that allow you to have your code work flexibly with Java implementations on multiple platforms and work great.

We showed you some bug isolation techniques for finding and isolating problems further when you run into them running Java on Mac OS X. And we showed you how to file an effective bug report to get information back to Apple when you think you found something that Apple should be aware of. Now I'd like to bring back Matt Drance, who has some additional points.

Thank you very much, Tom. So there have been a couple questions floating around this week and in weeks past about DTS and what DTS does and what DTS stands for. How many of you have actually logged an incident with DTS in the past? Okay, that's a pretty good crowd.

So DTS is Developer Technical Support, and I'm going to just reiterate what Barry and Tom said, is that the Java dev mailing list is a priceless resource. There are both Apple and non-Apple experts on the list that reply very frequently and very rapidly, sometimes too much frequently. I think in most of the sessions this week we've been telling people, if you join Java dev, set up a filter, because there's quite a bit of volume in it. But a lot of the information is very, very useful.

And if just community conversation doesn't help you out, you can talk to DTS and send an email to [email protected]. And what DTS does is basically we give people code-level assistance on a per-incident basis or a per-problem basis. And that could be something as simple as, "Hey, I read about this new API or this new feature.

I don't know how to implement it. Can you guys help me understand how this works?" Or it could be, "I have this bug, and I don't know how to work around it, and it's critical to my application." And we do anything in between or including those two things. Now, the reason I'm emphasizing this is because DTS does not actually fix bugs in the JVM or in the OS anywhere else. Engineering works on the bugs, and DTS works around them.

And I wanted to emphasize that because sometimes we get people writing in and saying, "Okay, I bought an incident. Will you fix my bug now, please?" And that's not really how we work. We'd like to think that we fix your bugs even if you don't pay us. But some people out there may be more skeptical. That's really the only message I wanted to send. DTS is out there. There are people for Java, there are people for printing, core graphics, sound, QuickTime, every technology area. And I think that's about it.

So, of all the things we've been referencing this afternoon, there's obviously the disk image that's been showing up for every talk this week. There's the Java reference library off of the reference library home. There's a great document on general Java 1.4 development for Mac OS X, which talks about cross-platform issues as well as things you can do to enhance your Mac look and feel. And there's the tech note that was cited earlier, number 2110, for identifying Java. You need to do something Mac-specific, the best way to identify Java on Mac OS X, as well as identifying a specific Java release on Mac OS X that has version strings and everything.