WO developers have been able to deploy their applications as a WAR bundle in a J2EE container since WO 5.1, and as an independent SSDD (Servlet Single Directory Deployment) bundle since WO 5.2. There is some documentation out there already for preparing your apps for this if you use XCode, but more and more developers are ditching that in favor of the vastly superior (in my opinion) Eclipse/WOLips IDE. For more information on XCode, [start here]. This article is all about how to do things in Eclipse, and then as a bonus, how to create a deploy a project wonder application so that it runs in tomcat. I had a fairly miserable time figuring all of this out, but there's really not that much too it once you have all of the information in one place. Read on...
You really ought to know how to create a regular standalone webobjects application before you dive into this article. It helps if you understand the basic servlet container file structure, and you should also have the container of your choice installed. I'm using Tomcat 5.5.9.
For an example of how this works, we're going to do the most boring little hello world app imaginable from scratch. Don't fret though, you can apply the same set of changes to any existing app and it should work. After getting Hello World working, I applied the changes described here to a fairly complex existing project full of Ajax and project wonder fanciness, and it worked just as expected.
First create your hello world just like you would In this tutorial. I called my project JSPHelloWorld, and all I did after the WOLips wizard finished guiding me through the project was to edit the Main.html component to say HELLO, WORLD! About as boring as it gets, but go ahead and run your application as a WOLips WOApplication run configuration (the beauty of all this, as you'll see, is that you can develop your applications as you normally would, and in the end, you only have to think about the tomcat stuff when you're actually ready to deploy):
There are really just a few steps you need to go through to make a plain WebObjects application deploy on Tomcat from here:
1) Open up the build.xml file for editing. It should be at the project level. If you don't see it, it's probably just hidden. To show it, click the down triangle at the top of the Package Explorer, and select the "Filters" menu:
Uncheck the item labeled build.xml (WOLips). Now you should see it in package explorer.
Note: If you are converting an existing project to deploy in a servlet container, you may have an older version of the WOLips build.xml file (this happened to me when I started playing with things, and it was all kinds of confusing). Lots of work has been done by the community in the last year to bring this up to speed. To get the recent good stuff, you can right click on the build.xml file and choose WOLips Ant Tools->Replace with latest build.xml. Take care to back up your original version somewhere first though, if you've made any modifications, because you will lose those changes.
If you are using the ant editor to edit the file, you will see a nice summary of your targets in the Outline window:
Click on the 'ssdd' target (If you are not in the and editor, you can just scroll down in the file until you see '<target name="ssdd" depends="build.woapp">').
The directions in the comments above the target are fairly self-explanatory, but here is the more verbose rundown:
By default, the target tag for ssdd has an attribute that looks like 'if="$
"'. Just delete that, so that the target will execute next time you do an ant install.
A couple of targets up in the file, you will find the build.woapp target (<target name="build.woapp">). Within that tag, you will find several 'frameworks' tags. By default, these will have an embed="false" attribute. For each of them, change the "false" to "true". This is important because you are bundling a self contained thing to go in your servlet container, so everything you reference needs to be included. embed="true" makes the ant task copy all of the referenced frameworks out of /Library/Frameworks/ and /System/Library/Frameworks and into the folder that will ultimately move to your tomcat 'webapps' directory (by default, this folder will be created within your project, within a folder named 'dist'. More on this later)
At the root level of your project, you need to create a text file and name it LICENSE. Within this file, you are going to paste the contents of your WebObjects license key. For WebObjects 5.3, this can be found in the file at /System/Library/Frameworks/JavaWebObjects.framework/Resources/License.key. More on the whole license key thing [here]. Here's what my project directory looks like after I created the LICENSE file:
Now you need to modify your build path to include the framework that lets your webobjects application behave in the servlet world: JavaWOJSPServlet. It's in /System/Library/Frameworks. If you don't know how to modify your build path, [go read this].
Now open up your build.properties file, which also resides at the root level of your project. If you don't see it, it's probably hidden from view. Open up the Filters window in package explorer (just like you did above to see the build.xml file), and uncheck build.properties (WOLips). Double click the build.properties file to edit it. There will be a line that looks like "webXML = ". Make that line read 'webXML = true' and then save the file.
That's the long and short of it if you don't want to include wonder in your app. All you have to do is do an ant install (right click on your project folder and choose WOLips Ant Tools->Install. A bunch of stuff will be compiled into the proper exploded WAR directory structure in a folder called 'dist' in your project. If you don't see it, it could be hidden. Open up the Filters window in package explorer again and make sure dist (WOLips) is unchecked. If you still don't see it, it could just be that package explorer hasn't picked up on it yet. Right click your project and choose 'Refresh' and it should appear.
Let's have a quick look at what's in 'dist':
There are two top-level folders. The first is the one you will copy into the webapps directory of your tomcat installation. Inside it is the WEB-INF folder containing an auto-generated web.xml file (more on this later), the bundled frameworks (because we set embed="true" in our build.xml), a tld file that you don't really need to know too much about, a lib directory that contains, as far as I can tell, every jar resource that you have installed in /Library/WebObjects/Extensions (does anyone know how to prevent the unnecessary stuff from being copied in?), and your .woa folder, which is an exact copy of the second folder under dist, JSPHelloWorld.woa, in this case.
If this were not a project wonder project (that is, if it's Application and Session classes did not extend ERXApplication and ERXSession), we could copy over the JSPHelloWorld folder from dist into tomcat's webapps folder, restart tomcat, pull up a browser, type in http://localhost:8080/JSPHelloWorld/WebObjects/JSPHelloWorld.woa, and see the same boring hello world page we saw when we ran the application as a standalone WO app. If you really want to verify this, just make your Application and Session classes extend WOApplication and WOSession instead, rebuild the thing, deploy it into tomcat as described above, and have a go.
But SINCE we're trying to incorporate project wonder (and what sensible WebObjects developer tries to live life without project wonder?) we instead get this awesomely helpful message back:
Servlet WOServletAdaptor is currently unavailable
Man, that tells you a lot. Checking the logs (tomcat-root/logs/catalina.out) tells you little more that makes any sense. But I've done the desparate scrounging on Google, so I'll spare you the expense: it's because Project Wonder does a lot of early intialization and patching of terrible WebObjects code, and the process of patching is broken when you run things in a servlet container. When you're running them as a standalone app, you have a static main method in your Application class that calls ERXApplication.main(), which in turn does all that cool pain saving patching. There's a pretty good thread on the whole business here. But the main method does not get called in a servlet container because things just operate differently in this world. So we have to do a few extra things: