ptg 122 Chapter 6 Response Rendering Serving Static Files The easiest way to start responding to URL requests is to place static files inside the project’s /public directory. As the name implies, this is where all publicly accessible resources are located. Static files include HTML markup pages, CSS stylesheets, JavaScript files, images, and anything else that you would place on a plain old web server. Well, this isn’t very exciting, is it? If your users wanted to see static content, they could go read a book. What we want is dynamic con- tent that can react to specific input data and generate a custom response. That’s what this Web 2.0 world is all about anyway, so let’s give our users a truly interactive experience. Do not fret, static files—you still have an important role to serve. Even the richest of Internet applications requires a bootstrap HTML page to get things started, and images, style sheets, and, of course, Javascript to enable the browser as an application platform. Remember, any files located within the public directory are directly accessible by the URL. This means that you must ensure that you secure sensitive data behind an authentication scheme and also not rely on simple page flow to control your application. An example might be an online quiz. After the student answers a question, he is forwarded to the answer page for further discus- sion. If your file and directory conventions are similar to /topic1/question.html and /topic1/ answer.html, you might be surprised how well your students do when taking these tests! There are many ways to prevent such obvious URL hacking, but you must be aware of how files may be accessed inside the public directory. Internationalizing Static Files For performance reasons, support for serving internationalized files is disabled in WebSphere sMash. If you plan on offering pages in multiple languages for your application, you will want to enable this feature. Internationalization (i18n) uses content negotiation to determine the browser’s preferred lan- guage. We’ll discuss content negotiation in more detail in Chapter 7. To enable internationalization support in your application, add the lines shown in Listing 6.1 to your zero.config file. Listing 6.1 Adding i18n Support in zero.config # Set to true to enable internationalization support. /config/fileserver/contentNegotiation=true # Set this variable to override default locale /config/fileserver/defaultLanguage="en" When a request comes in with content negotiation enabled, WebSphere sMash will check the Accept header for preferred languages. It will then attempt to serve up the requested file with the first desired language code appended to the resource. Failing that, the next preferred language is attempted in the same manner. If all the preferred languages are exhausted without a hit, the application’s default language, set in the configuration, is served. Download from www.wowebook.com ptg Internationalizing Static Files 123 An example is in order here to illustrate the point. First, I set the language preferences of my Firefox browser, as shown in Figure 6.1. In the application, I’ve added several files, as shown in Figure 6.2. Now, let’s request a static file from our WebSphere sMash application. We request the /chap6/i18n.html file. Because our preferred language is fr-ca, WebSphere sMash will check for an i18n.html.fr files to server. Because that file is found, it is served back to our browser, as shown in Figure 6.3. Note that WebSphere sMash does not currently support locales, so even though our preferred language setting is fr-ca, only the fr suffix is searched. This same file-naming schema applies to more than HTML files. Any static content can be served up in this manner. Therefore, you can have a custom banner image for each supported lan- guage. A sample banner image filename might be /public/images/banner.png.fr. Figure 6.1 Browser language settings Figure 6.2 Internationalization project files Figure 6.3 Internationalization browser response Download from www.wowebook.com ptg Supporting internationalization is easy within WebSphere sMash for serving static files, but there are a few items to address. First, only static files are supported. You cannot serve php, groovy, or groovy template files using the language suffix syntax. If you want to support i18n within dynamic files, you will have to use an implementation native to that language. Another thing to note is that when enabling internationalization, you cannot have a base version of the i18n files (for example, i18n.html) present, or it will take precedence over the language-specific files. Internationalization can be a powerful addition to any web application, and potentially increase your audience exponentially. WebSphere sMash makes it easy to add a global view of your world. It won’t, however, actually translate all those pages for you! That is an exercise for your friends in other countries. Serving Dynamic Content Serving up dynamic content is performed in a similar way as static files. The key difference is that the contents of the file are processed before rendering. Dynamic files also have the benefit of eas- ily including external fragments of markup or other files into the response. This gives you the ability to create modular designs and to create consistent theme and structure elements into the response. There are two basic types of dynamic file languages currently supported by WebSphere sMash. You can choose to use either the PHP or Groovy language. Native Java may also be used either in conjunction with Groovy or as its own language environment. For this discussion, we’ll treat it as an extension to Groovy. Although it’s certainly possible to use both PHP and Groovy in the same project, it is probably not a good idea. For this reason, let’s discuss each language separately. From a programmatic point of view, writing output to STDOUT will create a response. So whatever language you choose, just output text using either echo or println statements as appro- priate for the language. PHP and Groovy templates treat everything outside of the scriptlet tags as direct output for rendering. PHP Rendering PHP files are identified with a .php suffix. PHP files can either work as a simple scripting envi- ronment or as a properly structured class file. Because PHP is considered an embedded scripting language, you can have standard HTML content within the file itself. Dynamic content is gener- ated with the normal PHP script tags. Listing 6.2 shows a very basic PHP file that echoes the input parameters. It shows how you can seamlessly mix normal HTML markup and PHP logic. Listing 6.2 args.php—Simple php Example <h1>Arguments:</h1> <ul> <?php $arr = zlist("/request/params", false); 124 Chapter 6 Response Rendering Download from www.wowebook.com ptg Groovy Rendering 125 foreach( $arr as $arg) { echo "<li>$arg = " . zget("/request/params/$arg") . "</li>"; } ?> </ul> In this example, we obtain a list of the incoming request parameters and iterate over each one obtaining the value of each in the loop. When we load this file in our browser, passing in a few arguments on the URL, we see those arguments listed on the response page, as shown in Figure 6.4. Groovy Rendering If you choose to use Groovy as your WebSphere sMash functional language, you have a few options for rendering. A normal groovy file is identified by a “.groovy” suffix. It can be structured as a simple script, or as a proper Groovy class file. There is also a Groovy Template file (.gt) that combines normal HTML markup and groovy code. Placing normal “.groovy” script files in the public directory is a valid way to directly expose functionality on your application, but I personally do not like doing this. I can’t provide a hard justification for not doing it, other than it just feels wrong to me to put a pure script in a loca- tion directly accessible via a URL. I would much rather use a groovy template file for direct ren- dering and have inline code, or better yet, make calls to external scripts for my business logic. Again, this is my opinion, and as you will see, using a Groovy template with inline scripting is directly equivalent to a groovy script. I guess it boils down to a matter of personal taste. Let’s try the same example we wrote in PHP using a Groovy script file. In Listing 6.3, we have a normal groovy script that extracts the parameters and lists them in the response. From a rendering perspective, groovy templates are a simple way to mix markup and logic together. Figure 6.4 Argument echo response Download from www.wowebook.com ptg 126 Chapter 6 Response Rendering Listing 6.3 args.groovy—Simple Groovy Script Example println("<h1>Arguments:</h1><ul>") zlist("/request/params", false).each { println("<li>${it} = " + zget("/request/params/$it") + "</li>") } println("</ul>") In Listing 6.4, we show the same code sample but use a groovy template instead. These two samples are semantically identical, and it’s up to you to decide which version best fits your needs. You can s ee t hat t he e xa mp les are v er y s im ilar. Listing 6.4 args.gt—Simple Groovy Template Example <h1>Arguments:</h1> <ul> <% zlist("/request/params", false).each { %> <li>${it} = <%= zget("/request/params/$it") %></li> <% } %> </ul> The output of each of these groovy-based solutions is exactly the same as our PHP sample shown in Figure 6.1. Although these basic examples don’t explore the full capabilities of PHP or Groovy, they’re meant to show that it is easy to produce dynamic output using WebSphere sMash. We have only scratched the surface of how we can render content within WebSphere sMash. So, let’s continue, explore the possibilities, and show how easy it is to create full-featured and modu- lar applications within WebSphere sMash. Serving Default Files All web servers have a concept of default files to be served when the URL ends with a directory instead of a direct file reference. The file is universally known as the index file, and if it is present when a Directory URL is requested, it will be served up. When a directory request is made, Web- Sphere sMash will look for the following files in order—it will render the first one located as a response. Default files for Groovy projects are as follows: 1. index.gt 2. index.groovy 3. index.html Download from www.wowebook.com ptg Directory Browsing 127 Figure 6.5 Default welcome page An interesting anomaly is that if you have the PHP module included in your project, the search order for default files is rearranged somewhat, with the index.php being the most pre- ferred as expected, but the groovy and gt files switch order. Thus, the new order becomes the following: 1. index.php 2. index.groovy 3. index.gt 4. index.html This is really more of an academic exercise, as you should not have multiple index files and worry about which one will be picked up. I can’t think of a valid reason you would ever have mul- tiple index files in a directory, but you never know. So, what happens if you request a directory, and there is not an index file to serve up? By default, WebSphere sMash will return a generic “404 Not Found” error. The exception to the 404 is the top-level directory. WebSphere will display a simple welcome message, as shown in Figure 6.5, to indicate that the application is up and running if you do not provide an index file. For this reason, you should always include a top-level index file for any application. Directory Browsing There are times when you may want to simply show a directory listing instead of getting a 404 error on directories. To enable this feature, add the following lines to your zero.config, as shown in Listing 6.5. Download from www.wowebook.com ptg 128 Chapter 6 Response Rendering Listing 6.5 zero.config—Enable Directory Browsing # Setting this to true enables global directory browsing. # Overridden by an index.* file, or the top level /public directory /config/fileserver/directoryBrowsing = true # Set this to override the default directory listing template # Default is: /app/views/listing.gt (from zero.core) # Hint: Use core's implementation as a guide /config/fileserver/directoryView = "customDirectoryListing.gt" I would typically recommend that you do not enable this feature on a production applica- tion unless you have a valid reason to do so. By allowing users to view and traverse directories, you are making it that much easier for hackers to probe your site for holes or access files that you might not intend for them to see. Conversely, if your application is primarily focused on provid- ing files for users to download, you may want to have a simple way for users to see all the files in a directory. For those directories for which you want to have tighter control, either add an index file or set up access controls for particular trees. Custom Rendering States WebSphere sMash contains several custom renderers that you can apply to your response. These renderers provide a standard mechanism to send back data to a client. There are four defined ren- derers supplied with WebSphere sMash, but you can also define your own to suit your needs. Two renderers are for visual response: View and Error. The other two are for data responses and include JSON and XML formats. We’ll go through each of these and explain how they can assist you in developing your applications. Using Views for Rendering Another facility available to you is the ability to use views for rendering your response. In even a modest application, keeping all your rendering logic stuffed into the public directory becomes clut- tered and redundant. WebSphere sMash provides two virtual directories that help us separate our logic and view concerns. The /app/scripts directory provides a place to store proper classes and scripts for reuse.You can then make calls to these using the invokeScript and invokeMethod calls. For reusable blocks of view logic, you can place static and dynamic rendering files into the /app/views directory and dynamically pull them into your response. This is a great way to include common blocks of output that can be used by multiple pages. The View files can be dynamic scripts, but a well-designed application would strive to limit their functionality to more of a templating language and leave the business logic in the /app/scripts directory. Download from www.wowebook.com ptg Using Views for Rendering 129 To include a View file in Groovy, simply set the request.view to your desired file, relative to the /app/view directory itself, and call render, as shown in Listing 6.6. For a PHP-based applica- tion, the process is basically the same with only a slightly different syntax, as shown in Listing 6.7. Listing 6.6 Groovy View Include Syntax request.view="quiz/theme/header.gt" render() Listing 6.7 PHP View Include Syntax <?php zput("request/view", "quiz/theme/header.php"); render_view() ?> Let’s go through a sample application to illustrate the flow of a typical application that uses scripts and views. In this sample, we have an application that can serve several different quizzes to the user. We want each quiz to have a consistent look and navigation. First, we have our main index.gt file, as shown in Listing 6.8, which contains standard HTML visuals, and also includes several reusable view components. Listing 6.8 index.gt—Quiz Application Home Page <html> <% request.view = "quiz/theme/head.html"; render() %> <body> <table width="100%" cellspacing="0'" cellpadding="0"> <tr><td colspan="2" class="banner"> <% request.view = "quiz/theme/header.html"; render() %> </td></tr> <tr><td class="nav"> <% request.view = "quiz/theme/nav.gt"; render() %> </td> <td class="content"> <! MAIN CONTENT > <h1>Quiz Home page</h1> <h3>Welcome to the ACME Quiz Factory</h3> <h4>To take a quiz, select it from the left navigation links</h4> <! MAIN CONTENT ></td> Download from www.wowebook.com ptg 130 Chapter 6 Response Rendering Figure 6.6 Quiz home page </td> </tr> <tr><td colspan="2" class="banner"> <% request.view = "quiz/theme/footer.html"; render() %> </td></tr> </table> </body> </html> The only other file of interest here is the navigation block (nav.gt), which contains the links to each quiz. This file is shown in Listing 6.9. When we render our home page, shown in Figure 6.6, we see the beginnings of our quiz application. Each quiz in the application will have its own target file that is essentially an exact copy of the index.gt, with the exception of the main content. A graphical representation of this is shown in Figure 6.7. Listing 6.9 /app/views/theme/nav.gt—Navigation View Block <% def links = [ "Home" : "home.gt", "PHP Quiz" : "php.gt", "Groovy Quiz": "groovy.gt", "Dojo Quiz" : "dojo.gt", "sMash Quiz" : "smash.gt" Download from www.wowebook.com ptg Using Views for Rendering 131 Header Footer Header Footer Nav Nav Dynamic Content Dynamic Content Figure 6.7 Basic assembly flow ] links.each() { label, page -> def uri = getRelativeUri( page ) %> <a href="${uri}">${label}</a><br/><hr/> <% } %> You ma y be s eeing t he b eg in ni ngs o f so me anti pa tt erns he re . T he re i s a l ot o f re dund an cy in the boilerplate HTML; it’s difficult to locate the actual content among the HTML, and there is business logic embedded in our view with the list of quizzes. Wouldn’t it be nicer if we extracted out the business logic into a controller and had a theme view that could simply inject the desired content into itself? Let’s move around some pieces and see if we can improve upon our application. In the following example, we are going to define our desired content elements, pass them into our view on the request zone, and have our theme pull them in for us. This will save us from having to repeatedly build up our pages with common code fragments. First, let’s move all of our code directly into a controller script. From a graphical viewpoint, our new design will look like Figure 6.8. Our index script page now looks like Figure 6.8, which does nothing more than invoke our controller, as shown in Listing 6.10. We now have a business controller script called quiz.groovy located in our /app/scripts directory, as shown in Listing 6.11. Download from www.wowebook.com . of the scriptlet tags as direct output for rendering. PHP Rendering PHP files are identified with a .php suffix. PHP files can either work as a simple scripting envi- ronment or as a properly structured. 6.2 shows a very basic PHP file that echoes the input parameters. It shows how you can seamlessly mix normal HTML markup and PHP logic. Listing 6.2 args.php—Simple php Example <h1>Arguments:</h1>. let’s request a static file from our WebSphere sMash application. We request the /chap6/i18n.html file. Because our preferred language is fr-ca, WebSphere sMash will check for an i18n.html.fr