Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 69 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
69
Dung lượng
3,25 MB
Nội dung
<xsl:variable name= "seat ingPlanImage">static/seatingplans /<xs1:value-of select="show/seatingPlanId" />. jpg</xsl:variable> <img src="{$seatingPlan!mage}" /> </body> </html> </xsl : template> The template for the reservation information is pretty straightforward, save for the need to display the description of the PriceBand object, obtained from the root element (highlighted): <xsl:template match="item[@key= 'reservation' ] "> <xsl:value-of select="quoteRequest/seatsReguested" /> seats in <xsl:value-of select=" /reservationlnfo/item[@key='priceband']/description"/> have been reserved for you for <xsl:value-of select="minutesReservationWillBeValid" /> minutes to give you time to complete your purchase. The seat numbers are : XSLT makes light work of iteration over the array of reserved seats: <ul> <xsl:for-each select="seats/item"> <li/><xsl :value-of select="name" /> </xsl:for-each> The total cost of these tickets will be <xsl:value-of select="format:currency(totalPrice, $reqlnfo/language, $reqlnfo/country)" />. This includes a booking fee of <xsl:value-of select=" format : currency (quo teRequest/bookingFee, $reqlnfo/ language, $reqlnfo/country)" />. XSLT conditional syntax is quite like that of JSTL: <xsl:if test="not (seatsAreAdjacent='true')" > <b>Please note that due to lack of availability, some of the seats offered are not adjacent .</b> <form method="GET" action= "payment .html"> <input type="submit" value="Try another date" /> </form> </xsl:if> </xsl:template> Finally, we need a rule to display the <formatted-date> element created by the dateTimeElement() extension function: <xsl:template match= "formatted-date" > <xsl:value-of select="day-of -week" /><xsl:text></xsl:text> <xsl:value-of select="month" /><xsl:text></xsl:text> 560 Brought to you by ownSky Views in the Web Tier <xsl:value-of select="day-of-month"/>, <xsl:value-of select="year"/> at <xsl:value-of select="hours"/>:<xsl:value-of select="minutes"/> <xsl:text> </xsl:text> <xsl:value-of select="am-pm"/> </xsl:template> </xsl:stylesheet> The good news is that if this stylesheet is evaluated successfully, we know that the generated output is well-formed. There's no need to change controller code, and the output rendered to the browser will look exactly as that generated by JSP and Velocity. A user would have no way of telling that XSLT was being used. It is possible to perform XSLT transformations in the client browser, providing both XML document and stylesheet on the server. However, this approach, which has the potential to move processing load from server to client, is problematic in the real world, as not all browsers offer standard or dependable XSLT support. A special View implementation could add support for this in our MVC framework without changing controller or model code. The XSLT stylesheet for our simple view is arguably more complex and harder to understand than the approaches we've seen so far - although it's simple given an understanding of XSLT. It would be hard to justify using XSLT as the view technology for the sample application as its business requirements stand. However, XSLT is a very powerful language, which comes into its own with more complex presentational requirements, which it can often handle with ease. For example, if the welcome page of our sample application needed to display a tree structure of genres, shows and performances (rather than just genres and shows, as at present) and sorting or filtering was required, XSLT would be a very good choice, and the necessary XSLT stylesheet would almost certainly be simpler than a JSP generating the same output. Fortunately we don't need to commit to a "pure" XML approach to enjoy some of the benefits of XSLT. We can embed XPath expressions and XSLT transforms within JSP pages using theJSTL. XSLT and XPath are best used when data already exists in XML form, but it's relatively easy to convert JavaBean models to XML, as in our example. Alternative Approaches to Markup Generation All the approaches we've considered so far are templating solutions, in which a template language renders content made available to it by a Java view adapter. This is not the only valid approach for views. Let's now consider some approaches in which the view is built using java code. In our framework, this means that there will be a distinct implementation of the com.interface21.web.servlet View interface for each page that will actually generate content. 561 Brought to you by ownSky HTML Generation Libraries One approach is to use what I'll refer to as an HTML generation library: a set of Java classes that enables us to construct HTML documents using Java code. In this model, rather than use a view template such as a JSP or Velocity template, we use Java code to construct an HTML document as an object composed of objects representing text, formatting, form fields etc before writing the generated markup to the response. The HTML generation library ensures that the generated markup is well formed, and conceals the complexity of the eventual output. This concept is quite old, and the earliest implementations predate JSP, although none has become very popular. Most generation libraries are HTML-specific. However, some concepts can be shared between different output formats. The iText library, which we'll discuss below, allows some commonality between generating HTML and PDF, for example. The advantages of object generation libraries are: o It's a more object-oriented approach than using JSP pages or a template language. o It is likely to perform well. o It may help to avoid problems such as typos, as complex output generated, rather than coded by developers. o It may support multiple output formats, hiding their details behind an abstraction layer. However, in my experience, this advantage is more theoretical than real, as different output formats don't share enough concepts to make such generalization worthwhile. The disadvantages include: o Who changes the presentation? Is a Java developer required for every change? If Java resources are always required, it will be a serious problem, even if Java developers are freed of the need to handle fine markup details. o Problematic authoring model. How can HTML mockups, which are often produced during design of a new interface, be turned into Java code to generate it? Some solutions, such as XMLC, address this problem. o Many libraries are too tightly bound to HTML. What if we need to generate WML, for example? This will be a fatal problem if the generation library we're using doesn't support WML; it may call for major code changes even if it does. o We are inviting the central problem with HTML - the fact that, unlike, XML, it doesn't cleanly distinguish between content and presentation - right into our Java code. o HTML is a human-readable format. If we need to generate complex formats such as PDF, using a generation library makes sense. In the case of HTML, however, markup interspersed with a few dynamic statements - as in a well-written JSP or a template - will be more readable than Java code that calls a class library. Probably the most highly developed object generation library was BEA's htmlKona. See http://www.weblogic.com/docs51/classdocs/API_html.html for a description of its capabilities. This was a closed-source, proprietary product bundled with WebLogic server. In WebLogic release 6, htmlKona was deprecated, in favor of JSP - an indication that the HTML generation library didn't prove a runaway success. The Jetty servlet engine also includes an HTML generation library that can be used separately. See http://jetty.mortbay.com/jetty/index.htmlttHTML. 562 Brought to you by ownSky Views in the Web Tier Later we'll look at an example of using iText to generate PDF. This illustrates a similar authoring model to HTML generation libraries. I dislike HTML generation libraries and can't think of a reason I would choose to use them. However, their use is compatible with good MVC design, and can be supported by our web application framework like any other view technology. XMLC The only way to address the most serious problems with HTML generation libraries - the need for a Java developer to make any presentational change, and the difficulty in turning an (X)HTML mockup into Java code to generate it - is to automate the generation of Java code to create or manipulate a predefined output format. One technology to achieve this is XMLC. It was originally developed by Lutris as part of the Enhydra application server, but is now in open source. XMLC is a very different approach to view generation to any we've seen so far. XMLC preserves some of the advantages of HTML generation libraries, while almost eliminating the basic problem of creating holding template structure in Java code. XMLC drives the generation approach from the markup. A page designer first creates a mockup site with static HTML. XMLC will "compile" the mocked up HTML pages, resulting in Java source code and/or classes. These classes, "XMLC objects", using the W3C DOM, represent the HTML content in Java, and allow programmatic manipulation of the HTML before it is output. Content from the static mockup can be changed if it is within a tag with an id attribute. For example, a page title can be given an id attribute to allow it to be changed. When larger sections of markup need to be changed, an HTML <span> or <div> tag can be introduced to enclose it (these standard structural tags are defined in the HTML 4.0 specification). The XMLC object, and the HTML it represents, can be manipulated either through the standard DOM interfaces (which allow retrieval and modification of elements) or using convenience methods added by XMLC. Thus Java developers fill in the blanks and add or delete context to the static templates with dynamic content. So long as the blanks don't change, the designers and Java developers can continue to work independently, with revised mockups resulting the generation of new Java objects. The HTML mockups are effectively a contract, defining the dynamic content of the view. Thus at design time the XMLC approach involves the following steps: 1. Create HTML content with placeholders for dynamic data 2. "Compile" the HTML content to XMLC objects (Java classes) with XMLC 3. Write Java code to manipulate the XMLC objects before output At run time the XMLC approach involves the following steps: 1. Construct a new instance of the "XMLC object" for the view in question 2. Manipulate the state of that object, for example by adding elements, deleting elements or setting dynamic element content 563 Brought to you by ownSky 3. Use XMLC to output the object's final state to the HttpServletResponse XMLC offers the following advantages: o A XMLC is good at generating XML, as well as HTML. o XMLC is not tied to the Servlet API. o Prototyping is easy. Templates are pure HTML: they contain nothing to confuse a browser. XMLC allows the designer to insert mockup data, which can be excluded from the compiled class. This means that XMLC templates usually look more complete - when viewed in a browser - than templates using any of the other technologies we've discussed. For example, tables can include multiple rows of mockup data that will be replaced by real data at run time. This is a unique feature, which makes XMLC very attractive in some situations. However, there are two catches: o Output data displayed according to conditional logic is problematic. We can add or remove content from the generated XMLC object, but the content needs to be templated somewhere. The usual solution is to have the markup template include all conditionally output data. Data will be suppressed at run time as the conditions are evaluated. This doesn't pose a technical problem, but it does mean that templates may look nonsensical to designers and business users. o Static includes will not show up at design time unless the templates are served on a web server that understands server side includes. o XMLC will work better than other technologies with the unreadable HTML generated by many popular web authoring tools. However, the designer must be able to assign id attributes to dynamic content, and to create <span> and <div> elements as necessary. XMLC is the only technology we've looked at in which it doesn't matter if the markup is human readable. The disadvantages of XMLC include: o Using the DOM API to manipulate XMLC-generated classes is clumsy. However, XMLC generates additional convenience methods to access elements that go some way towards addressing this problem. o The XMLC model is unusual, and doesn't share many of the concepts shared by other view mechanisms. This may make its introduction difficult in an organization, as it requires the adoption of a model that's likely to be unfamiliar. o The HTML templates maintained by page designers literally hold the keys to the Java code. Any change to them requires regeneration of the associated XMLC object. This is normally no problem, but if careless change deletes or corrupts the ids required by XMLC, the XMLC object will no longer work. So it's not quite magic: some care is needed in maintaining pure-HTML templates. An XMLC Template for Our Example The template is standard HTML, without any XMLC-specific tags. In fact, I started work on it by saving the dynamic output of the Velocity view. The only special requirement is that elements with dynamic content must be given an id attribute, using an enclosing <span> or <div> tag if necessary. Note that the values inserted in template will be visible when the template is viewed in a browser. 564 Brought to you by ownSky Views in the Web Tier The title is given an id, enabling us to append the performance name to its initial content of template text. We could also use a Java.text.MessageFormat here: <html> <head> <title id="title">Seats reserved for </title> </head> With the name, date, and time of the performance we must introduce <span> elements, as there's no markup element we can manipulate like the <title> element in the opening fragment: <body> <b><span id="performanceName">Hamlet</span>: <span id="date">January 1, 1983</span> at <span id="time">7:30 pm</span> Note that the contents of the <span> elements in die template will serve as placeholders, making the template display meaningfully in a browser. We adopt the same approach for the reservation information: <span id="seatsRequested">2</span> seats in <span id="seatType >Seat Type</span> " have been r served e for you for <span id="minutesHeld">5</span> minutes to give you time to complete your purchase. Displaying the list of seat ids involves creating a template list id (the <li> tag can be given an id, so we don't need a <span> or <div> tag to enclose it). Note that I've also added two rows of mockup data, identified with a class of "mockup". These elements will help make the template's appearance in a browser realistic, but can be deleted by XMLC before the generation of the XMLC object: The seat numbers are: <ul> <li id="seat">Zl</li> <li class="mockup">Z2</li> <li class="mockup">Z3</li> Displaying price information simply involves using <span> tags to identify potentially dynamic content. Note that we don't need to change these values: in some cases, we might be happy with the defaults, and only change them occasionally: The total cost of these tickets will be <span id="totalPrice">totalPrice</span>. This includes a booking fee of <span id="bookingFee">bookingFee</span> . As the content displayed if the seats reserved aren't adjacent includes a nested <form> element, we must use a <div> element, rather than a <span> element, to enclose it: <div id ="nonAdjacentWarning" > <b>Please note that due to lack of availability, some of the seats offered are not adjacent.</b> 565 Brought to you by ownSky <form method="GET" action="otherDate.html"> <input type="submit" value="Try another date"> </form> The only remaining dynamic data is the URL of the seating plan image. We give this element an id to allow manipulation, and give it a relative URL that will enable the template to display in a browser: <img alt="Seating plan" id="seatingPlanImg" src=" / /static/seatingplans/1.jpg" /> This certainly separates template from Java code. The best thing about the whole process is that this HTML template looks exactly like the dynamically generated page, unlike any template we've seen. The list of seat names is populated with dummy entries, while other dynamic content has placeholder values. The only snag is the inclusion of the non-adjacent seating warning, which won't appear on most pages (we'll have to remove the unwanted branch programmatically at runtime). The following screenshots displays this template in a browser: 566 Brought to you by ownSky Views in the Web Tier Compiling the Template Before we can write Java code to implement the "Show Reservation" view, we need to generate an XMLC object. We can run the xmlc command shipped with XMLC, but I've chosen to use Ant to make the task repeatable. As only a single HTML file in the sample application is compiled using XMLC, I've hard-coded its name. However, it would be easy to make the Ant target more sophisticated: <target name="xmlc"> <java classname="org.enhydra.xml.xmlc.commands.xmlc.XMLC" fork="yes"> <classpath> <fileset dir="${lib.dir) "> <include name="runtime/xmlc/*.jar"/> </fileset> </classpath> <arg value="-keep"/> <arg value="-nocompile"/> <arg value="-dump"/> <arg value="-ssi"/> <arg line="-sourceout src"/> <arg line="-delete-class mockup"/> <arg line="-class com.wrox.expert j2ee. ticket .web.xmlc.generated.ShowReservationXmlcObject" /> <arg value="war/WEB-INF/xmlc/showReservation.html"/> </java> </target> The most interesting content is in the flags to XMLC: o The -keep flag tells XMLC not to delete the Java source code (it defaults to leaving only a .class file). o The -nocompile flag tells XMLC not to compile the generated source file. We choose to make this part of our build process, rather than the XMLC compilation process. o The -dump flag tells XMLC to display the structure revealed by its analysis of the HTML input. This can be useful if XMLC doesn't generate the convenience setter methods we expect. o The -ssi flag tells XMLC to process server-side includes (it doesn't by default). o The -sourceout flag tells XMLC where to put the generated Java class. We choose to put it in our /src directory, along with our own classes. o The -delete-class flag tells XMLC to delete elements with class mockup. This will delete the dummy list data we included in the template to make it appear more realistic when viewed in a browser. o The -class flag specifies a fully qualified name for the Java class (the default is to generate a class with the same name as the template, in the default package). o The last value is the path to the template. 567 Brought to you by ownSky When this is complete we should have a class called com.wrox.expertj2ee.ticket.web.xmlc.generated.ShowReservationxmlcobject, which is the Java representation of the template HTML. We won't edit this class, but we will use its methods to manipulate its state. If generated XMLC objects are placed along with ordinary source code where an IDE can find them, an IDE should be able to provide context help on their methods, which is likely to prove very useful. Manipulating the XMLC Object Generated from the Template Let's now look at an implementing the com.interface21.web.servlet.View interface for XMLC. In the XMLC object, as with a code generation library, we need a distinct Java object for each view. At runtime the HTML template is no longer required, but we need one view implementation for each XMLC-generated view. We don't need to start from scratch. Our MVC framework provides a convenient superclass for XMLC views - com.interface21.web.servlet.view.xmlc.AbstractXmlcView - which uses the template method design pattern to conceal the necessary plumbing from subclasses and leave them only the task of creating manipulating the relevant XMLC object. Subclasses need to implement only the following protected method: protected abstract XMLObject createXMLObject( Map model, HttpServletRequest request, HttpServletResponse response, XMLCContext context) throws servletException; Like most XMLC view subclasses, the concrete implementation that we use in the sample application doesn't expose any bean properties. Thus the entire bean definition in /WEB- INF/classes/views.properties is as follows: showReservation.class= com.wrox.expertJ2ee.ticket.web.xmlcviews.ShowReservationView See Appendix A for information on installing and configuring XMLC, and a description of the implementation of the com.interface21.web.servlet.view.xmlc.AbstractXmlcView framework class. Now let's move to our specific example, com.wrox.expertj2ee.ticket.web.xmlcviews.ShowReservationView. We begin by extending AbstractXmlcView: public class ShowReservationView extends AbstractXmlcView { There are no bean properties, and don't need to provide a constructor. We implement the required protected abstract method as follows: protected XMLObject createXMLObject( Map model, 568 Brought to you by ownSky Views in the Web Tier HttpServletRequest request, HttpServletResponse response, XMLCContext context) throws ServletException { We begin by constructing a new XMLC object. We can do this with a no-argument constructor, but it's more efficient to use the XMLC context argument to provide an object: ShowReservationXmlcObject showReservationXmlcObject = (ShowReservationXmlcObject) context.getXMLCFactory().create( ShowReservationXmlcObject.class); We now extract our model objects from the map, so we perform type casts once only: Reservation reservation = (Reservation) model, get (TicketController .RESERVATION_KEY) ; Performance performance = (Performance) model.get(TicketControiler.PERFORMANCE_KEY); PriceBand priceBand = (PriceBand) model.get(TicketController.PRICE_BAND_KEY) ; Next we use similar code to that we've seen before to use standard Java internationalization support to format dates and currency amounts, based on the request locale: SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDate!nstance(DateFormat.SHORT, request.getLocale()); df.applyPattern("EEEE MMMM dd, yyyy"); String formattedDate = df.format(performance.getwhen()); df.applyPattern("h:mm a"); String formattedTime = df.format(performance.getwhen()); NumberFormat cf = NumberFormat.getCurrencylnstance(request.getLocale ()); String formattedTotalPrice = cf.format(reservation.getTotalPrice()); String formattedBookingFee = cf.format(reservation.getQuoteRequest().getBookingFee()); Now we can begin modifying dynamic content in the elements with an id attribute. XMLC spares us the ordeal of using DOM to do this, as it generates convenience manipulation methods. Setting dynamic text is very easy: showReservationXmlcObject.setTextTitle( showReservationXmlcObject.getElementTitle()-getText() + " " + performance.getShow() .getNameO ) ; showReservationXmlcObject.setTextPerformanceName( performance.getshow().getName()); showReservationXmlcObject.setText eatsRequested("" + S reservation.getSeats().length); showReservationXmlcObject.setTextSeatType(priceBand.getDescription()); showReservationXmlcObject.setTextMinutesHeldl"" + reservation.getMinutesReservationWillBeValid()); showReservationXmlcObject.setTextDate(formattedDate); showReservationXmlcObject. setTextTime (formattedTime) ; showReservationXmlcObject.setTextTotalPrice(formattedTotalPrice); showReservationXmlcObject.setTextBookingFee(formattedBookingFee); 569 Brought to you by ownSky [...]... required by a J2EE web application o The implementation classes and deployment descriptors of an EJB deployment, which may include multiple EJBs Typically, each of these deployment units will include both standard J2EE and proprietary, application server-specific deployment descriptors WAR and EJB JAR deployment units comprising an application using the entire J2EE stack can be included in a single J2EE deployment... topic of performance tuning and testing, including benchmarks for some of the view technologies discussed in this topic and the issue of HTTP caching 580 Brought to you by ownSky Packaging and Application Deployment In this chapter we'll look at packaging J2EE applications and deploying them onto application servers This is an area in which we require server-specific knowledge, and in which portability... package J2EE applications Deployment Units The two most commonly used deployment units in J2EE applications are Web ARchives (WARs) and EJB JAR files These are JAR-format files that contain: o The implementation classes, binary dependencies, document content (such as JSP pages, static HTML and images) and deployment descriptors of a web application If we don't use EJB, a WAR can contain all code and binaries... views from multiple dynamic and static blocks In JSP, for example, this is done via the include directive and include standard action, while both WebMacro and Velocity provide include directives There are two basic approaches, which I'll term content page inclusion and template page inclusion In content page inclusion, each page of content includes other elements: often, a header and footer In template... application to modify a JSP during development The sample application's Ant build script includes a target to deploy the application as an EAR containing an EJB JAR file, but an expanded WAR This makes it possible to modify JSP pages and other web content, without redeploying the application Understanding J2EE Class Loading Perhaps the toughest issue in packaging J2EE applications relates to class... applications, and especially where we include classes used by both EJB JAR and WAR modules o Portability between application servers Differences between class loading behavior in different application servers can be a real problem for portability, and can mean that an EAR that works on one server may not work in another, even if it is coded within the J2EE specifications Unless we understand how J2EE server... including custom tags and validation infrastructure o o EJB client classes, such as superclasses for business delegates and service locators o i21-e jbimpl jar EJB superclasses and the JNDI bean factory implementation, which is not used by WARs, and so can be loaded by the EJB class loader o i21-jdbc.jar The JDBC abstraction layer and generic data access exception packages discussed in Chapter 9 The classes... identifies theJ2EE modules composing the application In this book we've considered the WAR and EJB JAR file module types, which are used most often in practice It is also possible to include Java application clients and J2EE Connector Architecture JCA) Resource Adapters in an EAR Where collocated applications are concerned, EAR deployment is usually the best option, providing convenient deployment and accurately... specification-compliant and because it provides an easy pre-deployment check for errors The verifier tool reports problems such as missing classes or invalid deploym1 descriptors in a detailed and consistent manner This may provide clearer information on the cause of a deployment failure than the output of some J2EE servers 584 Brought to you by ownSky Packaging and Application Deployment Expanded Deployment... Units Most servers allow deployment units to be deployed in "expanded" or "exploded" form: that is, as a directory structure, rather than an archive in a fixed directory structure Expanded deployment is typically most useful in development; we will want to roll out single deployment units into production The advantages of expanded deployment in development are that it often enables individual files to be . model.get(TicketControiler.PERFORMANCE_KEY); PriceBand priceBand = (PriceBand) model.get(TicketController.PRICE_BAND_KEY) ; Next we use similar code to that we've seen before to use standard Java internationalization. Model.get(TicketController.PERFORMANCE_KEY); PriceBand priceBand = (PriceBand) model.get (TicketController. PRICE_BAND_KEY) ; Next, we use the same code we've seen before to format dates and currency amounts according. follows: showReservation.class= com.wrox.expertJ2ee.ticket.web.xmlcviews.ShowReservationView See Appendix A for information on installing and configuring XMLC, and a description of the implementation