The Internationalization Service


Building applications for use by different countries can add a degree of complexity. Consider, for example, a scenario where you partition your Plants-By-WebSphere application between order processing and inventory management/order fulfillment. Let's say you configure several instances of the order processing applications in different countries (to provide some locality), and drive all these instances against a single central instance of the inventory application (representing your central distribution center).

You will want to process the inventory and order fulfillment in the locale and timezone of the country from which the order is placed. For example, you may want to collate the available item names in a sequence and return it in the customer's language. You may also want to indicate the time of shipment in the timezone and date conventions of the ordering country.

J2EE helps with its support for built-in internationalization, but the support is limited only to servlets on HTTP request and response processing. With this, you can get the locale associated with the HTTP request (allowing you to determine how the client or end user wants to see the information) and set the locale for the response. J2EE does not define any other more comprehensive approach to managing internationalization across J2EE components or the distributed system. More so, the internationalization support described by J2EE will only consider the locale preferences of the end user if the browser (assuming a classic browser-based client) supports and has been configured to define the locale preference of the end user. End users often do not configure this information. WebSphere will compute a default locale if no locale information is provided from the HTTP client using the defined locale of the web container's JVM.

Possibly, you could perform all of the locale-specific processing in your web application – re-sorting the information you get from the inventory system in the locale of the client. However, this could be inefficient. Consider the case where you want to return a partial result – using an iterator to pull the first part of the response from the server and presenting only that subset to the user. Sorting the result at the web application would require obtaining the entire result set from the inventory server before returning the partial result to the end user.

In addition, not all the locale-sensitive information will be used in the response to the user – you may have reasons for filtering it in the intermediate server or using it as part of some other portion of your business logic. In many cases, it would be best to pass the locale information of the client through to the downstream application components.

WebSphere provides an Internationalization Service that will automatically propagate locale information on invocation requests between components. This service gives you control over whether to pass the client's locale, or some other locale set by the intermediate application component. The internationalization context is passed implicitly – freeing you from having to pass the locale information as an explicit argument on method requests. This becomes particularly useful if you incorporate intermediate components that are not designed to pass locale information.

The internationalization service implemented by WebSphere has been submitted to the Java Community Process in JSR 150. It is listed at: http://www.jcp.org/jsr/detail/150.jsp.

About the Internationalization Example

The example used in this section to describe the Internationalization service is composed of four parts:

  • I18Nclient – is a J2EE client application that drives the various paths of this example to demonstrate the use of the internationalization service. Specifically, it calls a variety of operations on the MidTierCMI and MidTierAMI session beans in the server.

  • MidTierCMI – is a session bean deployed in the application server with container-managed internationalization policy.

  • MidTierAMI – is a session bean deployed in the application server with application-managed internationalization policy.

  • FinalTierCMI – is a session bean deployed in the application server that both the MidTierCMI and MidTierAMI beans call to demonstrate how various policies and programming options affect what context is actually received by the final end-point of cascaded requests.

To run the example, you should install the Chapter11Sample application in the application server, and then invoke the client from a command line. At the command prompt:

  • Make sure that <WAS_INSTALL_ROOT>/bin is in your path

  • Invoke the following command:

     launchClient <WAS_INSTALL_ROOT>/installedapps/<nodename>/Chapter11Sample.ear              –CCjar=Chapter11SampleI18NClient.jar 

You will need to substitute <WAS_INSTALL_ROOT> with the path to where you have installed the WebSphere Application Server and <nodename> with the nodename that you specified during installation (usually taken from your host name, by default).

You can import this example into WSAD-IE. To run this example in the WebSphere EE version 5.0 Test Environment server, you will have to enable the Internationalization Service manually in the defaultConfiguration.wsc/cells/localhost/nodes/localhost/servers/server1/server-pme.xml document in the Servers project. You can find this under the Servers perspective. Set the enable attribute of the i18nServer element to true, as highlighted in the screenshot. If necessary, republish your configuration and restart the server:

click to expand

Enabling the Internationalization Service

The internationalization service is provided with the programming model extensions of the Enterprise edition of the WebSphere Application Server. It is disabled by default, but can be enabled through the admin interface. To disable/enable the service, configure the service to begin at server start-up in the Administration console:

click to expand

You will find this panel in the Internationalization Service property-group listed in the server configuration panel of the server on which you want this enabled. You will have to enable this on each individual server that you want to run this service. You will have to restart your application server after enabling this configuration option.

The Internationalization Service Architecture

The internationalization service is premised on the idea that work requests operate within an internationalization context. This context identifies both the locale and the timezone of the caller. We sometimes refer to the context as locale information, but that is just short-hand for the entire context. The context contains both locale and timezone information. Since, in a distributed object system, any given object can be both the receiver of a request, and the source of a request, the internationalization service goes on to make a distinction between the caller context and the invocation context. The caller context may be passed through to the invocation context so that the downstream request is performed under the caller's context, or the intermediate object may change it – your object may place different expectations on the objects that it invokes:

click to expand

The internationalization provides access to the service itself, from which you can get either the caller context or the invocation context.

The service also makes a distinction between Container-Managed Internationalization (CMI) and Application-Managed Internationalization (AMI). You decide which model you want when you deploy your bean, and each bean can select a different model. CMI basically indicates that you expect the container to manage the setting or delegation of internationalization context. AMI indicates that you want to control the setting of context inside your application. You can't have it both ways – if you select CMI an exception will be raised if you attempt to change the context values in your application. This philosophy has been adopted to allow deployers have some control over the behavior your application – they can use CMI to force your bean to make requests with a certain context.

With CMI, the container will set the invocation context according to the policies you set with your bean – either delegating the caller's context through (runAs-caller), using the default context for the application server (runAs-server), or setting it to a specific context that you configure for your bean (runAs-specified). You can set different policies for different methods of your bean (similar to setting runAs and permission security policies for your bean).

The internationalization service is composed of three interfaces:

  • UserInternationalization
    This is the main representative of the internationalization service. This is analogous to the UserTransacation object of the transaction service. You will acquire the UserInternationalization object from JNDI. The UserInternationalization interface supports the following operations:

    • getCallerInternationalization() – returns an Internationalization object representing the context received from the caller (or the default context if no context was received from the client or if your program is the client).

    • getInvocationInternationalization – returns an InvocationInternationalization object representing the context that will be transmitted with any requests from your program.

  • Internationalization
    Represents the readable aspects of the internationalization context. An object with this interface is returned from the UserInternationalization representing the caller's context. The Internationalization interface supports the following operations:

    • getLocales() – returns a list (an array) of java.util.Locales that are included in the context. The context can contain multiple locales, indicating that the client can accept responses encoded for any of the listed locales, with the preferred locales listed first.

    • getLocale() – is like getLocales but only returns the first, preferred locale.

    • getTimeZone() – returns the java.util.TimeZone for the context.

  • InvocationInternationalization
    Represents the settable aspects of the Internationalization context. An object with this interface is returned from the UserInternationalization representing the invocation context. The InvocationInternationalization supports the following operations:

    • setLocales() – can be used to set the list (an array) of java.util.Locales for the context. Multiple locales in the context indicate that any of the specified locales are acceptable to the client, with the preferred locale listed first.

    • setLocale() – is shorthand to indicate that only one locale can be supported for the context.

    • setTimeZone() – this operation is overloaded and can either take a java.util.TimeZone object or a String encoding of the time-zone ID for this context.

The following class-diagram illustrates the relationship between these interfaces:

click to expand

The UserInternationalization object gives you access to the service. From that you can get either the caller context (with the getCallerInternationalization() operation), or the invocation context (with the getInvocationInternationalization() operation). The caller context is represented by the Internationalization object – only allowing you to get information in the context. The invocation context is represented by an InvocationInternationalization object, which extends the Internationalization interface – allowing you to either get or set context information.

Internationalization and Clients

In addition to components (servlets and EJBs) hosted on the application server, the internationalization service also works in full J2EE client containers as well. Thus, you can set the internationalization context that you want to operate within these clients.

Unfortunately, the service does not work in applet clients, nor does it interoperate with other non-WebSphere clients at this point – although, as we stated earlier, the service has been submitted for standardization that should prepare it for such interoperability.

Mapping from HTTP Browsers

J2EE specifies standard support for servlets for obtaining locale information from HTTP requests and setting it in HTTP responses.

The internationalization service can be used in addition to the standard J2EE servlet support for HTTP request and response processing – in essence, to extend the standard J2EE support to enable the propagation and control of internationalization context when communicating with EJBs in your application.

Getting Access to the Internationalization Service

Before you can do anything with the internationalization service in your application, you have to get access to the service itself. This is done by resolving it from the JNDI name space at "java:comp/websphere/UserInternationalization":

 package websphere.pro.chapter11.sample; import com.ibm.websphere.i18n.context.*; import java.util.Locale; import javax.ejb.CreateException; import javax.naming.*; /** * Bean implementation class for Enterprise Bean: MidTierCMI */ public class MidTierCMIBean implements javax.ejb.SessionBean {   private InitialContext jndi = null;   private UserInternationalization i18nService = null;   /**   * ejbCreate   */   public void ejbCreate() throws javax.ejb.CreateException {     try {       jndi = new InitialContext();       i18nService = (UserInternationalization)       jndi.lookup("java:comp/websphere/UserInternationalization");     } catch (NamingException e) {       //The only reason you should ever get this exception is if        //something is wrong with the naming service, or if the        //internationalization service has been disabled by the        //administrator.       System.out.println("Exception looking up " +       "internationlization context: " + e.toString());       e.printStackTrace();     }   } } 

You only have to get access to the service once, so this is usually done in your component's initialization routine. You should then cache a reference to the service and reuse it on any method request to your component. The reference to the service can be shared across different threads of execution, and will always pick up the context from the thread on which the service is called.

Retrieving the Caller's Internationalization Context

The locale and timezone information for the caller is represented in an Internationalization Context that you can obtain from the internationalization service. You can then get the caller's locale(s) and timezone. Callers may supply multiple locales in order of preference. The idea is that, if your server-side application component cannot operate in the first locale specified, then it should operate in one of the other locales – the alternative locales represent the various locales that are acceptable to the caller. If you are not able to operate in any of the locales that are specified, then you run the risk that the caller (or the client user represented by the calling program) will not be able to understand your results. There are no hard rules in this case, but a common convention is to then fail the request rather than return results that cannot be understood.

The internationalization context supports a method for returning an array of locales (the ordered list of locales specified by the client), or just a single locale (the first locale specified in the list). The locale(s) specified by the caller are standard J2SE locales (java.util.Locale).

The internationalization context also supports a method for returning the caller's timezone. This is a standard J2SE timezone (java.util.SimpleTimeZone):

 package websphere.pro.chapter11.sample; import com.ibm.websphere.i18n.context.*; import java.util.Locale; import java.util.SimpleTimeZone; import javax.naming.*; /** * Bean implementation class for Enterprise Bean: FinalTierCMI */ public class FinalTierCMIBean implements javax.ejb.SessionBean {   private InitialContext jndi = null;   private UserInternationalization i18nService = null;   public String getReceivedLocale() {     Internationalization callerI18nCtxt =        i18nService.getCallerInternationalization();     Locale callerPreferredLocale = callerI18nCtxt.getLocale();       SimpleTimeZone callerTimeZone =      (SimpleTimeZone) callerI18nCtxt.getTimeZone();     return callerPreferredLocale.toString();   } } 

There are a number of things you can do knowing the locale and timezone of your caller. The following example demonstrates the use of a NumberFormat object to convert price information to the currency convention of the caller's locale:

 java.text.NumberFormat fmt =       java.text.NumberFormat.getCurrencyInstance(callerPreferedLocale); java.lang.String i18nPrice = fmt.format(itemPrice); 

Setting Downstream (Invocation) Context

If you make calls to other components, the caller's internationalization context will be automatically propagated downstream. However, if you want to have explicit control over the context in the downstream requests, you can create an invocation context and set the locale and timezone information. This context will then become the caller context in the downstream component.

As with the caller's context, you can get an invocation context from the internationalization context. You can set a single locale or a list of locales in preference order. You can also establish the timezone either with the standard J2SE TimeZone, or by timezone identity:

 package websphere.pro.chapter11.sample; import java.util.Locale; import javax.ejb.CreateException; import javax.naming.InitialContext; import javax.naming.NamingException; import com.ibm.websphere.i18n.context.InvocationInternationalization; import com.ibm.websphere.i18n.context.UserInternationalization; /**  * Bean implementation class for Enterprise Bean: MidTierAMI  */ public class MidTierAMIBean implements javax.ejb.SessionBean {   private InitialContext jndi = null;   private UserInternationalization i18nService = null;   public String sendSetLocale() {     try {       InvocationInternationalization invokeI18nCtxt =                i18nService.getInvocationInternationalization();       invokeI18nCtxt.setLocale(Locale.JAPAN);       Object homeObject =                jndi.lookup("java:comp/env/ejb/FinalTierCMI");       FinalTierCMIHome i18nCtxtHome =                (FinalTierCMIHome) javax.rmi.PortableRemoteObject.narrow(       homeObject,FinalTierCMIHome.class);       FinalTierCMI termI18nCtxt = i18nCtxtHome.create();       return termI18nCtxt.getReceivedLocale();     } catch (NamingException e) {       System.out.println("Exception looking up " +                           "internationalization context: "+ e.toString());       e.printStackTrace();     } catch (java.rmi.RemoteException e) {       System.out.println("Remote exception creating " +                          "TerminalI18NContext: " + e.toString());       e.printStackTrace();     } catch (CreateException e) {       System.out.println("Exception creating " +                           "TerminalI18NContext: " + e.toString());       e.printStackTrace();     } catch (IllegalStateException e) {       System.out.println("You can not set I18N locale if the bean " +                           "has been deployed with Container Managed I18N.");       throw e;     }     return null;   } } 

As with the caller's internationalization context, you can also get the locale and timezone of the invocation context. The invocation context is initially set to the values of the caller's context. By separating the caller's context from the invocation context, you can update (or set) the invocation context without affecting the caller's context. Hence, the caller's context cannot be changed.

Modifying the invocation context in your application code is referred to as Application-Managed Internationalization (AMI). The difficulty with managing the internationalization context with AMI is that the invocation policy then becomes hard-coded in the component implementation. If you move that component to another computer, perhaps in another country, you may want to employ a different invocation policy, but will not be able to do so without changing your component implementation.

Container-Managed Internationalization

WebSphere 5.0 introduces support for Container-Managed Internationalization (CMI). Like other similar forms of policy, CMI is a declarative mechanism for setting the invocation policy for internationalization. You can set extended deployment descriptors with your J2EE application that will direct the container on what context to use for downstream requests.

Establishing whether your bean will be application-managed or container-managed is set in with the Application Assembly Tool in the WAS Enterprise extensions of the bean specification:

click to expand

If you have configured your bean to run with CMI, then you can go on to define the internationalization delegation policy – referred to as the "CMI policy" – for each method of your bean.

Valid deployment settings include:

  • runAs-caller – instructs the container to pass the caller's internationalization context through to downstream requests. This is the default behavior for the container, unless overridden by changes encoded in the component implementation.

  • runAs-server – instructs the container to pass the server's default internationalization context through to downstream requests. The locale and timezone for the server, on which the component is hosted, will be used in the invocation context.

  • runAs-specified – instructs the container to pass the specified locale and timezone through to downstream requests. The runAs-specified policy is accompanied with additional descriptors that define the locale (language, optional country code, and optional variant) and timezone identity to use in the invocation context.

The CMI policy can be set differently for each method of the component. By default, unless specified otherwise, the CMI policy will be runAs-caller. You can set the CMI policies using the AAT:

click to expand

The CMI policy will be applied to all business methods. To be clear, on the servlet side, the javax.servlet.Servlet.service() method and the javax.servlet.http.HTTPServlet.doGet(), doPost(), doPut(), doDelete(), doHead(), doOptions(), and doTrace() methods, are all subject to the CMI policy you specify in the deployment descriptor for the servlet. In addition, javax.servlet.Filter.doFilter() and javax.servlet.FilterChain.doFilter() will operate with the deployment policy of the corresponding servlet. With CMI, you do not have to – in fact, you are not expected to do anything in your code. The internationalization locale will be picked up automatically from the servlet request context and propagated to downstream EJBs.

Downstream servlets invoked through the forward() or include() methods of a javax.Servlet.RequestDispatcher are executed under the CMI policy of the calling servlet.

Likewise, any method that you specify in the remote or local interface of an EJB is subject to CMI policy. The CMI policy is applied to both remote and local interfaces in the same manner. The consequence is that, unlike other explicit parameters passed to local methods (which are passed by reference), changing the internationalization context in a local EJB interface will not change the context for the calling servlet or EJB.

In addition, local Java objects called from within a servlet or EJB are executed entirely in the context of the servlet or EJB that called it.

Application-Managed Internationalization

With the introduction of CMI, AMI is no longer the default deployment policy for applications in WebSphere 5.0. If you have written code in your application to explicitly set the internationalization context in a prior release of WebSphere, then you must set the deployment policy for those applications to use AMI when porting them on to the 5.0 runtime. As with CMI, you set the deployment policy for AMI in the AAT:

click to expand

If you deploy a bean with AMI, any runAs policies that you have set for the bean will be ignored.

Internationalization and Lifecycle Methods

Lifecycle methods on servlets and EJBs can be called under a variety of situations that may or may not be in the context of a client request. As such, it may or may not be safe to assume an internationalization context, depending on which method and under what circumstances. The following discussion will detail when you can expect internationalization context to be available for use under different methods.

Servlets

The following servlet lifecycle methods will always be executed under the default locale and timezone of the servlet container:

  • javax.servlet.Servlet.init()

  • javax.servlet.Servlet.destroy()

  • javax.servlet.ServletContextListener.contextInitialized()

  • javax.servlet.ServletContextListener.contextDestroyed()

  • javax.servlet.http.HttpSessionActivationListener.sessionDidActivate()

  • javax.servlet.http.HttpSessionActivationListener.sessionWillPassivate()

No assumptions should be made about the internationalization context of the following lifecycle methods:

  • javax.servlet.ServletContextAttributeListener.attributeAdded()

  • javax.servlet.ServletContextAttributeListener.attributeRemoved()

  • javax.servlet.ServletContextAttributeListener.attributeReplaced()

  • javax.servlet.http.HttpSessionAttributeListener.attributeAdded()

  • javax.servlet.http.HttpSessionAttributeListener.attributeRemoved()

  • javax.servlet.http.HttpSessionAttributeListener.attributeReplaced()

  • javax.servlet.http.HttpSessionBindingListener.valueBound()

  • javax.servlet.http.HttpSessionBindingListener.valueUnBound()

The conditions under which these methods are called are sufficiently ambiguous and varied, that you can never be certain whether they are or are not being called in the context of a client request. Different application servers can further complicate this by driving these methods on different threads.

Stateful Session Beans

For stateful session beans the setSessionContext() and ejbActivate() methods are invoked with the CMI policy of the corresponding Home.create() method.

You can safely assume the CMI policy set for ejbCreate(), afterBegin(), beforeCompletion(), afterCompletion() and of course, any bean methods you introduce as set in the AAT.

You cannot assume anything about the CMI policy for ejbRemove() as this may be invoked at any time by the container.

The ejbPassivate() method will always be invoked with the default internationalization context of the server.

Stateless Session Beans

For stateless session beans, the constructor, and setSessionContext(), ejbCreate(), and ejbRemove() methods are all invoked with the default internationalization context of the server.

CMI policies are only applied to the business methods that you introduce on the EJB interface for stateless session beans – they are not applied to any of the lifecycle methods of your stateless session bean.

Entity Beans

For entity beans, it is unsafe to assume anything about the internationalization context in the constructor, setEntityContext(), and ejbActivate() methods.

The unsetEntityContext() and ejbPassivate() methods are always invoked with the default internationalization context of the server.

For all other methods, including the ones declared on the bean interface, it is safe to assume the CMI policy.

Message-Driven Beans

All methods of message-driven beans (MDB) are invoked under the default internationalization context of the server with the exception of the onMessage() method. The onMessage() method will be invoked with the CMI policy as specified in the deployment descriptors for the MDB, assuming that a context can be propagated with the JMS provider in use.

Web Services Internationalization

To assist in propagating internationalization context for web services, IBM has introduced a proprietary SOAP header for carrying this information. This header is not a standard and therefore, cannot be used for inter-operation with non-WebSphere clients and can only be used between WebSphere clients and servers. Nonetheless, the result is the same as described above for EJB requests. We have chosen to not detail that header here, as it is proprietary and is expected to change as the idea of internationalization propagation is standardized through the various bodies that govern the specifications of web services.




Professional IBM WebSphere 5. 0 Applicationa Server
Professional IBM WebSphere 5. 0 Applicationa Server
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 135

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net