ColdFusion MX 7 lets you use ColdFusion pages, JavaServer Pages (JSPs), and servlets together in a single application, or as a means to share certain Web pages among applications. This section explores exactly what you can and cannot do with respect to these technologies. You can't freely mix the different types of code in the same code file, but you can do any of the following:
NOTE ColdFusion 5 included <cfservlet> and <cfservletparam> tags for invoking servlets in ColdFusion pages. These tags have been removed (deprecated) from the CFML language. Don't use them when developing pages for ColdFusion MX or later. Understanding Which Variables Can Be SharedThe following variables can be shared effortlessly among ColdFusion pages, JSP pages, and servlets:
The following variables cannot be shared directly, but can be shared by copying their values into the REQUEST scope:
Sharing REQUEST VariablesSharing REQUEST variables among ColdFusion pages, JSP pages, and servlets is easy and straightforward. Here's how it works. All servlets and JSP pages can access an instance of a class called ServletRequest. Within the body of a JSP or servlet, this ServletRequest instance is traditionally referred to as a variable called request. Among other things, the ServletRequest object allows developers to get and set attributes (basically variables) by name using methods called request.getAttribute() and request.setAttribute(). These methods are commonly used to share values between JSP pages and servlets. If a servlet sets a variable called age using request.setAttribute("age",31), then a JSP file participating in the same page request can read that value using request.getAttribute("age"), and vice versa. Simple enough. So, what does this have to do with integrating with ColdFusion? Well, in ColdFusion MX 7, the REQUEST scope is really a set of JSP/servlet-style request attributes in disguise. Whenever you set a variable in the REQUEST scope, ColdFusion MX 7 is really using setAttribute() to set a variable in the J2EE request object, and when you use getAttribute(), you're really getting an attribute from the request object. You can easily prove this to yourself in a ColdFusion page by setting an ordinary REQUEST variable called REQUEST.Age. You can now output the value of the variable using the getAttribute() method of the underlying J2EE response object. In ColdFusion, you get to the underlying response object using GetPageContext().getResponse(), as explained in Table 29.5. Putting all that together, the following snippet displays "Your age is 31," and then "Your age is 32." <!--- Create request variable ---> <cfset REQUEST.Age = 31> <!--- Output the request variable using underlying J2EE response object ---> <P>Your age is <cfoutput>#GetPageContext().getRequest().getAttribute("age")#</cfoutput> <!--- Change the value of the request variable ---> <cfset GetPageContext().getRequest().setAttribute("age", 32)> <!--- Display the variable normally ---> <P>Your age is now <cfoutput>#REQUEST.Age#</cfoutput> If you have any experience with JSP or servlets, you can probably see where this is going. Assuming that it has been included in the same page request using include() or forward() as explained in Table 29.5, a JSP page could output the value of REQUEST.Age like so: <%= request.getAttribute("age") %> Similarly, a servlet could output the value using the following: response.getWriter().print( request.getAttribute("age") ); Either a servlet or a JSP page could change the variable's value like this: request.setAttribute("age", 32); Shared Variables and Case-SensitivityColdFusion's REQUEST scope is not case-sensitive, but J2EE request attributes are. ColdFusion resolves the difference by always setting attributes using lowercase attribute names. That's why age is used instead of Age in getAttribute() in that last code snippet. Because ColdFusion isn't case-sensitive, this is all less of an issue when reading variables in your ColdFusion code. If you use setAttribute() to set a request variable in your JSP or servlet code, ColdFusion can get to the variable using REQUEST.Age or REQUEST.age or REQUEST.AGE, regardless of whether you used Age or age or some other capitalization in your setAttribute() call. In the unlikely event that your JSP or servlet code is actually using setAttribute() to set two separate attributes called age and Age, the CFML REQUEST scope won't be able to discern between them; the one you would actually get at run time isn't defined. In such a situation, you can use GetPageContext().getRequest().getAttribute() in your ColdFusion code as a workaround. TIP Just to avoid confusion, you should consider using all lowercase variable names for any REQUEST variables that you intend to share with JSP pages or servlets. If you do so in your ColdFusion, JSP, and servlet code, you won't have any of these minor case-sensitivity issues to keep in mind. Shared Variables and Data TypesIn addition to being easy and forgiving in terms of case, ColdFusion is easy and forgiving when it comes to data types. Most simple CFML variables (strings and numbers) are stored internally as strings until you use them in some other context, in which case they are "automagically" parsed or converted to the appropriate type for you. This means that Java will receive most variables as strings unless you take specific steps otherwise. For instance, when you create a variable like the following, it's stored internally as a string, even though there aren't any quotation marks around the right side of the statement: <cfset REQUEST.Age = 31> As such, request.getAttribute("age") will return a string in Java Land, which could be a problem if you are trying to refer to the value as an integer. For instance, the following will fail at run time because of a type mismatch between java.lang.String and java.lang.Integer: Integer age = (Integer)request.getAttribute("age"); It's up to you whether you solve this issue on the ColdFusion side or Java side. In most cases, it probably makes the most conceptual sense to solve it on the ColdFusion side using JavaCast() whenever possible. The recommended way out of this particular dilemma, then, would be to cast the value as an int when you set the REQUEST variable, like so: <cfset REQUEST.Age = JavaCast("int", 31)> NOTE I hope this won't confuse the issue, but if a value is already known to be a number on the ColdFusion side, it will be exposed to Java as a Double. For instance, if the REQUEST.Age variable were created as a result of a mathematical computation, or using Val(31) instead of just 31, any Java code expecting the value to be a java.lang.Double would work fine without the need for an explicit JavaCast() in your ColdFusion code. To put it another way, Val() and JavaCast("double") are more or less synonymous in ColdFusion MX 7. Shared Variables and Multifaceted ValuesIf you are using a multifaceted ColdFusion variable such as an array, you should be aware of how it will be received by Java. Table 29.6 summarizes the object types that will be received when Java's getAttribute() method is used to access a value in ColdFusion's REQUEST scope.
A Simple ExampleThe next few code listings show how easy it is to create ColdFusion pages that incorporate logic and output from existing JSP pages or servlets. Listing 29.9 is a ColdFusion page that uses GetPageContext().include() to include output from a JSP page and then a servlet. The JSP page and servlet are both able to refer to the REQUEST.Name variable set by ColdFusion. The servlet also changes the value of the variable, and the change is reflected in ColdFusion and displayed at the bottom of the page (Figure 29.5). Listing 29.9. IntegratingCFML.cfm A ColdFusion Page that Includes a JSP Page and a Servlet Page<!--- Filename: IntegratingCFML.cfm Author: Nate Weiss (NMW) Purpose: Shows how ColdFusion pages, JSP pages, and Servlets can participate in the same page request ---> <html> <head><title>ColdFusion, JSP, and Servlet Integration</title></head> <body> <h2>A Friendly Conversation</h2> <!--- Set a variable in the REQUEST scope. ---> <!--- This variable will be visible to any included JSP and Servlet pages ---> <cfset REQUEST.Name = "Nate"> <!--- Display a simple message, using normal ColdFusion syntax ---> <cfoutput> <b>Hello, #REQUEST.Name#. This is ColdFusion talking.</b><br> You and really I have some issues that we need to work out, don't we?<br> Oh wait, Dr. JSP wants to have a word with you.<br> </cfoutput> <!--- Include a JSP page ---> <cfset GetPageContext().include("IntegratingJSP.jsp")> <!--- Another ColdFusion message ---> <cfoutput> <p><b>Um, hi, this is ColdFusion again.</b><br> What happened, did Dr. JSP forget what she was going to say again? Those JSPs tend to flake out from time to time. I'll pass you over to IntegratingServlet now. A word of warning: he's a bit... stressed out lately. I hope you make it back in one piece...<br> </cfoutput> <!--- Include a Java Servlet ---> <cfset GetPageContext().include("/servlet/IntegratingServlet")> <!--- Show that REQUEST variable can be changed by JSP pages or Servlets ---> <cfoutput> <p><b>Hi, this is ColdFusion once again.</b><br> Well, it's sure been nice talking to you, #REQUEST.Name#.<br> Have a nice afternoon!<br> </cfoutput> </body> </html> Figure 29.5. A ColdFusion page, JSP page, and servlet can all participate in the same page requestListing 29.10 shows the code for the JSP page that is included by the ColdFusion page in Listing 29.9. Note that it is able to use standard JSP-style request.getAttribute() syntax to refer to the value that ColdFusion calls REQUEST.Name. Listing 29.10. IntegratingJSP.jspJSP Page Included by Listing 29.9<%-- Filename: IntegratingJSP.jsp Author: Nate Weiss (NMW) Purpose: Demonstrates variable-sharing between environments --%> <%-- The REQUEST variable that was set in the ColdFusion page --%> <%-- is available here as an attribute of the JSP "request" object --%> <p> <b>Hi there <%= request.getAttribute("name") %>. Dr. JSP here... how ya doing?</b><br> Gosh, this is embarassing, but I completely forgot what I was going to say.<br> I''m going to pass you back to ColdFusion now. Peace out, dude!<br> NOTE ColdFusion MX 7 can process JSP pages, so you're probably already all set to execute this part of the example. If you're not using ColdFusion MX 7's built-in Web server, it's possible that you'll need to add a mapping to your Web server software so it knows to pass requests for .jsp pages to ColdFusion. See your Web server documentation for details. Listing 29.11 shows the Java code for the simple Java servlet that is included by the ColdFusion page from Listing 29.9. Again, the code is able to use standard servlet-style getAttribute() syntax to get the value of the REQUEST.Name variable known to ColdFusion. Similarly, it's able to use setAttribute() to change the value. The servlet could, of course, use setAttribute() to create entirely new variables, which would also become visible to ColdFusion in the REQUEST scope. Listing 29.11. IntegratingServlet.javaJava Servlet Included by Listing 29.9/* Filename: IntegratingServlet.java Author: Nate Weiss (NMW) Purpose: Demonstrates variable-sharing between environments */ import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class IntegratingServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { // Get reference to the servlet's PrintWriter. This object's print() // method is similar conceptually to <cfoutput> or WriteOutput() in CFML PrintWriter out = resp.getWriter(); out.print("<p><b>Well, hellooooo there.</b> "); out.print("<b>This is IntegratingServlet speaking.</b><br>"); out.print("I'm not sure how much you've heard about me, but I am a bit"); out.print(" crazy. In particular, I like to refer to everyone I meet"); out.print(" as if they were teen pop sensation Belinda Foxile. So, "); out.print( req.getAttribute("name") ); out.print(", you don't mind if I call you Belinda, do you? In fact, "); out.print(" I'm going to ask ColdFusion to call you Belinda too, ok?"); // Change the value of the name attribute // (which corresponds to the REQUEST.name variable in ColdFusion) req.setAttribute("name", "Belinda"); } } If you want to test out this servlet example, you need to use javac to compile the Java class into the corresponding IntegratingServlet.class file, and then place it into the appropriate location on your Web server. If you are using the stand-alone version of ColdFusion MX 7, that location is typically the CFusionMX/wwwroot/WEB-INF/classes folder. If you're running ColdFusion under a different J2EE server, the location may be different. If you're using ColdFusion under IIS or some other non-J2EE server, then you may need to install a separate servlet host to see this example in action. |