Powerful browser detection and custom JSP tags with Geronimo Use Geronimo and Jetty to create a browser and OS detection scheme

Skill Level: Intermediate

Daniel Wintschel ([email protected]) Author and developer Freelance

13 Sep 2005

Learn how to take advantage of and Jetty to create a powerful browser and open source detection scheme. In addition to the open source (OS) Geronimo application server, this tutorial shows you how to use freely available JavaScript programs to perform browser and OS detection on the client side.

Section 1. Before you start

This tutorial is for developers who would like to implement some form of a browser detection API into an application. You can take advantage of Geronimo as the Java™ 2 Platform, Enterprise Edition (J2EE) application server (specifically its use of Jetty as a servlet container) as well as some client-side JavaScript. You'll be developing a few separate Java-based components including a servlet filter and two custom JavaServer Pages (JSP) tags. You'll use Apache Ant as a build tool to build the .war file that you'll deploy to Geronimo, so some familiarity with Ant is handy. You should be familiar with the concepts of filters and JSP tag libraries, and feel comfortable reading Java source code.

By the end of this tutorial, you should have an idea of how to develop your own basic servlet filters and JSP tag libraries, and be able to implement a robust browser detection API into a J2EE application with the Apache Geronimo application server.

About this tutorial

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 1 of 26 developerWorks® ibm.com/developerWorks

The content in this tutorial may beg the question, "Why another browser detection tool?" or "Why not use something like BrowserHawk or one of the other available products on the market?" Sometimes it is better to reinvent the wheel when a product doesn't meet your needs or may not integrate cleanly or easily into your application. In addition, many tools, including BrowserHawk, are proprietary, which is not necessarily a bad thing; however, some developers prefer to use more open tools so they can easily adapt them to their specific needs. Geronimo is an excellent example of this. The Apache Software Foundation wanted to provide a completely open source J2EE application server to fulfill a need it felt was not being met within the Java developer community. Its reasoning was not that there weren't any good J2EE application servers around; it was because Apache wanted to build up an open source, certified J2EE server that could be supported by the Java developer community.

The techniques used in this tutorial are relevant not only to browser and OS detection; the same techniques can be used for the detection of which version of Macromedia Flash a client may have installed or which country they're located in. There are some terrific open source JavaScript programs that provide access to this information, and the same technique we're applying today with browser and OS detection can be applied using these other scripts as well.

This tutorial is structured as follows:

• Custom JSP tags -- a refresher provides a brief overview or refresher course about what custom JSP tags and tag libraries are and how to develop them. • JavaScript for browser detection outlines the reasons behind choosing JavaScript for browser detection and the role it plays within our application. • Design strategy gives you an overall understanding of how to design this sample application and of the the final build structure that you'll deploy to Geronimo. • Server-side components details all of the server-side Java components and source code within the sample application and ties together how these components interact with each other. • JSP components and sample usage details the JSP components used within the application and provides examples of how to use the custom tags developed in this application. • Trying it out allows you to compile and build the sample application from source and provides all the commands necessary to deploy the application to Geronimo and test the functionality of the application for yourself.

Prerequisites

Powerful browser detection and custom JSP tags with Geronimo Page 2 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

This tutorial assumes that you have basic knowledge of the Java Servlet API and the Java programming language. Some knowledge of JavaScript won't hurt either.

System requirements

To run the example code in this tutorial, you need to perform the following steps:

1. Download and install the following applications: • Geronimo Milestone 4 or later. • Apache ANT 1.6.5. • J2SE 1.4.2_09.

2. sure that the environment variables outlined in Table 1 are defined in your shell. Table 1. Setting the environmental variables Variable name Required setting GERONIMO_HOME Set to the root folder of your Geronimo installation ANT_HOME Set to the root folder of your Ant installation JAVA_HOME Set to the root folder of your Java installation PROJECT_HOME Set to the root folder of your BrowserDetection application PATH Ensure that ANT_HOME/bin is in your PATH

3. Extract the supplied . file to your preferred location (this will be the project root). The project is laid out as follows: Listing 1. Project layout

/BrowserDetect/ /conf/ ' contains taglib definition /deploy/ ' created by ANT (will contain WAR file) /src/ ' contains Java source code /web/ ' contains JSP, JavaScript and web. /build.xml ' ANT build file

If you are eager to compile and run the application, jump to the Trying it out section.

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 3 of 26 developerWorks® ibm.com/developerWorks

Section 2. Custom JSP tags -- a refresher

This section provides an overview or refresher on what a custom JSP tag is and why you might want to develop your own JSP tags.

Tag libraries: What and why?

Tag libraries and custom JSP tags were introduced into the JSP specification at Version 1.1. In technical terms, the purpose of a custom tag is to create and access programming objects that are used to affect the output stream that is being sent back to the user's browser. Custom tags can also help break your JSP pages down into small components, allowing easier customization of the presentation layer. Some other examples of tasks that a custom tag may perform include flow control, form processing, accessing databases, and sending e-mail. The tag we'll look at relates closest to a tag that performs some type of flow control, displaying one set of data on a browser and another set of data on a different browser.

Geronimo fits into this picture as the J2EE server that runs Jetty. Jetty is the servlet container that performs the execution of the custom tags you write.

Tag libraries: How?

Here's a brief description of the steps involved in creating and deploying a tag library within an application. At the most basic level, you need to write a Java class that extends javax.servlet.jsp.tagext.TagSupport or javax.servlet.jsp.tagext.BodyTagSupport. These classes are part of the standard servlet API and come bundled with Geronimo. Following this, write a Tag Library Definition (TLD) file that describes to the servlet container the name of your custom tags, what attributes they have, and whether those attributes are mandatory. After you've created the necessary Java classes and TLD files, you're ready to bundle the tag with your application and deploy it to your application server.

In this application, the class files and TLD files that make up your tags are bundled within a . (Java ARchive) file. The .jar file is deployed with your application and contained inside the application .war (Web ARchive) file.

Although this is a high-level overview of the process of developing custom tags, later in the tutorial you'll see specific examples outlining Java classes that make up a custom JSP tag. You'll also see the accompanying TLD file and the structure of the Web application that you'll deploy to Geronimo.

Powerful browser detection and custom JSP tags with Geronimo Page 4 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Section 3. JavaScript for browser detection

This section describes why JavaScript was chosen for browser detection and outlines other potential uses for JavaScript-based detection mechanisms.

Why JavaScript?

So why use JavaScript for browser detection instead of the user-agent string that the browser sends to the server with each request? In JavaScript you can detect many additional things that could be useful on the server side, including screen height and width, browser plug-ins that are installed (for example, QuickTime, Flash, Shockwave, and Java Plug-in), and the versions of all the plug-ins. This information can be beneficial (and sometimes necessary) to have access to the server side when preparing to deliver content to a user.

The role of JavaScript in the application

Within the browser detection application, JavaScript plays a simple but important role. The application includes a JSP with some embedded JavaScript that analyzes data about the user's browser and operating system. You'll have the JavaScript assign these values to hidden HTML form fields and submit the form to the server.

The following sections describe the server-side components and how the client-side and server-side pieces fit together.

Section 4. Design strategy

This section describes the overall design strategy for the application. Learn how the application is designed, and learn about the build structure of the application to give you a better idea of how the components work together.

Application design

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 5 of 26 developerWorks® ibm.com/developerWorks

The example browser detection application provides browser detection functionality to the developer, allowing the delivery of dynamic content based on the client's browser. The basic request flow within the application is as follows:

1. User arrives at the Web site. • Use a javax.servlet.Filter implementation to check the user's HttpSession to see if it has detected the browser information. • If yes, then forward the request to the view. • If no, then redirect to a browser detection JSP page.

2. At the browser detection JSP page, execute the necessary JavaScript to determine browser information.

3. Store the detected browser information in hidden form fields, and use JavaScript to automatically post the form data back to the server.

4. The same filter handles the newly submitted browser information, stores it in the user's session, and forwards the user to the page they originally requested.

There are probably 500 different ways to implement this scenario into a Web-based application, so feel free to adapt the example to suit your needs.

Application deployment

Because you want to deploy a Web application to Geronimo, and because the application does not contain any Enterprise JavaBeans (EJB) components, the application is deployed as a .war file. Use Ant to build the .war file using the structure shown in Listing 2.

Listing 2. Directory structure for the .war file

browserdetection.war/ /detect.jsp /index.jsp /index2.jsp /js/browser_detection.js /WEB-INF/web.xml /WEB-INF/lib/browserdetection.jar

The browserdetection.jar file contains server-side components, including custom JSP tags and other Java objects, as well as the TLD file describing the custom tags. It's structured as shown in Listing 3.

Listing 3. Directory structure for the browserdetection.jar file

browserdetection.jar/ /META-INF/taglib.tld net/humandoing/browserdetect/BrowserDetectFilter.class net/humandoing/browserdetect/BrowserInfo.class

Powerful browser detection and custom JSP tags with Geronimo Page 6 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

net/humandoing/browserdetect/BrowserInfoFactory.class net/humandoing/browserdetect/BrowserParentTag.class net/humandoing/browserdetect/BrowserTag.class

By placing the taglib.tld file in this location, Geronimo automatically understands that you want to have these tag library definitions available within the application, so you don't have to define the tag library in the web.xml file.

The next section highlights each of the server-side components, their source code, and how they interact within the application as a whole.

Section 5. Server-side components

Let's examine the server-side components that are used within the application and how they integrate with each other to capture values from the client, transport them to the server, and associate those values with a specific user. Then you'll see how to use these captured values within a JSP page to deliver content based on the user's browser and/or operating system. At a high level, here is a list of the server-side components that exist within the application:

• Bean class (BrowserInfo), a Plain Old Java Object (POJO) that provides information to the caller about the user's browser information. • Factory class (BrowserInfoFactory) that creates and populates BrowserInfo objects based on parameters it extracts from the current executing HttpServletRequest. • Filter class (BrowserDetectFilter), which is responsible for intercepting requests to the application's JSP pages to ensure that you've stored in the user's session an object instance that represents information about the user's browser. • Tag classes that consist of a parent tag (BrowserParentTag) that do nothing except encapsulate one or more child tags (BrowserTag).

Bean class

The code in Listing 4 (which is greatly abridged because all the source code is available in the Download section) is a POJO that is used to store Boolean values about a specific user's browser.

Listing 4. BrowserInfo.java class

package net.humandoing.browserdetect; import javax.servlet.http.HttpSession;

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 7 of 26 developerWorks® ibm.com/developerWorks

/** * A class that represents a given users browser or user-agent * for a given session. */ public class BrowserInfo { private boolean isIE = false; private boolean isIE4 = false; private boolean isIE5 = false; private boolean isIE5x = false; ... public BrowserInfo( boolean IE, boolean IE4, boolean IE5, boolean IE5x, boolean IE5Mac, boolean IE5xWin, boolean IE6, boolean IE7, boolean netscape4, boolean mozilla, boolean konqueror, boolean safari, boolean opera, boolean opera4, boolean opera5, boolean opera6, boolean opera7, String browserName, String browserFullVersion, boolean windows, boolean mac, boolean linux ) { isIE = IE; isIE4 = IE4; isIE5 = IE5; isIE5x = IE5x; ... } /** * Utility method to grab the BrowserInfo object from a users * session, if one exists. */ public static BrowserInfo getBrowserInfoFromSession( HttpSession session ) { if ( session != null ) { BrowserInfo out = (BrowserInfo) session.getAttribute( BrowserDetectFilter.BROWSER_INFO ); return out; } else { return null; } } public boolean isIE() { return isIE; } public boolean isIE4() { return isIE4; } public boolean isIE5() { return isIE5; } public boolean isIE5x() { return isIE5x; } ... public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append( "[Browser Name: " + getBrowserName() + "]\n" ); buffer.append( "[Browser Version: " + getBrowserFullVersion() +

Powerful browser detection and custom JSP tags with Geronimo Page 8 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

"]\n" ); buffer.append( "[Is Linux? " + isLinux + "]\n" ); buffer.append( "[Is Windows? " + isWindows + "]\n" ); buffer.append( "[Is Mac? " + isMac + "]\n" ); buffer.append( "[Is IE? " + isIE + "]\n" ); buffer.append( "[Is Opera? " + isOpera + "]\n" ); buffer.append( "[Is Mozilla? " + isMozilla + "]\n" ); buffer.append( "[Is Netscape4? " + isNetscape4 + "]\n" ); // ... etc. return buffer.toString(); } }

In this listing, a simple bean class stores data about a specific user's browser and operating system. Within the example application, instances of this class are only constructed from the BrowserInfoFactory class and, subsequently, the instance is stored in a user's session for use by the rest of the application.

Factory class

A factory class has the sole purpose of instantiating new objects and returning the new object instance to the caller. In the example application, you use a factory class to create instances of the BrowserInfo class. The BrowserInfoFactory, as shown in Listing 5, extracts information from the currently executing HttpServletRequest and uses these values to construct and return a populated BrowserInfo instance to the caller.

Listing 5. The BrowserInfoFactory.java class

package net.humandoing.browserdetect; import javax.servlet.http.HttpServletRequest; import java.util.Enumeration; /** * This class is strictly a factory class that is responsible for * parsing posted JavaScript variables from a ServletRequest, and * constructing a BrowserInfo object from the resulting extracted * variables. */ public class BrowserInfoFactory {

private static final boolean DEBUG = false; private static final String BROWSER_NAME_PARAM = "brow"; private static final String MOZILLA_BROWSER_NAME_PARAM = "moz_brow"; private static final String BROWSER_VERSION_PARAM = "nu"; private static final String MOZILLA_BROWSER_VERSION_PARAM = "moz_brow_nu_sub"; private static final String IS_IE_PARAM = "ie"; private static final String IS_IE4_PARAM = "ie4"; private static final String IS_IE5_PARAM = "ie5"; private static final String IS_IE5X_PARAM = "ie5x"; ...

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 9 of 26 developerWorks® ibm.com/developerWorks

/** * Private constructor - this is a factory for creating BrowserInfo * instances only. */ private BrowserInfoFactory() { }

/** * Factory method to instantiate and populate a BrowserInfo * instance for a given request. */ public static BrowserInfo createBrowserInfo( HttpServletRequest request ) { if ( DEBUG ) { dumpRequest( request ); } // Check browser family... boolean isIE = Boolean.valueOf( request.getParameter( IS_IE_PARAM ) ) .booleanValue(); boolean isNS4 = Boolean.valueOf( request.getParameter( IS_NS4_PARAM ) ) .booleanValue(); boolean isMozilla = Boolean.valueOf( request.getParameter( IS_MOZILLA_PARAM ) ) .booleanValue(); boolean isOpera = Boolean.valueOf( request.getParameter( IS_OPERA_PARAM ) ) .booleanValue(); //Check specific browser versions... boolean isIE4 = Boolean.valueOf( request.getParameter( IS_IE4_PARAM ) ) .booleanValue(); boolean isIE5 = Boolean.valueOf( request.getParameter( IS_IE5_PARAM ) ) .booleanValue(); boolean isIE5x = Boolean.valueOf( request.getParameter( IS_IE5X_PARAM ) ) .booleanValue(); ... return new BrowserInfo( isIE, isIE4, isIE5, isIE5x, isIE5Mac, isIE5Win, isIE6, isIE7, isNS4, isMozilla, isKonqueror, isSafari, isOpera, isOpera4, isOpera5, isOpera6, isOpera7, browserName, browserFullVersion, isWindows, isMac, isLinux ); } ... }

The BrowserInfoFactory class demonstrates how useful a factory can be for doing work that is tedious, repetitive, and a bit unrefined. For the sake of simplicity, no error handling has been added to this class (such as checking null conditions). But in a real-world scenario, this class would contain more logic. Now we'll move on to one of the most important components in this sample application.

Filter class

Powerful browser detection and custom JSP tags with Geronimo Page 10 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

The code in Listing 6 is a standard and simple implementation of javax.servlet.Filter (with some of the interface methods cut out to save space). This class is configured to intercept all requests made to Geronimo for JSP pages and performs some processing to see if you have already been able to detect and store the current user's browser information in the session.

Listing 6. The BrowserDetectFilter.java class

import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * This filter is configured to capture all .jsp requests and * then checks to see if the session attached to the current * request contains an instance of a BrowserInfo object. If * not, it does some redirecting and captures some browser * information from the client, stores it in their session, and * subsequently redirects them to the page they initially * requested. */ public class BrowserDetectFilter implements Filter { /** * True/false depending on whether or not you want the debug * logging messages to get printed to the console based on * the UBER-simple logging method found below. */ private static final boolean DEBUG = false; /** * String used as a Key for the key-value pairing to store the * BrowserInfo object in the users session. */ public static final String BROWSER_INFO = "__Browser__Info__"; public void init( FilterConfig filterConfig ) throws ServletException { //initialize stuff here... } /** * Perform the appropriate filter action. If there is no browser * info, stop the filter-chain and redirect to a page that will do * some browser detection. */ public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain ) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; HttpSession session = request.getSession(); String requestURI = request.getRequestURI(); if ( session.getAttribute( BROWSER_INFO ) != null ) { //carry on - nothing to see here... filterChain.doFilter( servletRequest, servletResponse );

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 11 of 26 developerWorks® ibm.com/developerWorks

} else if ( requestURI.equals("/browserdetection/BrowserDetect") ) { //we just finished doing the detection and we're getting the //results posted from the JavaScript, do something about it, //and pass the user on to the previous page they requested. BrowserInfo browserInfo = BrowserInfoFactory.createBrowserInfo( request ); session.setAttribute( BROWSER_INFO, browserInfo ); request.getRequestDispatcher( request.getParameter( "requested_page" ) ) .forward( request, response ); } else { //no browser info was found - forward the client to our detection //jsp page for some browser detection action. request.setAttribute( "RequestURI", requestURI.substring( request.getContextPath().length() ) ); request.getRequestDispatcher( "/detect.jsp" ).forward( servletRequest, servletResponse ); } } public void destroy() { //destroy stuff here... } }

Listing 6 is slightly abridged to show only the portions relevant to the browser detection application. In a real-world scenario, you wouldn't have hard-coded strings in this class, and you would do a little more error checking (especially for null conditions). The main action in this listing takes place in the doFilter method. You've retrieved a reference to the user's session object to see if there is an instance of the BrowserInfo object in the session. If the BrowserInfo object exists, then you know that browser detection has already taken place, and you can simply carry on the filter chain. The other two conditions in the if/else statement are indicative of the following scenarios:

1. Browser detection has just finished executing, and now you need to extract the browser information from the current request.

2. There is no browser information at all.

In the first scenario, the request Uniform Resource Identifier (URI) is checked to ensure that it's equal to a certain string ("/browserdetection/BrowserDetect"). This URI is checked because the detect.jsp page (covered next) posts an HTML form to that URI after it has executed the script used for browser detection. So you know (unless a user keyed in that URI manually) that if you get a request to that specific URI, you have some browser information you can parse out of the request. At this point you can also see how the BrowserInfo and BrowserInfoFactory classes fit into this part of the application. In this listing, the BrowserInfoFactory is used to create the BrowserInfo object, and then the filter class inserts the newly created instance into the current user's HttpSession.

Powerful browser detection and custom JSP tags with Geronimo Page 12 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

In the second scenario, you need to get the browser information somehow, so you forward the user to the detect.jsp page. This page contains the HTML and JavaScript responsible for performing the browser detection and posts a form back to the server.

Custom tag classes

The following two listings are the custom JSP tag classes created and used within the browser detection application. The class outlined below in Listing 7 is simply the parent tag class. The only responsibility it has is ensuring that all uses of the BrowserTag class are wrapped within a BrowserParentTag class.

Listing 7. The BrowserParentTag.java class

package net.humandoing.browserdetect; import javax.servlet.jsp.tagext.TagSupport; /** * A parent tag for the BrowserTag (Can have multiple * nested BrowserTag instances). Nothing exciting to * note here. */ public class BrowserParentTag extends TagSupport { public int doStartTag() { return EVAL_BODY_INCLUDE; } public int doEndTag() { return EVAL_PAGE; }

Listing 8 is another important part of the browser detection application being built.

Listing 8. BrowserTag.java class -- section one

package net.humandoing.browserdetect; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; import java.lang.reflect.Method; /** * This tag is used to evaluate a body for a browser version or * combination as required by set tag attributes. * * @author Daniel Wintschel */ public class BrowserTag extends BodyTagSupport { /** * This is the value that the JSP programmer can use when they wish * to have a "default" value to appear if none of the other values * used in the set of BrowserDetect tags evaluates to true. */ private static final String DEFAULT = "default"; /** * The parent tag - nothing exciting here. */

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 13 of 26 developerWorks® ibm.com/developerWorks

private BrowserParentTag parent = null; /** * The attribute we need to check from the BrowserDetect JSP tag. */ private String check; public String getCheck() { return check; } public void setCheck( String check ) { this.check = check; }

Listing 8 shows the first few lines from the BrowserDetectTag. Note that the tag's single attribute is named check, and its value is set in any JSP page that this tag is used. Valid values of the check attribute include any public method names within the BrowserInfo class that return a Boolean value (that is, isIE, isLinux, and so on). An additional valid value for the check attribute is default. This value may be used as a default value if the BrowserInfo instance doesn't exist within the user's session. In our application, the value default doesn't act as a final else or a final default as you would find in a switch statement. However this functionality could be added to the tag without much difficulty, as shown in Listing 9.

Listing 9. BrowserTag.java class -- section two

public int doStartTag() throws JspException { doParentCheck(); BrowserInfo browserInfo = (BrowserInfo) pageContext.getSession() .getAttribute( BrowserDetectFilter.BROWSER_INFO );

This ensures that this BrowserTag is embedded within a BrowserParentTag. If not, an exception is thrown. The next piece of code pulls the BrowserInfo object out of the user's session (if it exists).

The BrowserInfo object

Listing 10 contains the portion of the implementation that writes data back to the client's browser based on whether or not certain expressions evaluate to true. Here you can see if the BrowserInfo object exists or not; if it doesn't exist, and the user has specified default as the check value, write the data nested in this JSP tag to the output stream. If, however, you do have the BrowserInfo object, things are slightly more interesting. In this case, use reflection to get a reference to the method name in the BrowserInfo class that corresponds to the value of the check attribute, and execute that method against the BrowserInfo object. If the value returned is true, then it writes the content within that tag to the output stream. If the value is false, the content is ignored. Let's take a look at the code.

Listing 10. BrowserTag.java class -- section three

if ( browserInfo == null && check != null

Powerful browser detection and custom JSP tags with Geronimo Page 14 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

&& check.equals( DEFAULT ) ) { return EVAL_BODY_INCLUDE; } else { try { Method method = browserInfo.getClass().getMethod( check, null ); Object result = method.invoke( browserInfo, null ); if ( result != null && result instanceof Boolean ) { Boolean evaluate = (Boolean) result; if ( evaluate.booleanValue() ) { return EVAL_BODY_INCLUDE; } else { return SKIP_BODY; } } else { throw new JspException( "You have chosen a value for the 'check' " + "attribute that does not correspond to an " + "available attribute in the BrowserInfo class" ); } } catch ( NoSuchMethodException e ) { throw new JspException( "You have chosen a value for the 'check' attribute " + "that does not correspond to an available " + "attribute in the BrowserInfo class" ); } catch ( Exception e ) { e.printStackTrace(); throw new JspException( "Something bad definitely happened... Try some " + "better exception handling next time." ); } }

The code in Listing 10 decides whether the data embedded in the JSP page in the body of the BrowserTag is either written back to the user or discarded until a user with the appropriate browser comes along. The final variables that you reference in the tag are entitled EVAL_BODY_INCLUDE and SKIP_BODY. These constant variables are declared in the superclass javax.servlet.jsp.tagext.BodyTagSupport. EVAL_BODY_INCLUDE means to write the contents contained in the body of this tag back to the output stream, while SKIP_BODY means to skip the contents in the body of this tag.

Section 6. JSP components and sample usage

This section briefly outlines the JSP components within the application and provides two examples of sample usage of the custom tags you've developed.

Detection JSP -- JavaScript

The only real JSP component to worry about is the detect.jsp page. The other JSP components are just simple examples of how to use the BrowserTag. The detect.jsp page is the page that the BrowserDetectFilter forwards to when there is no BrowserInfo object associated with the current user's session.

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 15 of 26 developerWorks® ibm.com/developerWorks

Listing 11. The detect.jsp page

<% String originallyRequestedPage = (String) request.getAttribute( "RequestURI"); %> Detecting Browser Information...

... // more hidden form field...... // omitted for the sake of brevity...

Powerful browser detection and custom JSP tags with Geronimo Page 16 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Listing 11 contains HTML, JavaScript, and Java snippets that can be found in detect.jsp. The page executes line by line and:

1. Prints out an HTML form with hidden form fields.

2. Declares JavaScript variables.

3. Uses the functions and abilities given by JavaScript to assign values to the declared variables that are indicative of the browser name, browser version, and operating system with which the user is making this request.

4. Assigns the detected values to the hidden form field elements.

5. Submits the HTML form back to the server automatically.

The action of the HTML form is BrowserDetect, and given the application context, it translates into "/browserdetection/BrowserDetect". This works in the example application because there are no subdirectories within its context.

Sample usage

Listing 12 and Listing 13 show simple JSP pages that act as the entry point to the application and examples of how to use the custom JSP tags created in this tutorial.

Listing 12. The index.jsp page

<%@ taglib uri="/WEB-INF/lib/browserdetection.jar" prefix="bd" %> Browser Detection Test This is a basic server-side check of the browser using session-persisted values that were previously determined from an open-source JavaScript.

Look Ma!!! I'm Internet Explorer... Woof! Look Ma!!! I'm some kinda Mozilla Browser... Yum!

Let's see what else: Check OS

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 17 of 26 developerWorks® ibm.com/developerWorks

Listing 12 is the entry page -- or index page -- of the application. This is a simple example of your final BrowserTag in action. If the user's browser is Microsoft® Internet Explorer, then the application prints Look Ma!!! I'm Internet Explorer... Woof!. If the browser is Mozilla, then Look Ma!!! I'm some kinda Mozilla Browser... Yum! prints. It's worth noting again that the example application does not provide an else function. For example, if the user is not using Internet Explorer or Mozilla, then no output is displayed. To achieve this, you need to add a little more functionality to the BrowserTag.

Listing 13 is similar to index.jsp, but demonstrates how to achieve operating system-specific content as opposed to browser-specific content.

Listing 13. The index2.jsp page

<%@ taglib uri="/WEB-INF/lib/browserdetection.jar" prefix="bd" %> Browser Detection Test This is a server-side check of the operating system using session-persisted values that were previously determined from an open-source JavaScript.

I'm running on Windows Linux is us, and we're you're friend Mac - what else can we say? Yum!

Section 7. Trying it out

Now you're ready to build and run the example application.

Building and running the application

To build the application, make sure you've downloaded and installed the appropriate applications and set the appropriate environment variables, as detailed in the Prerequisites section. Open a shell, and execute the following commands:

Powerful browser detection and custom JSP tags with Geronimo Page 18 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

% cd %PROJECT_HOME% % ant build-deployment-war

The above command runs the Ant build file (included in the attached resources as build.xml) and executes the build-deployment-war target. This compiles all the source code from the tutorial and bundles it into the .jar and .war files in the appropriate format as covered in the Application deployment section.

The following command starts Geronimo, the application server.

% java -jar "%GERONIMO_HOME%\bin\server.jar"

The following command deploys the browser detection application to make it accessible for use.

% java -jar "%GERONIMO_HOME%\bin\deployer.jar" deploy "%PROJECT_HOME%\deploy\browserdetection.war"

After you type the last command, you're prompted for a user name and password to be able to deploy the application to Geronimo. Enter the default user name is system and the default password manager.

Reference environment variables as %ENV_VAR% on and as $ENV_VAR on Linux®, , and Mac OS X.

Provided you have executed the above steps successfully, you should now be able to open a browser up and test the application at the following URL:

http://localhost:8080/browserdetection/index.jsp

This example only works with Internet Explorer- and Mozilla-based browsers, but you can easily extend the code to deal with other browsers, including Safari and Opera. See how the examples in Figure 1 and Figure 2 differ based on the browser used. Figure 2 shows an example of providing the user with operating system-specific content.

Figure 1. Firefox browser accessing index.jsp

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 19 of 26 developerWorks® ibm.com/developerWorks

Figure 2. Firefox browser accessing index2.jsp

Powerful browser detection and custom JSP tags with Geronimo Page 20 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

To test the functionality of the application, try accessing the page using a different browser. See Figure 3 for the result when using Internet Explorer to access the application instead.

Figure 3. Internet Explorer browser accessing index.jsp

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 21 of 26 developerWorks® ibm.com/developerWorks

Section 8. Summary

This tutorial takes advantage of Geronimo's support for servlet filters and custom JSP tag libraries to demonstrate one way in which browser detection can be integrated into a Web-based Java/J2EE application. This manner of integration makes the detected information easily available to Java code executing on the server. In addition, you've implemented a custom JSP tag library that allows JSP developers to provide browser- or operating system-specific content to clients and end users. In no way has this been an exhaustive look at the subject, but simply one of many ways to implement a robust browser detection API into a J2EE application with open source tools, such as the Apache Geronimo application server.

Powerful browser detection and custom JSP tags with Geronimo Page 22 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 23 of 26 developerWorks® ibm.com/developerWorks

Downloads

Description Name Size Download method Source code for the browser detection browserdetect.zip60 KB HTTP application

Information about download methods

Powerful browser detection and custom JSP tags with Geronimo Page 24 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Resources

Learn • Read "JSP taglibs: Better usability by design" (developerWorks, December 2001), covering better leveraging of JSP custom tag libraries. • See "J2EE Pathfinder: Filtering with Java Servlets 2.4" (developerWorks, January 2004) for an introduction to the servlet filter architecture. • Take a guided tour through the Geronimo maze in "Geronimo! Part 1: The J2EE 1.4 engine that could" and its companion article, "Geronimo! Part 2: Tame this J2EE 1.4 bronco" (developerWorks, May 2005). • Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products. • Visit the developerWorks Apache Geronimo project area to access resources for Geronimo developers. • Browse all the free Apache tutorials available in the developerWorks Open source area. Get products and technologies • Visit the official Apache Geronimo site to download the latest release. • Visit the official site for the Apache Ant build tool. • Access a number of browser detection scripts. • Get scripts that detect Flash and QuickTime objects. • Download Gluecode Standard Edition, an open source application server based on Apache Geronimo. • Innovate your next open source development project with IBM trial software, available for download or on DVD. • Learn about the Apache Geronimo support offering, which gives you the technical support you need to confidently develop and deploy your Web and J2EE applications using Apache Geronimo. Discuss • Participate in the discussion forum for this content.

About the author

Daniel Wintschel Daniel Wintschel is a regular guy who derives great excitement from solving business problems, streamlining processes, and writing all sorts of Java code. He loves coffee

Powerful browser detection and custom JSP tags with Geronimo © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 25 of 26 developerWorks® ibm.com/developerWorks

and is currently seeking development opportunities on a telecommuting basis from Singapore. If you are bored one day, you can read more about him.

Powerful browser detection and custom JSP tags with Geronimo Page 26 of 26 © Copyright IBM Corporation 1994, 2008. All rights reserved.