In the first article in this series I introduced Shale and explained how it differs from its predecessor, Struts. I explained the conceptual basis of Shale and showed you how to install and set it up in your development environment. I also discussed some of the possible downsides of Shale -- namely that it's a work in progress -- but concluded that, for developers willing to tinker and learn as they go, Shale is an incredibly promising new development framework.
In this article, I begin to put that tinkering-and-learning clause to the test with an in-depth look at the anatomy of a Shale application. I start out by revisiting Shale's so-called starter application (which you'll quickly learn is more of a template) so that you can see exactly what it brings to Web application development. You use the starter application to build your own sample application, which you then use to explore the many files and directories that make up even the most basic Shale application. Along the way, I show you where your JSPs and Java™ classes go and explain how Shale simplifies the process of building highly functional and customized Web applications.
Most of the discussion in this article builds on what you learned in the first article in this series. If you haven't read that article, you should do so now.
As you learned in the last article, the easiest way to begin building a Shale application is by using the Shale starter application as a template and then making changes from there. Because this article is fairly hands-on, the first thing you need to do is start up that starter application now. Learning about the various components in the starter application (via the application directory structure) and how they function together is helpful when it comes to creating your own Shale application later on.
In fact, it's always a good idea to begin your Shale application development projects using the starter app. I walked you through the process of setting up the Shale starter application in my last article, so I'm assuming you've done that groundwork already. You should have copied the Shale starter app into a directory in your development environment called "first-shale." The code in the first-shale directory is your personal starter app, which you'll use to learn all about the Shale application structure.
Assuming you've got your own application (first-shale) copied over from the Shale starter app, take a look at the directory structure of your application. You'll find a ton of files. If you're not sure what each component, file, and directory does, the application can appear a bit overwhelming -- at least at first. Figure 1 shows the directory structure; as you can see, there's quite a lot in the starter app:
Figure 1. The Shale starter application directory structure
I start by unpacking the Shale starter application directory structure.
The first two files in the starter app root directory are build.xml and default.properties. If you've ever used the Ant build environment, then you're familiar with the first file. Basically, build.xml tells Ant what to do. In the case of the Shale starter app, it lets Ant know what files to compile and how to create the WAR distribution and file used by your servlet engine (which I discuss in-depth later in this article).
The default.properties file is a template for specifying the location of several of Shale's dependencies. Yes, that means that you essentially have a template file (default.properties) inside of a template application (the Shale starter app). I won't go into detail about default.properties because I discussed it in the first article of this series (see Resources). Basically, you copy this file to a new file called build.properties, make changes specific to your environment, and then use Ant to build the project. When Ant runs, it uses the locations you specified in build.properties to create the Shale distribution.
Next up you see two empty directories: ext/ and lib/. These are intentionally empty, so don't feel like you've missed something. When you build a Shale Web application and set up the build.properties file, you have to indicate where the Shale framework and your servlet engine should look for dependencies. In fact, you can indicate two types of dependency:
- JAR files that your application needs at both compile time and run time. These files should be a part of the WAR file for your application and will end up in your Web application's WEB-INF/lib/ directory.
- JAR files that your application needs at compile time but not at run time. This usually is the case when your servlet container provides a set of libraries at run time, but you need them in the meantime to compile your app. You shouldn't include such files in your Web application's WAR file because the container provides them at run time.
The build.properties file provides a path to specify run-time dependencies (using the lib.dir property) and compile-time dependencies that shouldn't be in the run-time WAR deployment configuration (using the ext.dir property). If you want, you can just drop your dependencies in the corresponding directories as follows:
- Run-time dependencies in lib/
- Compile-time-only dependencies in ext/
The two empty directories are provided for just this purpose.
LICENSE.TXT, NOTICE.txt, and README.txt are simple documentation files. They detail the conditions under which you can use Shale and the modifications you can make to the framework. They also provide simple instructions for setting up and building a Shale application. These files are worth reading once, but having done that, you can probably ignore them.
The last directory, called src/, should be fairly easy to figure out: it contains the source code for the Shale starter application. This directory doesn't contain a lot of files, but it does hold a ton of subdirectories. As a result, its structure looks more complex than it actually is. Figure 2 shows the complete, expanded structure of the source code directory:
Figure 2. The source code directory structure
Here's a closer look at those subdirectories:
conf/ contains a single file, MANIFEST.MF, which the build process customizes and uses when generating a WAR for your application. You never need to use or modify this file in a typical application development cycle.
java/ actually contains the only class used in the starter application.
org.apache.shale.blank.WelcomeBeanis a simple JavaBean that demonstrates how beans can be used with Shale. More importantly, it indicates where you can put Java files in the starter application. Any Java code you have within the java/ directory is automatically compiled by Ant when you build the starter app. So, if you have your own code to add, you can just drop it into the java/ directory (directory structure and all), and Ant compiles the code and includes it in the build of your application.
test/ and systest/ simply contain tests to make sure the starter app builds and functions correctly. Unless you're working on the Shale framework or the starter application itself, neither is of much concern to you.
- web/ contains the JSPs used in the starter app. You can add any JSPs you want to include in the application to this subdirectory and they'll be added to the build.
It should be pretty obvious that the most interesting components of the Shale starter app are located in the src/ directory. As you develop increasingly complex Shale applications, your src/ directories will get pretty full with your own Java classes and JSPs. So get accustomed to working within the Shale starter application's src/ structure; you'll find it very useful in your own application development.
Once you've got a good handle on the initial directory structure of the starter app, you're ready to dig more deeply into how Shale applications look when they're built. In the last section, you saw where the source code for a Shale application lives. In this section, you learn how that source code is built into a Web application and where all the compiled Java files, JSP pages, and related dependencies go.
In the process, you should get a good idea of how Shale applications are deployed and where you can change standard deployment options. You also find out where to add libraries for additional plug-ins or dependencies you want to use with your Shale code.
You should recall from my discussion in the last article in this series how to build the starter application, but here's a quick review:
- Copy default.properties to a new file and name the new file build.properties.
- Open the build.properties file in the first-shale/ directory and make edits specific to your system.
- Use Ant to build the app by typing
antat a command-line prompt.
I mentioned previously that you can easily add your own JSPs to the src/web/ directory of the Shale starter app. Any JSPs in that directory are then automatically added to the build process. The same is true for Java source files. In the src/ directory, there's a subdirectory called java/. Just drop your Java source files in this directory and they'll be compiled as part of the build process.
If you're not quite convinced of the value of using the Shale starter application, the build process should prove how useful it is. By editing a single file -- build.properties -- you can build your own application with almost no effort. Even when working with Ant (the build system used for the Shale starter app), you have to set up all the directories, dependencies, and rules involved in building a Web application. With the Shale starter application however, you can spend your time writing JSPs and Java classes, drop the files into the right places, type
ant, and you're ready to go.
When it comes to dropping-in your Java class files, as a general rule, you should use a directory structure that matches the package structure of your Java classes. For instance, if your class is called
Song and is in the package
com.nathanson.music, you should place the Song.java file in a directory structure called src/java/com/nathanson/music. This doesn't change how Java compiles the file --
javac simply looks at the
package directive at the top of your Song.java -- but it does give you a nice organizational structure for your code.
Once you run
ant and build your application, you see a new directory called target/. This directory has all the files built from the source code in the src/ directory. In fact, the target/ directory contains an "exploded WAR." WAR files are simply JAR files with a bit of extra configuration information, built in a way that all servlet containers can deploy the application inside. If you took a WAR file and expanded it -- that is, decompressed it -- you'd end up with the directory structure underneath the target/ directory. (I explain how to actually create a WAR in a moment.)
The best way to get to know where Shale application source files go is by looking at the src/ directory of the starter application. Similarly, the best way to understand how a deployed Shale application looks is to check out the target/ directory. First, I explain where Shale puts various files during the build process, and then I show you how it is set up to deploy applications.
As soon as Ant is finished running, open up the new target/ directory that has been created. The contents of that directory should look something like what you see in Figure 3:
Figure 3. The target/ directory
A lot of this looks similar to the structure you saw in the src/ directory shown back in Figure 2. As in the src/ directory, you'll recognize the standard Web application structure, including Java classes and JSP pages. You might notice several additions, though, and that the files have been shuffled around a bit.
Almost everything in target/ is located within a subdirectory called first-shale/. This directory name might be different on your system if you specified a different project path in your build.properties file. Whatever it's called, Listing 1 shows the file used to build the application:
Listing 1. A sample build.properties file
# Basic project information project.copyright=My project, Copyright © 2006 project.name=My First Shale Application project.vendor=IBM DeveloperWorks project.vendor.id=com.ibm.dw # Java package and context path for servlet engine project.package=com.ibm.dw.firstShale project.path=first-shale # Directory for Shale distribution - change this for your system shale.dir=/usr/local/java/shale-framework-20060204 # Directory for all your libraries - change this for your system lib.dir=/usr/local/java/shale-framework-20060204/lib
You could use any name you want as your project path. The Shale build scripts (which use Ant) simply use the name you specify for the directory it creates under target/.
Most of my remaining discussion focuses on the contents of the target/ directory -- but before getting further into that, you should know about the contents of the directory created directly underneath target/. The META-INF/ directory contains only one file, called MANIFEST.MF, which is shown in Listing 2:
Listing 2. The MANIFEST.MF file
Extension-Name: com.ibm.dw.firstShale Specification-Vendor: The Apache Software Foundation Specification-Version: 1.0 Implementation-Vendor-Id: com.ibm.dw Implementation-Vendor: IBM DeveloperWorks Implementation-Version: 0.1
Compare the contents of this file to Listing 1 and the information entered into the build.properties file, and you should immediately see some connections. MANIFEST.MF picks up the package name, project vendor, and project vendor ID from build.properties and inserts them into the contents of this file.
When you use the Shale build process to build a WAR file for deployment into your servlet engine, this manifest file is included as part of the WAR, identifying its contents. If you use any sort of GUI tools to work with your servlet engine, those tools can read the MANIFEST.MF file and let you -- or other administrators -- know what's in the WAR.
In general, you should never manually change MANIFEST.MF; instead, if you need to modify its values, update build.properties and simply rebuild the application. If you were to change MANIFEST.MF on your own -- without changing build.properties -- and then later rebuild the project, all your changes would be lost. By controlling all the contents of target/ with build.properties and the src/ directory, you can ensure that your deployable application is always consistent with the source code you've developed and the information you've authored about that code in build.properties.
If you've programmed any type of Web application -- whether it was using a framework like Struts or just coding JSPs and servlets on your own -- you're familiar with the basic structure of a Web application. You see that same structure underneath the target/first-shale/ directory, where it shouldn't come as a great surprise to see directories like META-INF/ and WEB-INF/.
All the JSP files you included under the src/web/ directory are now placed in the root of the Web application. You see index.jsp, welcome.jsp, and messages.jspf -- three JSP and JSP-related files that were in the src/web/ directory -- directly underneath target/first-shale/.
The root directory (first-shale/) is where all of your JSP files should go; however, if you need to add more JSPs to your application, do not simply drop them into this directory. Instead, place the additional JSPs in src/web/ and then rebuild the application. I've said it before and I'll say it again: One of the most important things you can do in Shale programming (as with any Web programming) is keep your source tree and the deployment tree in sync. As long as you make all your changes in the src/ directory structure, you won't have any problems.
You see your Java classes in the target/first-shale/WEB-INF/classes/ directory structure. This is the standard location for Java classes in any Web application, so it shouldn't be a surprise. You find all the compiled Java .class files in this structure, nested within a directory structure matching the package structure. So the
WelcomeBean class file, which is in the
org.apache.shale.blank package, is in classes/org/apache/shale/blank, in WelcomeBean.class.
In keeping with the separation between source code and binary code, there are no .java files in the classes/ directory structure -- and there shouldn't be! Instead, only compiled Java files exist; like your JSPs, you should place new Java source files in the src/ directory, under the java/ subdirectory, and let the Shale build scripts compile your Java code.
The build script also copies over any property files you have in your src/java/ directory structure; for example, you see Bundle.properties (refer back to Figure 3) in the target/ directory because that file was placed in the src/java/ directory structure. This allows you to place files your Java classes might need alongside your Java source files and know that they'll be available in the application build structure.
The lib/ directory, under target/first-shale/WEB-INF/, contains all the libraries that your application needs to run. As already noted, Shale has a tremendous number of dependencies:
- Java Runtime Environment (JRE) and Java Development Kit (JDK) 1.4 or later (including Java 5.0)
- Java Servlet API 2.4 or greater
- JavaServer Pages (JSP) 2.0 or later
- JavaServer Faces (JSF) 1.1 or later
- JSTL (JSP Standard Tag Library) 1.1 or later
- Jakarta Commons BeanUtils 1.7 or later
- Jakarta Commons Chain 1.0 or later
- Jakarta Commons Digester 1.7 or later
- Apache Logging 1.0.4 or later
- Apache Ant 1.6.3 or later
One of the key features of the Shale starter application is that it takes care of these dependencies for you during the build. I won't delve into what the dependencies do just yet. You'll learn about them as they're used in particular programming tasks or contexts. Do note, however, that the remaining discussion presumes you've used the starter application and that you have all the dependencies in place. If you're trying to build a Shale application truly from scratch -- without using the starter application as a template -- then you need to add all the dependencies yourself. Yet another reason to always start your development process with the Shale starter app!
In your starter app, you find the dependencies in the WEB-INF/lib/ directory, all as JAR files. Again, this is the standard location for JAR files in Web applications, so it shouldn't come as a surprise. You also find the actual Shale libraries -- shale-core.jar -- as well as several Shale add-ins that allow Shale to work with other frameworks like Spring (shale-spring.jar), Clay (shale-core.jar), Tiles (shale-tiles.jar), and Java 5.0 Tiger (shale-tiger.jar). In other words, you already have almost every library you'd ever need to develop Web applications using Shale. That was easy, wasn't it?
Your source code is in the right place and you've built your application. The end result of these two steps is a directory structure (in the target/ directory under your first-shale/ main directory) that contains all the files you need to deploy your application into a servlet engine. Keeping up with all these files and copying entire directories around isn't convenient or secure, however. Fortunately, Shale provides an easier means of deploying your application.
I showed you how to create a WAR file in the last article, but here's a quick review:
- Open your build.xml file and change the "javadoc" task as detailed in the last article.
Once you take these steps, you have yet another new directory, this time called dist/. The contents of this directory are shown in Figure 4:
Figure 4. The Shale starter application after being built
The most notable file here is first-shale-0.1.war, which is named according to the values you supplied in build.properties (shown back in Listing 1). The dist/ directory also contains licensing and readme information about Shale, as well as your source code. This makes it easy to package up the entire dist/ directory as a ZIP file in case you need to take your entire application to another machine, such as another development server or workstation. In many cases, you'll simply be developing your applications on one machine, though, so it's the WAR file you'll be most interested in.
Once you've got your WAR file, actually deploying the application is a piece of cake. Just take the file and drop it into the directory that your servlet engine provides for Web applications. This directory is usually called something like webapps/. A servlet engine then expands the WAR file (which results in the directory structure you've already seen in target/) and deploys the application. At this point, you've got an application ready to use.
In this article, you've taken a tour of the anatomy of a Shale application. You've learned the purpose of every directory -- and almost every file in every directory -- in the context of a Shale application, from building an application to deploying one. You should clearly understand the contents of a Shale Web application's source code directory and the resulting expanded WAR file.
The best thing to do before reading my next article is practice. If you have a Web application that you've been waiting to convert to Shale, go ahead and do it. Start by moving all its JSP and Java files into the Shale directory structure. Just remember that all your JSPs go in src/web/ and all your Java classes are nested into src/java/. Then you can build your application and deploy it.
Granted, playing around with the directories isn't the same thing as actually using Shale components, but you are working with the Shale application infrastructure, which is a big step in the right direction. (Big enough that it's taken an entire article to explain where Shale locates all of its files in source and deployed form.) In the next article, I'll take things a step further, showing you how to write code that interacts with Shale. I'll start with JSPs and then introduce some Shale-related tags that you can use in your JSP pages. Until then, play around with the starter application. Make changes and test them out -- just be sure to keep your source tree in sync with your deployment tree!
- "All Hail Shale: Shale isn't Struts" (Brett McLaughlin, developerWorks, February 2006):
Get started with a whole new take on the Struts framework.
Shale home page: Read the Javadoc and find additional framework information about Shale.
Apache Struts: The "father" of Shale is a well-used and extensible Web development framework in its own right.
The Java technology zone: Hundreds of articles about every aspect of Java programming.
Get products and technologies
Download Shale: Get started developing with Shale.
Apache Tomcat: A great servlet engine that works perfectly with Shale, as well as Struts.
Apache Ant: A Java-based build tool that is used to build Shale applications.
developerWorks blogs: Get involved in the developerWorks community.
Brett McLaughlin has worked in computers since the Logo days. (Remember the little triangle?) In recent years, he's become one of the most well-known authors and programmers in the Java and XML communities. He's worked for Nextel Communications, implementing complex enterprise systems; at Lutris Technologies, actually writing application servers; and most recently at O'Reilly Media, Inc., where he continues to write and edit books that matter. Brett's upcoming book, Head Rush Ajax, brings the award-winning and innovative Head First approach to Ajax, along with bestselling co-authors, Eric and Beth Freeman. His last book, Java 1.5 Tiger: A Developer's Notebook, was the first book available on the newest version of Java technology. And his classic Java and XML remains one of the definitive works on using XML technologies in the Java language.