12. The Presentation Tier

SCA does not offer an alternative presentation-tier technology. When it comes to user interfaces, SCA’s mantra is integration. Service tiers built with SCA can be integrated with a variety of client technologies, including Swing and rich-clients built using Adobe Flex, AJAX, and web frameworks, such as Struts and Java Server Faces (JSFs).

Instead of a cursory overview of how SCA integrates with a wide variety of presentation-tier technologies, this chapter focuses on how Java EE web applications are used as front-ends to SCA services. Specifically, we cover how servlets and Java Server Pages (JSPs) access SCA services. With this knowledge, it is possible to integrate SCA services with more sophisticated presentation-tier technologies, including the myriad of web frameworks that exist today.

Web Components

As a component-based technology, it may not be surprising that SCA has the notion of a web component. Web components are Java EE web applications configured as components. What does this mean? In a nutshell, it is the way servlets and JSPs can be wired to SCA services. This brings SCA protocol abstraction benefits to the presentation tier; similar to Java-based components, servlets and JSPs can invoke services without having to resort to low-level, transport-specific APIs.

Web components are like any other SCA component in that they may have references wired to remotable services. Returning to the BigBank loan application from previous chapters, BigBank may decide to offer a consumer-facing web application that offers loans directly to customers. In this case, a Java EE web application will provide the user interface and interact with the LoanService for processing. Listing 12.1 illustrates this scenario.

Listing 12.1 A Web Component Wired to the LoanService

image

Using a web component, implementing a servlet that collects loan application information and submits a request to the LoanService is fairly straightforward. In fact, the servlet resembles a typical Java-based component, as shown in Listing 12.2.

Listing 12.2 A Servlet That Accesses the LoanService

image

In Listing 12.2, take note of the @Reference annotation. As with Java-based components, this instructs the SCA runtime to inject a proxy to a service. When injected, the servlet can invoke the proxy, which may forward the request to a component hosted on a remote runtime. The specific transport used—for example, web services, JMS, or RMI—is conveniently abstracted from the servlet code.

Having seen the essentials of how a web component is implemented, let’s now look in more detail at how one is configured.

Configuring a Web Component

In the preceding example, we implemented a servlet with a single reference to the LoanService. This reference is wired by configuring a web component in a composite. Web components are designated using the implementation.web element. Listing 12.3 presents the BigBank web component.

Listing 12.3 Defining a Web Component

image

As with other component types, when the web component is deployed to a domain, the SCA runtime is responsible for injecting reference proxies—in this case, on the servlet.

Often, more than one servlet in a web component may need to access the same service. In this case, each servlet defines a reference (using the @Reference annotation) with the same name. In the composite, the reference only needs to be configured once: The SCA runtime will inject a reference proxy into each servlet with an @Reference declaration. For example, if the BigBank web component contained two servlets with references to LoanService, the component definition would be the same as in Listing 12.3.

Packaging and Deploying a Web Component

Up to this point, we have not discussed how web components are packaged and deployed to a domain. In Chapter 9, “The Domain,” we detailed how SCA defines a portable packaging format for contributions, namely a ZIP-based archive, but allows for alternative packaging formats. In line with this, web components are packaged as Java EE web archives (WARs). This has several advantages. Most notably, WARs are familiar to most enterprise Java developers. In addition, existing tooling may be used to package web components.

When packaging a web component as a WAR, the composite file that defines the web component must be located in the WEB-INF directory and named web.composite. It is worth noting that in addition to the web component, the composite may define additional components and include other composites. For example, web.composite may configure several Java-based components used by the web application.

In addition to the web.composite file, a WAR-based contribution also must contain an sca-contribution.xml manifest file located in the META-INF directory. As with standard SCA contributions, this manifest file may specify imported contributions, export artifacts, and declare deployable composites. For example, a web component may reference artifacts such as WSDLs or schemas contained in another contribution, in which case it would import that contribution. However, a WAR-based contribution would typically not contain deployable composites other than the one defined in the web.composite file.

One important feature provided by WAR-based contributions is that classes placed in the WEB-INF/classes and jars in the WEB-INF/lib directories are accessible to servlets and JSPs contained in the archive. This is a useful and necessary feature—because Java EE defines this behavior, if SCA did not support it, many web applications would not work when deployed to an SCA runtime.

As we explained in Chapter 9, SCA does not define a standard way to deploy contributions to a domain. A runtime may use a command-line tool, a file directory, a GUI environment, or some other mechanism. However, SCA does define specific behavior for what happens when a composite is deployed to the domain: Components are included as top-level components in the domain composite. Consequently, when web.composite is deployed to a domain, its child components become domain-level components, as illustrated in Figure 12.1.

Figure 12.1 Deploying a web component to the domain

image

In the case of the BigBank web component, its reference is wired to the LoanService offered by the domain-level LoanComponent. This is shown in Figure 12.2.

Figure 12.2 Deploying the BigBank web component

image

Embedding an SCA Domain in a Web Application

In enterprise architectures, SCA domains will commonly span multiple runtimes. For more modest applications, some SCA runtimes such as Fabric3 support the capability to embed a domain entirely within a web application deployed to a servlet container. This enables web components to be conveniently packaged with other services in a single WAR. For more information and examples of embedding an SCA domain in a web application, see the Fabric3 site (www.fabric3.org).

Properties

Web components may also have properties used for configuration. To access a property, a servlet declares a field or setter with the @Property annotation. When the web component is instantiated by the SCA runtime, it injects the property values specified in the web component entry.

Java Server Pages and the SCA Tag Library

SCA defines a JSP tag library for accessing services from JSPs. Tag libraries are the standard way defined by Java EE to add custom behavior to JSPs. The SCA tag library contains the reference tag, which is equivalent to the @Reference annotation for servlets: It declares a reference, its service contract, and a name for the reference. The JSP fragment in Listing 12.4 demonstrates how this is done.

Listing 12.4 Using the SCA JSP Reference Tag

image

In the preceding JSP fragment, the <sca:reference> tag declares the loanService reference, with a service contract as defined by the bigbank.LoanService Java interface. Using the tag has two effects. First, it declares a reference for the web component that is wired in the web.composite file. Assuming this JSP and the servlet from the earlier example both declared the loanService reference, the web.composite file would remain the same as in Listing 12.3. In other words, the web component definition would contain only one <reference> entry. When the web component is deployed to the domain, the SCA runtime will ensure that reference proxies are available to all servlets and JSPs that declare it. The second effect of the JSP <sca:reference> tag is that it makes the reference proxy available in the JSP page context using loanService as the variable name. As seen in Listing 12.4, the reference proxy can be invoked using inline Java.

Generally, using inline Java in JSPs is considered bad practice as it mixes rendering logic (HTML and JavaScript) with application logic. An example that would align more closely with JSP best practices would use other tags to access the reference proxy. Because the reference proxy is made available in the JSP page context, it can be accessed using JSP expressions. For example, assume BigBank has another JSP that displays current rates using RateService. The current rates returned from the service can be iterated and displayed using built-in JSP tags and the JSP expression language, as shown in Listing 12.5.

Listing 12.5 Accessing a Reference Proxy Using JSP Tags

image

To use the reference tag, you need to include the tag library jar in the web component WAR under the WEB-INF/lib directory. SCA runtimes that support web components (for example, Fabric3) make this tag library available as part of the runtime distribution or development kit. After you have obtained the tag library, it must be declared in a JSP using the taglib directive, as shown in Listing 12.6.

Listing 12.6 Using the Taglib Directive with the SCA Tag Library

image

Asynchronous Interactions

At times, it is useful to avoid blocking on a request before returning a response to a browser client. In these situations, servlets can use non-blocking operations on SCA services. Assuming the LoanService.apply(..) operation is marked with the @OneWay annotation and is long-running, the servlet in the example shown in Listing 12.7 will return a response to the client before the service provider has completed processing.

Listing 12.7 A Servlet Invoking a Non-Blocking Operation on an SCA Service

image

Asynchronous invocations can improve scalability because the runtime does not need to hold open client connections while processing is being done. This is particularly the case when operations may require a significant amount of time to complete. The main drawback to using asynchronous invocations in servlets is that error handling becomes more difficult. For example, if an error occurs while processing the loan, the user will not receive immediate feedback because the servlet will have already returned a response to the client. Instead, error handling would need to be done by LoanComponent (that is, the component providing LoanService), with possibly a notification sent to the user via email or some other communications channel.

Although servlets and JSPs may invoke non-blocking operations, they cannot receive callbacks. If a service is bidirectional (that is, it specifies a callback service), it must be accessed from an intermediary service that implements the required callback interface. To understand how this works, let’s return to the CreditService callback example we introduced in Chapter 3, “Service-Based Development Using Java.” The CreditService and CreditServiceCallback interfaces are defined in Listing 12.8.

Listing 12.8 The CreditService and CreditServiceCallback Interfaces

image

Because the CreditService requires the client to provide a callback service, it cannot be invoked from a servlet. Instead, an intermediary service would need to be wired to the servlet, which in turn would have the CreditService wired to it. The intermediary would be responsible for handling the callback. The SCDL for setting this up is provided in Listing 12.9.

Listing 12.9 Bidirectional Wiring with Web Components

image

Accessing Conversation Services

Up to this point, we have discussed how to access non-conversational services from servlets and JSPs. Doing so is fairly straightforward, particularly because client servlets or JSPs do not need to take threading issues into account, even though web components are by nature multithreaded—that is, they may receive more than one simultaneous request. If the SCA service accessed by a servlet or JSP is implemented by a stateless component, the SCA runtime will guarantee that only one web request will have access to it at a time, as illustrated in Figure 12.3.

Figure 12.3 Dispatching multiple requests in a web component to a stateless component

image

In this case, the servlet or JSP and component implementation does not need to take any special care, such as synchronizing field access. When a service is implemented by a composite-scoped component, it is up to it to manage concurrent access (perhaps by not using field variables or synchronizing access to them), as all requests will be dispatched to the same instance (see Figure 12.4).

Figure 12.4 Dispatching multiple requests in a web component to a composite-scoped component

image

When invoking a service provided by a composite-scoped component, the servlet or JSP does not need to regulate concurrent access because the service provider handles it internally in the component implementation.

If a service is conversational, servlets and JSPs will need to take special care with concurrent access. To guard against inadvertently having two or more clients access the same conversational service instance through a servlet or JSP, web components associate references wired to conversational services with the HTTP session. This means that conversational services cannot be injected on a servlet field using the @Reference annotation. For example, assuming that MyConversationalService is marked as @Conversational, the code in Listing 12.10 will result in an error when the contribution containing the web component is installed.

Listing 12.10 Attempting to Illegally Inject a Conversational Service

image

If the preceding code were legal, because servlets handle multiple simultaneous requests, it would result in every client accessing the same instance of the MyConversationalService instance—something that is most likely not intended.

There are two options for accessing conversational services from a servlet. The first is to use the ComponentContext API, as shown in Listing 12.11.

Listing 12.11 Using the ComponentContext API

image

The ComponentContext instance—which is threadsafe—is injected on the servlet using the @Context annotation. When the ComponentContext.getService(..) API is called, passing the expected interface type and reference name, a reference proxy is returned. This proxy will always dispatch invocations to the same instance for the current HTTP session. If two requests associated with different HTTP sessions are received by the servlet, the code in Listing 12.11 will dispatch to two different instances of the MyConversationalService. If, however, two requests associated with the same HTTP session arrive, they will be dispatched to the same instance. Figure 12.5 illustrates this dispatching.

Figure 12.5 Dispatching to conversational services

image

The second option for accessing a conversational service is to use the Servlet HttpSession API. Listing 12.12 shows how this is done.

Listing 12.12 Using the Servlet HttpSession API to Access a Conversational Service

image

As seen in Listing 12.12, the SCA runtime makes reference proxies available from the HTTP session by reference name. Which way is better: using ComponentContext or HttpSession API? Whatever method is chosen is largely a matter of personal preference. The important thing to remember is not to attempt to store reference proxies in member variables, as doing so will expose a conversational instance to all web component clients.

Defining a Component Type

Previously, we mentioned that the SCA runtime will scan the contents of a web component for @Reference annotations and reference JSP tags when it is installed to determine the set of wireable references.

What happens when there are no @Reference annotations or reference tags used in a web component? This could happen if a web component contains servlets that only use the ComponentContext API. In this case, the runtime has no way to determine the set of references for a web component by introspecting its servlets and JSPs.

When this happens, a special file called a web.componentType file must be created and placed in the WEB-INF directory of the WAR. The componentType file is an XML file that defines services, references, and properties for a component implementation. We haven’t mentioned the componentType file previously because it is generally not needed—in Java, annotations can be used instead.

An example of a web.componentType file that defines a single reference is shown in Listing 12.13.

Listing 12.13 A web.componentType File

image

It is possible to use a combination of @Reference annotations, reference JSP tags, and a web.ComponentType file. The SCA runtime will combine all three sources when calculating the wireable references for a web component.

Summary

This chapter has provided an introduction to integrating SCA services with presentation tiers built using Java EE web applications. It has covered using web components to wire from servlets and JSPs to services. With this knowledge, you should have a thorough understanding of the basics to build user interfaces that front SCA services.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset