Skip Headers

Oracle9iAS Wireless Developer's Guide
Release 2 (9.0.2)

Part Number A90485-02
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

10
Core Technologies

This chapter discusses how you can use the Oracle9iAS Wireless to develop and deliver mobile services. It explains how to create adapters and transformers, customize your mobile portals at various levels (JavaServer Pages, Portal API, Data Model API, and Runtime API), extend and customize the functional components in the Oracle9iAS Wireless, and work with the XML formats that the Oracle9iAS Wireless uses. Sections include:

Figure 10-1 Core technologies

Text description of feature1.gif follows.

Text description of the illustration feature1.gif

10.1 Oracle9iAS Wireless Components and Process Architecture

10.1.1 Core Platform Architecture

Oracle9iAS Wireless provides a powerful, complete and integrated platform for developing, testing and deploying mobile applications. The Oracle9iAS Wireless core, runtime, tools are built top of proven Oracle technologies including OC4J Container, Distributed Configuration Management (DCM), Enterprise Management Daemon (EMD), XML, Oracle Internet Directory (OID), Single Sign-On Server (), Oracle Process Manager (OPMN), WebCache, and Oracle9i. Oracle9iAS Wireless in-house and community development and testing tools make the mobile application development easier. Oracle9iAS Wireless Server can take mobile applications to be deployed to any mobile network, and accessible from any device through any gateway.

Figure 10-2 Oracle9iAS Wireless Platform Architecture

Text description of 10-1.gif follows.

Text description of the illustration 10-1.gif

As depicted in the above diagram, Oracle9iAS Wireless provides the following wireless development/deployment tool sets:

10.1.2 Core Process Architecture

The following figure (divided into halves for easier viewing) shows how the above Wireless Platform and Tools are deployed physically in terms of processes and relationships with key components of a complete mobile application solution. The wireless-specific components are within the dark-blue rectangle. As the wireless component is an integral part of Oracle9iAS, it seamlessly integrates with other Oracle9iAS components including WebCache, Oracle Http Server, SSO, OID, EM, and Oracle Portal (highlighted with light-blue background color).

Figure 10-3 Oracle9iAS Wireless Process Architecture (part 1)

Text description of 10-2a.gif follows.

Text description of the illustration 10-2a.gif

Figure 10-4 Oracle9iAS Wireless Process Architecture (part 2)

Text description of 10-2b.gif follows.

Text description of the illustration 10-2b.gif

Oracle9iAS Wireless components contribute maximally 7 process groups on any machine on which the wireless component is installed and configured.

10.1.2.1 Key Execution Flows

Oracle9iAS Wireless platform can receive requests from any device via any protocol and deliver content to any device via any protocol. The key request execution flows are:

Http Request Flow--Many devices with certain gateway support can request service through HTTP protocol. These devices include WAP phones with WAP gateways, fixed voice lines with VoiceXML gateways, and others. As illustrated in the above process architecture diagram:

  1. Load Balancer dispatches a request sent from the external gateways to Oracle Http Server. Generally, Load Balancer supports sticky session; this means that the loader balancer will only load-balance these requests from a new session, otherwise the requests of an existing session will be delivered to the same Oracle HTTP Server. Load Balancer provides the hardware load-balancing solution.

  2. Oracle HTTP Server dispatches the received request to OPMN Worker, or to the Wireless Web Server directly (based on the configuration). Requests are routed to OPMN worker (if OC4J-based software load balancing is desired and configured). Otherwise, the request is dispatched to the wireless web server directly.

  3. OPMN worker dispatches the request to the appropriate process based on the process load (if the request is the first one of the current session). Otherwise, the OPMN worker dispatches the request to the wireless web server process to which the request session has been assigned.

  4. The wireless web server processes receive the request. If the response for the request from this particular requesting device is cached by the WebCache, the response is returned immediately. If the request is to access a privileged service, then the wireless web server redirects the request to SSO. Otherwise it proceeds to step b below.

    1. SSO perform the sign-on process via the wireless web server process. After the sign-on succeeds, the original request resumes.

    2. Wireless web server dispatches the original request to the mobile application provider to request the mobile content in mobile XML.

  5. The mobile application provide (which are the external mobile applications) process the request and return the mobile XML to the wireless web server process. Oracle Portal is just another mobile application provider.

  6. Wireless web server adapts the received content to the network and device and returns to the request device.

  7. The mobile content is visible on the requesting mobile device in its most native form.

Async Request Execution Flow--Wireless server can also process requests from non-HTTP based devices, such as SMS device, Pager, Email and etc. Here is the request execution flow:

  1. Messaging Server receives a service invocation request message and dispatches it to the Async Server that runs insides the Wireless Runtime Server process.

  2. Async Server preprocesses the request. The response is returned immediately. If the request is to access a privileged service, the wireless web server will redirect the request to SSO. Otherwise it proceeds to step b below.

    1. SSO performs the sign-on process via the wireless web server process. After the sign-on succeeds, the original request resumes.

    2. Wireless web server dispatches the original request to the mobile application provider to request the mobile content in mobile XML.

  3. Async Server adapts the received response to the requesting device native format and sends the adapted response to Messaging Server.

  4. Messaging Server dispatches the response to the requesting device.

Push Request Execution Flow--Wireless platform can also push any message to any device via different protocols. Out-of-the-box, any message can be pushed out as a SMS message, an email, a voice mail, a fax or to Oracle Mobile Message Gateway. The push request execution flow is as follows:

  1. Push applications including Push Server, Alert Engine, or external applications can compose a message and send the message through calling push APIs.

  2. Messaging Server asynchronously delivers the received message to the delivery provider through the specified protocol.

  3. Messaging Server also asynchronously queries the delivery status (if supported by the provider).

  4. Push applications can either pull the delivery status or be notified.

10.1.2.2 Default Configuration

The default installation configures the installed wireless component to work with the Oracle HTTP Server, WebCache on the local machine. The following mount points are added in the configuration file of the Oracle HTTP Server on the local machine:

If using an Oracle HTTP Server on a different machine (instead of on the local machine), you must manually configure the Oracle HTTP Server. For instructions on configuration, see Oracle9iAS Wireless Getting Started and System Guide.

By default, all the above mounting points are exposed. Comment out these mounting points (so you are not publishing the configuration file from the Oracle HTTP Server).

By default, the Wireless ToolSet and Wireless Runtime Server process groups are configured with single process only. See Oracle9iAS Wireless Getting Started and System Guide to learn how to configure them in load balancing mode.

10.1.2.3 Dependency

Files under ORACLE_HOME/wireless/lib belong to Oracle9iAS Wireless. They are:

Oracle9iAS Wireless depends upon the following jar/zip files included in the Oracle9iAS Wireless common technology stack:

Table 10-1 Oracle9iAS Wireless Dependent Files
Depending jar/zip files Description Location

uix2.jar, share.jar

Uix

ORACLE_HOME/jlib/uix2.jar

ORACLE_HOME/share/share.jar

classes12.zip

JDBC driver

ORACLE_HOME/jdbc/lib

jndi.jar

ORACLE_HOME/jlib

xmlparserv2.jar

Xml parser

ORACLE_HOME/lib

sax2.jar, regexp.jar

ORACLE_HOME/jlib

jai_codec.jar, jai_core.jar, jpeg_codec.jar, ordimimg.jar

sdoapi.jar, sdovis.jar

Advanced imaging

ORACLE_HOME/ord/jlib

OH/lbs/mapviewer/web/WEB-INF/lib/sdoapi.jar

OH/lbs/mapviewer/web/WEB-INF/lib/sdovis.jar

providerutil.jar

LDAP provider

ORACLE_HOME/jlib

mail.jar, activiation.jar, pop3.jar

EMail client

ORACLE_HOME/lib

xschema.jar

ORACLE_HOME/lib

http_client.jar, javax-ssl-1_2.jar, jssl-1_2.jar

http/ssl/https

OH/j2ee/home/lib/javax-ssl-1_2.jar

OH/j2ee/home/lib/jssl-1_2.jar

OH/lib/http_client.jar

dcm.jar, emd.jar, emPID.jar, log4j-core.jar

ORACLE_HOME/lib/libnmuk.so

ORACLE_HOME/bin/nmuk.dll

EM

OH/dcm/lib/dcm.jar

OH/sysman/webapps/emd/WEB-INF/lib/emd.jar

OH/sysman/webapps/emd/WEB-INF/lib/log4-core.jar

$ORACLE_HOME/lib/emPid.jar

ldapjclnt9.jar

OID client

OH/jlib/ldapjclnt9.jar

soap.jar

Soap

OH/soap/lib/soap.jar

repository.jar

Repository api

OH/jlib/repository.jar

ohw.jar

Oracle Help for Web

10.2 Integration with other Components

This section describes Oracle9iAS Wireless integration with Single Sign-On (SSO) and Oracle Internet Directory (OID) server. The IAS v902 SSO is used by all IAS v902 components for user authentication, and OID is the single place for storing all the User related information.

This integration provides:

Users authenticate only once, and can access any SSO partner application. For example, a user authenticated by the Oracle9iAS Wireless server can access any SSO-enabled Partner Application (such as Oracle Portal) without authenticating again.

The following scenarios illustrate interactions between Oracle9iAS Wireless server and the SSO server.

10.2.1 Scenario 1: User Authentication by Oracle9iAS Wireless (device portal)

The Oracle9iAS Wireless server authenticates a user when the user sends an explicit Login Request (identified by URL parameter PAlogin=true), or tries to access a private service.

Figure 10-5 Interactions between Oracle9iAS Wireless and the Login Server

Text description of 10-3.gif follows.

Text description of the illustration 10-3.gif

  1. The user sends a Login Request or accesses a private service.

  2. Oracle9iAS Wireless sends the Login request (without username/ password) to the SSO Server.

  3. The SSO Server checks the SSO cookie. If one is present, the login server identifies the user from the encrypted cookie and sends the SSO redirect form (step 7). This happens if the user is already authenticated by an external partner application (Section 10.2.2, "Scenario 2: User Authentication by an External Application"). If the SSO Cookie is not present, the SSO server sends the mobile xml login form to the Oracle9iAS Wireless server.

  4. Oracle9iAS Wireless transforms the mobile xml login page to the appropriate device markup language and sends the device markup login page (such as WML) to the device browser.

  5. The user enters the username/password and submits the Login Form.

  6. Oracle9iAS Wireless forwards the Login Request (with user credentials) to the SSO Server.

  7. SSO Server authenticates the user. If the authentication is successful, the SSO Server sends the SSO Redirect Form (if unsuccessful, the Login Form is sent [step 3 above]) to Oracle9iAS Wireless.

  8. Oracle9iAS Wireless Server sends the home page of the user (or the private service result) to the device browser.

10.2.2 Scenario 2: User Authentication by an External Application

In Oracle9iAS Wireless-v902, the first request to the device portal (http://Oracle9iAS WirelessServer:port/ptg/rm) returns the home page of the anonymous user (Guest), or the home page of the identified virtual User. From that point, the user can access public services or can do an explicit login to access their private services. The unauthenticated user can execute HTTP Adapter-based public services, which points to an SSO-based partner application (such as Oracle Portal). The partner application may complete the SSO-based user authentication.

Figure 10-6 Interactions Between Oracle9iAS Wireless, Login Server and the External Application

Text description of sso2.gif follows.

Text description of the illustration sso2.gif

  1. An unauthenticated user executes an HTTP adapter-based service pointing to an SSO-based external application.

  2. Oracle9iAS Wireless sends an HTTP request to the external application.

  3. The partner application sends an HTTP Redirect pointing to the SSO Server.

  4. Oracle9iAS Wireless follows the redirected URL.

  5. SSO Server checks the SSO cookie. If one is present, the login server identifies the user from the encrypted cookie and sends the SSO redirect form (step 9 below). This happens if the user is an authenticated user. If the SSO Cookie is not present, the Login Server sends the mobile xml login form to the Oracle9iAS Wireless server.

  6. Oracle9iAS Wireless transforms the mobile xml login page to the appropriate device markup language and sends the device markup login page (such as WML) to the device browser.

  7. The user enters the username/password and submits the Login Form.

  8. Oracle9iAS Wireless forwards the Login Request (with user credentials) to the SSO Server.

  9. SSO Server authenticates the user. If the authentication is successful, SSO Server sends the SSO Redirect Form (if unsuccessful, the Login Form is sent [as in step 5 above]) to Oracle9iAS Wireless. After successful authentication, the Oracle9iAS Wireless session of the user is upgraded.

  10. Oracle9iAS Wireless follows the SSO Redirect form. The redirect form points to the external partner application.

  11. The partner application returns the service content in mobile XML.

  12. Oracle9iAS Wireless transforms the mobile xml content to the appropriate device markup language, and sends the device markup content to the device browser.

10.2.3 Scenario 3: User Authentication by mod_osso

All Web-based Oracle9iAS Wireless applications (such as Customization) will authenticate users using mod_osso, which is a module plugged into Oracle HTTP Server. All of the Web-based Oracle9iAS Wireless applications running behind Oracle HTTP Server are treated as a single partner application. Users can access any of the applications after single sign-on.

The device portal uses the value of the HTTP header OssoUser_Guid to identify the mod_sso authenticated user.


Note:

When executing HTTP Adapter-based services pointing to external partner applications, the mod_sso authenticated user will have to be authenticated again. The reason for this is that for mod_sso authenticated users, the SSO cookies are stored in the PC browser.


10.2.4 Scenario 4: Voice based authentication

Voice authentication is accomplished by Oracle9iAS Wireless (locally) using the account number and the PIN of the user. Note that an authenticated user accessing external SSO partner applications from a voice device must re-authenticate (using username and password).

10.2.5 Global Logout

Oracle9iAS Wireless server participates in the SSO Global Logout. The following steps detail the interactions between Oracle9iAS Wireless, SSO Server and Partner Applications.

10.2.5.1 Scenario 1: Logout from Oracle9iAS Wireless

The user can click Oracle9iAS Wireless Logout to sign off.

  1. The user sends a an Oracle9iAS Wireless Logout request (identified by URL parameter PAlogoff=true).

  2. The Sign Off implementation of Oracle9iAS Wireless sends an HTTP request to the SSO Sign-Off URL.

  3. The SSO server returns the mobile XML global logout page and a special HTTP header (X-Oracle-SSO-logout with value = true). The global logout page contains one image for each partner application that has the user session.

  4. Oracle9iAS Wireless sends HTTP requests to each image link. This is done so that the user's session gets cleaned up in all the partner applications.

  5. Oracle9iAS Wireless terminates the user's session.

  6. If Logout is accomplished through Oracle9iAS Wireless link, then the home page of the "Guest" user is returned.

10.2.5.2 Scenario 2: Logout Link

The authenticated user can click on the logout link on the page returned by the SSO-based partner application. In this case, the logout link will point to the SSO sign-off URL.

  1. The user clicks on the logout link which points to the SSO sign-off URL.

  2. The SSO server returns the mobile XML global logout page and a special HTTP header (X-Oracle-SSO-logout with value = true). The global logout page contains one image for each partner application that has the user session.

  3. Oracle9iAS Wireless sends HTTP requests to each image link. This is done so that the user's session gets cleaned up in all the partner applications.

  4. Oracle9iAS Wireless terminates the user's session.

  5. Oracle9iAS Wireless follows the done_URL of the global logout page.

  6. The content returned by the done_URL is returned to the device.

10.2.5.3 Scenario 3: Logout from Web-based Oracle9iAS application

Since all Web-based Oracle9iAS applications are authenticated through mod_osso, and are treated as a single partner application, logout from any application triggers global sign-off and none of the applications will be accessible until the user signs on through mod_osso again.

10.2.6 Oracle9iAS Wireless-OID Integration

In this release, user information is stored centrally in OID. The SSO server uses an OID repository to authenticate users. The following table shows the attribute mapping between PanamaUser (stored in Oracle9iAS Wireless repository) and orclUserV2 user attributes (stored in OID).

Table 10-2 Attribute Mapping between PanamaUser and orclUserV2 user
PanamaUser OID User

Name

orclcommonnicknameattribute (by default cn) specified in OID configuration

DisplayName

DisplayName

Enabled

orclIsEnabled

PasswordHint

orclPasswordHint

PasswordHintAnswer

orclPasswordHintAnswer

Language and Country

preferredLanguage

TimeZone

TimeZone

DateofBirth

orclDateOfBirth

Globaluid

orclguid (orclguid attribute uniquely identifies OID Users)

Password

user password

Password Confirm

Confirms user password.

Gender

orcl header

iASv902 administrators can use tools (such as Delegated Administrative Services [DAS]), to create a new User in OID or to modify attributes of an existing user. Alternatively, Oracle9iAS Wireless customers can implement their own user administrator tool to create/modify/delete users using Oracle9iAS Wireless model APIs.

The user information is synchronized between Oracle9iAS Wireless and OID repositories using the following mechanisms:

10.2.7 Oracle9iAS Wireless Repository Synchronization after User Authentication

Oracle9iAS Wireless synchronizes user information (stored in the Wireless repository) with OID after SSO authentication.

Figure 10-7 Interactions between Oracle9iAS Wireless, SSO and OID

Text description of sso3.gif follows.

Text description of the illustration sso3.gif

  1. User sends an explicit login request or tries to access a private Service, or an external SSO partner application. The SSO server challenges user credentials and the user is authenticated.

  2. If the authenticated user does not exist in the Oracle9iAS Wireless repository, Oracle9iAS Wireless retrieves the user information from OID and creates a new user in the Oracle9iAS Wireless repository. Otherwise, the User attributes in the local repository are synchronized with the attributes stored in the OID.


    Note:

    The reason for synchronizing User attributes with OID is that the PL/SQL notification mechanism does not guarantee real time notifications.


10.2.8 PL/SQL based asynchronous synchronization

The Oracle9iAS Wireless installation registers a PL/SQL procedure with OID. The PL/SQL procedure is invoked when a user is modified or deleted in OID.

Figure 10-8 Interactions between PL/SQL and OID

Text description of sso4.gif follows.

Text description of the illustration sso4.gif

  1. User attribute is modified, or the user is deleted in OID.

  2. The Provisioning Synchronization agent picks up the modifications and calls the registered PL/SQL package.

  3. The PL/SQL package accomplishes appropriate changes in the PanamaUser table (if required).

  4. The trigger on the PanamaUser table broadcasts a RefreshCache message to all running instances of Oracle9iAS Wireless.

  5. If the modified PanamaUser is cached by the running instances, the PanamaUser object is reloaded from the Oracle9iAS Wireless repository.

10.2.9 Oracle9iAS Wireless Programmatic Model API Interface

The ModelFactory.createUser() method creates a corresponding User in the OID repository.

The User.set methods update the corresponding User entry in OID for all the attributes. The following table shows the attribute mapping between PanamaUser (stored in Oracle9iAS Wireless repository) and orclUserV2 user attributes (stored in OID). The User.delete() method removes the corresponding User from the OID repository. The current semantics of commit is preserved for the User modifications.

10.2.10 Oracle9iAS Wireless User Management Integrated with DAS

In Oracle9iAS Wireless integration mode, when you create a user through Webtool User Management, the request is first redirected to OID DAS (Delegated Administration Service), for entering Oracle9iAS User Common Attribute Values. After that, the request is redirected back to the Webtool User Management page for entering Wireless-specific attribute values.

The same applies for editing a registered Wireless user. The user is first edited through DAS and then through Webtool User Management.

10.2.11 WebCache Integration

Oracle9iAS Wireless is integrated with Oracle WebCache to improve page rendering performance and scalability. It must be clarified at the outset that WebCache is not deployed in the traditional sense with Oracle9iAS Wireless. WebCache is usually deployed in front of web-servers serving HTML content, and interacting with HTML clients and the web-server to cache dynamic content. However, with Oracle9iAS Wireless, the wireless runtime determines what content needs to be inserted into WebCache and when to expire content in the cache. WebCache, in this case, acts as a device adaptation cache rather than a reverse-proxy cache.

10.2.11.1 How Does this Work?

Since markup content is cached using WebCache, the performance and scalability benefits are due to two factors: reduced device adaptation costs, and significantly reduced adapter invocation costs. The savings in terms of device adaptation costs are due to the fact that content that can be shared across users and sessions is essentially transformed only once (per logical device) from its Mobile XML format. Secondly, since the content is not generated every time by an adapter, the total adapter invocation cost is significantly reduced for a site that has a large subset of cacheable pages.

10.2.11.2 A Cache Miss Scenario

  1. An incoming request is received by the wireless runtime, which requests the cache for a page corresponding to the request and the device that made the request.

  2. In this case, the page does not exist in the cache, causing WebCache to send a request back to the wireless runtime, requesting for the page.

  3. This time, the runtime recognizes this request to be from WebCache, rather than from a client.

  4. The runtime processes the requests following the traditional code-path of invoking the service corresponding to the request and transforming the content.

  5. The transformed content is now returned as a response to the WebCache request.

  6. WebCache examines the response to determine if the page is cacheable or not, and if it is, cacheable for what period of time.

  7. Assuming that this particular page is cacheable, WebCache inserts the page into the cache with an expiration limit set to the page.

  8. WebCache then serves this page out as a response to the original request from the runtime, which in turn uses this page as a response to the client request.

Figure 10-9 A Cache Miss Scenario

Text description of corearch.gif follows.

Text description of the illustration corearch.gif

10.2.11.3 A Cache Hit Scenario

In this case, an incoming request from a client is for a page that has been cached by webcache.

  1. The wireless runtime sends a request to webcache, which examines the cache to see if the page is cached or not.

  2. If cached, it checks to see if the page has expired. If the page has not expired, it serves it out of the cache to the runtime, which in turn uses this page as a response to the client request.

  3. However, if the page has expired, it once again follows the same routine as it would in the event of a cache miss.

Figure 10-10 Cache Hit Scenario

Text description of corearca.gif follows.

Text description of the illustration corearca.gif

10.2.11.4 Configuration

10.2.11.4.1 Enabling Caching for the Site

To cache dynamic content, it is necessary to enable WebCache in the first place. From the System Manager, click on the Site tab. Under the Administration section, in the Configuration sub-section, click on WebCache Configuration.

10.2.11.4.2 Cache-enabling a Service

The steps detailed above described how to enable caching for a site. For the cache to be of use, it is necessary to enable services to be cacheable.

10.2.11.4.3 Invalidating Cache Content

For any caching mechanism to be effective, it is necessary to perform invalidation of the cache contents at appropriate intervals. Invalidation of wireless content residing in webcache can be either policy-based or asynchronous.

Policy-based Invalidation--It is possible to specify in advance if a page should be cacheable or not. One of the ways to do this is by specifying the invalidation frequency of a service (as in the previous section). When a page is inserted into the cache, the invalidation frequency of the service it belongs to is taken into account while determining how long the page should live in the cache.

It is also possible to dynamically specify the cacheability of a page. This is done at the content-source. If the page is to be specified as cacheable, the SimpleResult element should have a SimpleMeta child element. This element has a required attribute `cache', which when set to `yes', enables caching for the page and when set to `no' disables caching. An optional attribute to be used in conjunction with a `yes' value for the `cache' attribute is `ttl'. This can be used to specify in seconds the number of seconds the page should be cached before expiring it. For example:

<SimpleResult>
<SimpleMeta cache="no"/>
.....
</SimpleResult>

results in the page being non-cacheable, as below:


<SimpleResult>
<SimpleMeta cache="yes" ttl="300"/>
....
</SimpleResult>

results in the page being cached for 300 seconds.

Apart from using the SimpleMeta tag to specify cacheability, it is possible to use standard HTTP cache-control headers and ESI headers to specify cacheability for a page. Refer to your documentation on WebCache on how to specify cacheability using ESI headers.

The order in which cacheability for a given page is evaluated is as follows:

Asynchronous Invalidation--Despite specifying the cacheability policy for a page at the time of service creation or during the generation of the page, it may be necessary to explicitly invalidate content in the cache. It is possible to invalidate and refresh content in the cache based on a master service or a device.

From System Manager, click on the Site tab. Under the Administration section, in the Configuration sub-section, click on either `Refresh webcache - Master service' or `Refresh webcache - Device'.

10.2.11.5 Administration

If webcache is reinstalled on a different machine/port the WebCache settings must be reconfigured as detailed in the configuration section above.

If the wireless instance is reinstalled on a different machine, the location of the wireless instance should be modified in the `Application Servers' of WebCache's administration console. See the WebCache Configuration Guide for details on how to perform this task.

10.2.11.6 Building a cacheable service

In this section we shall build a sample service that is cacheable using webcache. We shall also explore the means to control the cacheability of such a service dynamically.

The sample service displays the current time and therefore immediately demonstrates the cached status of the page. We follow the steps detailed below to create the service:

  1. Create an external content source that can be invoked from an HTTP adapter. (As an aside, there is no requirement that a cacheable service need to be HTTP adapter based, any other adapter would do just as fine). We designate the content source as a simple JSP page which displays the current time in Mobile XML. For example:

    <%@ page language="java" %>
    <%@ page import="java.text.SimpleDateFormat"%>
    <%@ page import="java.util.Date"%>
    
    <%@ page session="false" %>
    <%@ page contentType="text/html; charset=iso-8859-1" %>
            <SimpleResult>
            <SimpleContainer>
            <SimpleText>
            <SimpleTextItem>
            <%
                    Date date = new Date();
                    SimpleDateFormat formatter =
    new SimpleDateFormat("yyyy.MM.dd G 'at' hh:mm:ss a zzz");
            %>
             <%=formatter.format(date)%>
    
            </SimpleTextItem>
            </SimpleText>
            </SimpleContainer>
            </SimpleResult>
    
    

Let us assume that this page is deployed at the URL: http://mycontent-server.oracle.com/dateserv.jsp

  1. We need to create a master service that uses this as the content source.

    • From the System Manager UI, clicking on the Master Services tab we create a new master service by clicking the Create Master Service button. In the mandatory fields (marked by an asterisk), we enter the value Date Serv for the Name of the master service and choose HTTPAdapter as the Adapter and ensure that the Valid checkbox is checked.

    • In the subsequent screen, we check the Cacheable checkbox and choose the Invalidation Frequency by specifying the Cardinal as 40 and Unit as Seconds, causing all pages corresponding to the service (in this case just one page) to be cached for 40 seconds.

    • In the next screen since our sample service does not have any Init Parameters, we click the Next button.

    • In the subsequent Input Parameters screen, we select the URL column and check the Mandatory field and enter the Default Value as the URL to our content source, i.e. http://mycontent-server.oracle.com/dateserv.jsp

    • We can skip the next couple of screens (by clicking Next) and create the master service by clicking the Finish button on the last screen.

  2. Now, we need to publish the service from the Content Manager.

    • We click the Add Service button to add a link to the master service that was created earlier.

    • We name the new service as DateService in the subsequent screen by entering DateService in the Name field. We also ensure that at least the Visible checkbox is checked and the Type is chosen as Normal Service.

    • In the next screen we choose Date Serv as the master, drilling down to the folder it was created in and click on Next.

    • We accept the default values in the next screen by clicking Next

    • We publish the service by clicking Submit on the next screen.

  3. We need to associate the service with an available Group for which we choose the Groups tab in the next screen.

    • We choose a Group, say Guests and click on the Assign Services button.

    • In the next screen under the list of Available Services, we choose DateService and click on the Add To Group button.

    • In the subsequent screen DateService should now be listed under Group Accessible Services. We click the Finish button to complete the service association.

The service is now accessible from the device portal. We can see that the time-stamp displayed as a result of invoking the DateService service does not change for 40 seconds, indicating that the service has been cached for 40 seconds and invalidated after. Please note that after a page in the cache has expired, the content is fetched from the content source only on a demand basis, i.e. after 40 seconds elapse Webcache will not refresh the content immediately, but will do so only after a new request for the page is received.

10.2.11.7 Dynamic specification of page invalidation

The time for which the cache can retain the page without refreshing it has been set to 40 seconds during the service creation. However, this value can be changed dynamically at the time of generation of the Mobile XML. This can be done in two ways:

10.2.11.8 Mobile XML markup

In this case the generated Mobile XML can have a SimpleMeta tag to attain this. Please see the Policy-base Invalidation sub-section in the previous section on how to do this. For our sample service, to ensure that the page is expired after 10 seconds (rather than the default of 40 seconds), the JSP page would be:

<%@ page language="java" %>
<%@ page import="java.text.SimpleDateFormat"%>
<%@ page import="java.util.Date"%>

<%@ page session="false" %>
<%@ page contentType="text/html; charset=iso-8859-1" %>
        <SimpleResult>
    <SimpleMeta cache="yes" ttl="300"/>
        <SimpleContainer>
        <SimpleText>
        <SimpleTextItem>
        <%
                Date date = new Date();
                SimpleDateFormat formatter =
new SimpleDateFormat("yyyy.MM.dd G 'at' hh:mm:ss a zzz");
        %>
         <%=formatter.format(date)%>

        </SimpleTextItem>
        </SimpleText>
        </SimpleContainer>
        </SimpleResult>

10.2.11.9 ESI headers

Responses from the content source may contain ESI headers as part of HTTP headers that can dictate cache expiration behavior. Using ESI headers entail no changes to the Mobile XML. The following ESI header expires the page is 30 seconds.

Surrogate-Control: max-age=30+60, content="ESI/1.0"

For more information on ESI headers, please refer to the Webcache Developer's Guide.

10.2.12 Oracle Portal and Oracle9iAS Wireless

Oracle9iAS Portal is a web-based application model for building and deploying e-business portals. It provides a environment for accessing and interacting with enterprise software services and information resources. Portal provides a framework that integrates web-based resources such as web pages, applications, business intelligence reports, and syndicated content feeds, within standardized, reusable information components called portlets.

A portlet is an area of HTML/XML located within a defined area of a Web page. Portlets communicate with the portal through an entity called a provider. Portlets form the fundamental building blocks of a Oracle9iAS Portal page. Each portal page consists of content presented through one or more portlets and links that allow the user to navigate to another page to take some action.

Portlets summarize, promote or provide basic access to an information resource. The portlets allow information resources to be personalized and managed as a service of Oracle9iAS Portal. The portal framework provides additional services including single sign-on, content classification, enterprise search, directory integration, and access control. OraclePortal traditionally has been supporting Desktop/PC Web browsers. Starting in Orcale9iAS releas2.0 OraclePortal, besides support standard web browsers, will enable Oracle9iAS Portal pages to be accessed from wireless devices. OraclePortal, working in conjunction with Oracle9iAS Wireless, automatically transforms the portal page structure that is appropriate for the wireless devices. Portal generates the Page structure in Oracle9iAS Wireless XML, for all request from wireless device, and rendered to the device by Oracle9iAS Wireless. This allows portlets to provide wireless interface using OraclePortal, through Oracle9iAS Wireless.

10.2.13 Oracle Portal as a Wireless Service

To enable Oracle9iAS Wireless access to Portal, the Portal must be deployed as a Wireless service in the Oracle9iAS Wireless repository. Each Portal installation is deployed as an HTTP Adapter service in Oracle9iAS Wireless. Multiple Portals may be deployed on a single Wireless instance. The HTTP adapter service accepts a URL as a configuration parameter and must be set to the URL of the Portal's home page. To create a Wireless service, a Master Service definition based on an HTTP adapter must be created using the Oracle9iAS Wireless Webtool. Also, you must create an OraclePortal Service based on the HTTP adapter Master Service.

OraclePortal redirects requests from a Wireless device to an Oracle9iAS Wireless server. The Oracle9iAS Wireless Server accepts the request and invokes the OraclePortal home page over HTTP and accepts the response generated (in Oracle9iAS Wireless XML), from OraclePortal. The XML response, generated by OraclePortal, is then adapted to the native device markup by the Oracle9iAS Wireless server. All further requests and responses between Wireless device and OraclePortal is mediated by the Oracle9iAS Wireless Server.

Figure 10-11 Oracle Portal Integration

Text description of portalin.gif follows.

Text description of the illustration portalin.gif

Wireless devices make the first request to OraclePortal server and Portal redirects the device request to Wireless Server. The Portal appends two parameters to the redirected URL, the two query parameters appended are "PAoid" and "PAhome". Both PAoid and PAhome contain the value of the object id (service-id in the Wireless repository) of the Portal's HTTP adapter service. The syntax of the redirected URL is:

http://9iASWSerrver:port/ptg/rm?PAoid=<OraclePortal object 
id>&PAhome=<OraclePortal object id>

The PAoid parameter allows the Wireless server to directly launch the Portal home page, without having to navigate through the Wireless server's folder and service hierarchy. The PAhome sets the Portals Home Page as the home page for the current wireless session.

10.2.14 Developing Wireless Portlets

Portlets are owned by entities called Providers, and one Provider can manage one or many portlets. Providers are the backbone behind the Portlets being displayed on each page. Portal supports a Web Provider framework that is written as a web application. It is installed and hosted on a web server and is remote from the Portal. A portlet exposed as a Web Provider can be developed in any web language. A Web Provider communicates with Oracle9iAS Portal using SOAP(XML).

OraclePortal supports a Java based Portal Developer Kit (PDK) framework to develop portlets and services. The Java PDK Framework is a set of services that enable Java programmers to easily create portlets from existing Java-based applications (Java, Java Servlets, and JSPs). It provides an abstraction to handle communication with Oracle9iAS Portal, default classes to simplify portlet creation, and exposes APIs for end-user customization, session storage, security, and logging.

For Wireless devices, OraclePortal will support Portlets that generate Oracle9iAS Wireless XML. To enable wireless access Portlets must generate Oracle9iAS Wireless XML and indicate such capability using the Java PDK framework. The Java PDK framework uses a Provider.xml file to discover the capabilities of the Portlets supported by a Provider. Refer to OraclePortal's PDK-Java User's Guide for more information.

Following is a overview of tags (in the Provider.xml file) that indicates the wireless capabilities of a Portlet.

1.<acceptContentType>
           Usage:  
<acceptContentType>text/vnd.oracle.mobilexml</acceptContentType>

This value "text/vnd.oracle.mobilexml" indicates that the portlet is capable of generating Oracle9iAS Wireless XML required for Wireless access. A portlet can be enabled for both HTML (PC Desktop) and Wireless Access by indicating it can accept both the content types such as:

<acceptContentType>text/vnd.oracle.mobilexml</acceptContentType>
            <acceptContentType>text/html</acceptContentType> 

If the Portlet is capable of generating only Oracle9iAS Wireless XML (text/vnd.oracle.mobilexml), then (unless otherwise indicated) the Portlet will transform the Oracle9iAS Wireless XML to HTML for PC Desktop clients.

2.<mobileFlags>
           Usage: <mobileFlags>MOBILE_ONLY</mobileFlags>

Portlets can set this value to MOBILE_ONLY and hence indicate that this Portlet must be rendered in wireless devices only. This will prevent the default behavior of a Portal to transform Oracle9iAS Wireless XML, generated by the Portlet and rendered to PC Desktop clients.

3.<showLink>
           Usage:<showLink>true</showLink>

Portal renders all the Portlets on Wireless devices as links. Portlets must set this value to True to be rendered on a wireless device. A value of True allows the Portal to generate a Link, pointing to the Portlet content, on the wireless device.

4.<linkPage>
           Usage:<linkPage 
class="oracle.portal.provider.v2.render.http.ResourceRenderer">
                       <resourcePath>/mypath/mypage.jsp</resourcePath>
                       <contentType>text/vnd.oracle.mobilexml</contentType>
                       </linkPage>

This tags holds the pointer to the resource which generates the required link that is rendered on a wireless device. This resource must generate Oracle9iAS Wireless XML. Below is a sample link page implemented in JSP.

           <%@ page session="false" contentType="text/vnd.oracle.mobilexml" %>
               <SimpleHref target="/mypath/mywireless.jsp" label="Go">
                     Wireless HelloWorld
               </SimpleHref>

The new version JPDK has been updated to understand these wireless properties of a Portlet. The JPDK also supports wireless specific request information like location and device information, which can be accessed by the Portlets through the JPDK APIs.

10.2.15 OraclePortal, Oracle9iAS Wireless and Single SignOn (SSO)

Both OraclePortal and Oracle9iAS Wireless depend on Oracle's SSO solution for user authentication and login. This integration allows the user to invoke protected applications defined on both systems and eliminates multiple login dialog boxes for users.

Oracle9iAS Wireless Server upgrades the session context of a user to an "authenticated" state when any service or application (HTTP Adapter services) validates the user credentials with the SSO server. When OraclePortal, mobile application, validates the credentials of a user with the SSO Server, the session context in Oracle9iAS Wireless is also updated. This allows wireless Portlets deployed on OraclePortal to uses services such as User Location Picker, Routing, Mobile Positioning supported by the Oracle9iAS Wireless Server.

10.2.16 Portlets for Services Deployed on Wireless Server

You can use OraclePortal's services to provide a PC Desktop view of your Oracle9iAS Wireless services. You can use Portal's JPDK framework to provide a "showPage" and "editPage", for web-based customizations.

Since the Portal itself can be accessed from a wireless device, you must also provide a mobile Portlet. On a wireless device, the mobile Portlets are rendered as links and can be made to point to a service deployed on the Oracle9iAS Wireless server. You can use Portal's JPDK framework to provide a "linkPage" that generates the appropriate link for your wireless service. To point to a wireless service from a mobile portlet you can use following URL syntax in your Oracle9iAS Wireless XML:

target="___REQUEST_NAME__?___SESSION__&amp;PAoid=<PAoid of Wireless Service>"

The Wireless server will replace all "___<Name>__" to the correct values at runtime and will invoke a service define in the Oracle9iAS Wireless repository.

The following is a sample link page:

<%@ page session="false" contentType="text/vnd.oracle.mobilexml" %>
          <SimpleHref target="/___REQUEST_NAME__?PAoid="+PAoid + "&amp;___
SESSION__" label="Go">
                My Wireless Service
          </SimpleHref>

Mobile devices make the first request to OraclePortal server. Portal redirects the device request to Oracle9iAS Wireless Server, over HTTP, and appends two parameters to the redirected URL. The two query parameters are "PAoid" and "PAhome". Both PAoid and PAhome contain the Portal's object/service id. The typical syntax of the redirected URL are:

http://Oracle9iAS WirelessSerrver:port/ptg/rm?PAoid=<OraclePortalServiceid>&PAhome=<OraclePortalService id>

The PAoid parameter allows the Wireless server to directly launch the Portal home page, without having to navigate through the Wireless server's folder and service hierarchy. The PAhome sets the Portals Home Page as the home page for the current wireless session.

10.2.16.1 Webtool and Customization as Portal Providers

The post-installer automatically registers Webtool and Customization as two Oracle Portal Providers. Thus, if an Oracle Portal user selects the two providers he/she will see two portlets: one for Webtool, and one for Customization. If the URL for Webtool or Customization is changed, the provider can be registered from Wireless System Manager, part of Oracle Enterprise Manager. For more information, see Oracle9iAS Wireless Getting Started and System Guide.

10.3 Wireless Services

10.3.1 Wireless Services Overview

Services enable end users to access the functionality of Oracle9iAS Wireless. They represent the link between the content source and the delivery target. Services tie a specific data source (through an adapter) to the different devices.

There are different types of services:

10.3.1.1 MasterService

MasterServices provide the basic wireless functionality. They are the actual implementation of the service. Each MasterService is based on one adapter. A MasterService sets values for the adapter init, input and output parameters. Each MasterService creates its own instance of the adapter it uses. Therefore, several services can use the same type of adapter, and each can pass its own service-specific argument values.

It is recommended that you build all MasterServices using the HTTPAdapter. That gives you the flexibility to implement the service business logic using JSPs or other web technologies.

10.3.1.2 Link

Links are used to further customize existing services by overriding the values of their parameters.

When a Link service is invoked the Wireless server will merge the parameters with the parameters of the service the Link points to, and invoke that service.

Links are also used to better organize services into user service trees. They give you the flexibility to publish the same service under different names and in different folders (different levels in the service tree). If you do not override any parameter values, then invoking the link is the same as invoking the service it points to.

10.3.1.3 Module

Modules are wireless services with well-known virtual URL (OMP URL, that is, omp://my.module).

Modules can be called from any application or module and may be instructed to return control to another application or module. Calls may be nested to any level. This mechanism of bi-directional linking allows quick applications assembly.

An important difference between a module and a regular service is that the module receives information about the service it needs to return to after it is done. This is not always the caller of the module (the module caller may want the module to return to a different service).

10.3.1.4 Folder

Folders are containers for other services. They are used to better organize user-accessible services into a service tree. The content of a folder is displayed by invoking its rendering service--a special service associated with each folder.

The system rendering service displays the folder child services ordered by the specified sort rule.

Optionally, you can specify icons and audio files to be displayed/played when a service link is displayed in the folder content or when the service is invoked.

10.3.1.5 ExternalLink

An ExternalLink is a wireless service that points to an external resource. The external resource is typically a Web page that serves content in a format supported by the target device.

Oracle9iAS Wireless does not process the content of the ExternalLink target. As a result, ExternalLink services are not available to all targeted devices, as are other Wireless services. In most cases, ExternalLinks are set in the Customization portal by the end user, not in the Service Designer.

10.3.2 Access Control

There are two type of services in terms of accessibility:

There are different rules that apply to those two type of services.

The user private services are services that reside in the user home service tree. The user can access all of those services. No other user can access those services.

The shared services in contrast are accessed by multiple users. The access is controlled by the User - Group - Service relationship. When you assign a service to a group, all users from that group can access the service.

10.4 Device and Network Adaptation

This section describes how to create and manage Oracle9iAS Wireless transformers.

10.4.1 Logical Device

Logical Device in Oracle9iAS Wireless represents either a physical device, such as an Ericsson mobile phone or an abstract device, such as ASYNC. The Logical Device stores the attributes of the physical device/ browser and device transformers. The Oracle9iAS Wireless server uses the device transformer of the Logical Device associated with the request to transform mobile xml service result to device mark up language.

Each request in Oracle9iAS Wireless is associated with a Logical Device. The Device Detection process, i.e. finding out the Logical device corresponding to a request, is done for each Oracle9iAS Wireless request. Device Detection mechanism is discussed later in the chapter.

The following table lists the Logical Device attributes. These attributes can be retrieved and modified using programmatic java api's. Refer to the javadoc of oracle.panama.model.Device interface.

Table 10-3 Logical Device attributes
Attribute Name Description

Name

Name of the logical Device

Description

Description of the Logical Device

Encoding

The Character Encoding to be used by the Device. This attribute specifies the Character encoding used by the device browser to send URL parameters. Also the content returned in response to a request is encoded using the encoding of the logical device.

Preferred Mime Type

mime type supported by the device, for example text/html for devices supporting HTML

The above mentioned attributes can be used by the Transformers, Adapters, Folder Renderer hooks or external Http Adapter based Services to generate custom content for the device. The Logical Device attributes are passed to the external Http Adapter based services through HTTP headers. See Section 10.7, "Adapters" for more information.

Oracle9iAS Wireless server is shipped with pre-built Logical Devices. Customers can add additional logical devices or can modify existing Logical Devices if any of their physical devices can not be mapped to an existing Oracle9iAS Wireless Logical Device. Refer to Oracle9iAS Wireless Getting Started and System Guide for details on how to add or modify Logical Devices.

10.4.2 Device Detection

The Device Detection in Oracle9iAS Wireless can be customized by specifying a hook class that implements the interface oracle.panama.rt.hook.DeviceIdentificationHook. The default implementation of the hook is provided in oracle.panma.rt.hook.DeviceIdentificationPolicy class.

The default (built-in) implementation uses the User-Agent String to Logical device mappings, stored in the LogicalDevice model object, to identify the logical device from the request. Note that in previous releases of Oracle9iAS Wireless the User-Agent String to logical device mapping was specified in oracle/panama/core/admin/UserAgents properties file.

The User-Agent string can contain wild card character `*'. For example, the User-Agent String `*DS*' will match all the User-Agent values containing `DS'.

The Device Detection algorithm:

  1. Match the User-Agent http header value with all the User-Agent Strings. If there is a match then use the Logical Device corresponding to the matched User-Agent String, else go to step 2. In case of multiple matches the Logical Device corresponding to the User-Agent string with maximum number of non-wild card characters is used.

  2. Find all the Logical Devices whose mime type attribute matches the value of the Accept http header. Go to step 3.

  3. If the request contains x-up-devcap-screenpixels and x-up-devcap-screenchars http headers then, find the closest matching logical device using ScreenWidth, ScreenHeight, ScreenRows, ScreenColumns attributes of the Logical Device. Else select any logical device.

10.4.3 Image Support

The devices and browsers available in the market today support different image formats, for example, WML devices support wbmp image formats whereas Palm supports gray scale depth 2 image formats. The "image Format Preferences" attribute of Logical device stores all the image mimetype and corresponding file extension supported by the device. This attribute of Logical Device is used by the Transformers to transform the <SimpleImage> mobile xml element.

The mobile xml developer can use the "available" attribute of <SimpleImage> element to specify the list of image file extensions available. The transformer appends the file extension, supported by the device, to the "src" attribute of the <SimpleImage> element. The "src" attribute of <SimpleResult> specifies the location of the image file.

For example, the following <SimpleOracle9iAS Wireless element> specifies that the image_file is available in "gif", "wbmp"and "g2gif" formats.

<SimpleImage src="http://IASWServer:port/image_file" available="gif wbmp g2.gif" 
/>

For devices supporting only g2.gif extension the above <SimpleImage> will get transformed to:

<img src="http://IASWServer:port/image_file.g2.gif">

10.4.4 Transformer

Oracle9iAS Wireless supports Device Transformers.

The Device Transformers transform mobile xml document to the device markup language. The transformation logic can be implemented in an XSL stylesheet or in Java.

The Result transformers convert content from AdapterResult format to Mobile XML format. The Adapter Result format is an intermediary format layer that enables efficient exchange of user interface independent data. You may use it, for example, to link chained service. A chained service is an Oracle9iAS Wireless service that invokes another service. Result Transformers are deprecated in Oracle9iAS Wireless 9.0.2 version.

The following table lists the attributes stored in the Device Transformer objects. These attributes can be accesses by java programmatic apis' - refer to javadoc of oracle.panama.model.Transformer, oracle.panama.model.JavaTransformer and oracle.panama.model.XSLTransformer interface.

Table 10-4 Device Transformer objects attributes
Attribute Name Description

Name

Name of the transformer

Mime Type

The mime type of the target device markup language. For example, text/html

Mobile XML DTD version

The mobile xml dtd version supported by the transformer.

XSL Stylesheet

The XSL Stylesheet implementing the transformation logic. This attribute is valid only for XSL based Transformers

Java Class

The class path of the class implementing the transformation logic. This attribute is valid only for Java based Transformers.

10.4.4.1 Java Transformers

Transformers can implement transformation logic in Java by implementing oracle.panama.rt.xform.RtTransformer interface.

/*
 * $Copyright:
 *             Copyright (c) 2000 Oracle Corporation all rights reserved
 * $
 */
package oracle.panama.rt.xform;

import java.io.Writer;
import org.w3c.dom.Element;
import oracle.panama.PanamaException;

/**
 * Transform from a XML structure to a device specific content.
 *
 * @since     Oracle9i Application Server Wireless Edition
 */
public interface RtTransformer {

    /**
     * Transform the simple result XML document into a device specific markup la
nguage.
     * @param element the <code>ServiceContext</code> XML Element to process.
     * @param out the output writer for the result
     */
    public void transform(Element element, Writer out) throws PanamaException;

}

Oracle9iAS Wireless run time calls the transform method of the Java transformer to transform the mobile xml document to device markup. The parameter element contains the ServiceContext, and the device markup result is written to the out parameter of the method. The ServiceContext contains the input parameters of the request, attributes of the logical device corresponding to the request and SimpleResult (mobile xml document).

The class implementing oracle.panama.rt.xform.RtTransformer interface must provide a default constructor (that is, constructor without arguments) and the transform() method should be thread-safe.

The ServiceContext Element passed to the transform() method of RtTransformer class is of the form.

<ServiceRequest>
   <Arguments>
       <Inputs>

All the input arguments passed to the Service - this includes the service arguments and other arguments listed below

........
       </Inputs>
   </Arguments>
   <Result>
The mobile xml content
.......
   <Result>
</ServiceRequest>

The input argument is of the form

<name ....>value</name>

where "name" is the name of the input argument and "value" is the value of the input argument.

The following table lists the input arguments other than the service input arguments, which are passed to the Service.

Table 10-5 Input arguments
Name of the Input Argument Description

_LOGICAL_DEVICE

Name of the logical device corresponding to the request.

_ScreenColumns

The value of screen columns attribute of the logical device corresponding to the request

_ScreenRows

The value of screen rows attribute of the logical device corresponding to the request

_ScreenWidth

The value of screen width attribute of the logical device corresponding to the request

_ScreenHeight

The value of screen height attribute of the logical device corresponding to the request

_DeviceCategory

The value of device category attribute of the logical device corresponding to the request

_SoftKeys

The value of soft keys attribute of the logical device corresponding to the request

_MaxDocSize

The value of max doc size attribute of the logical device corresponding to the request

_ImagePreferences

The value of image preferences attribute of the logical device corresponding to the request

_User

The name of the User.

_UserLanguage

The language preference of the User

_FirstAcceptLanguage

The first language specified in the Accept-Language HTTP header.

USER-AGENT

The User-Agent HTTP header value of the request Note: All the HTTP headers of the Oracle9iAS Wireless request are added to the Service Context

COOKIE

The Cookie HTTP header value of the request

CONNECTION

The Connection HTTP header value of the request

ACCEPT

The Accept HTTP header value of the request

HOST

The Host HTTP header value of the request

REFERER

The Referer HTTP header value of the request

ACCEPT-LANGUAGE

The Accept-Language HTTP header value of the request

ACCEPT-ENCODING

The Accept-Encoding HTTP header value of the request

_SERVICE_NAME

The name of the invoked Service.

_SERVICE_NAME_ENC

The URL encoded name of the invoked Service.

_SERVICE_URL

The URL of the invoked Service

_SERVICE_URL_ENC

The URL encoded value of the URL of the invoked Service

PAoid

The object id of the invoked service

_REQUEST_NAME

The path component of the Servlet. For e.g. /ptg/rm

_HTTP_REQUEST_NAME

The URL path of the Servlet. For e.g. http://IasServer:Port:7777/ptg/rm

_ABS_REQUEST_NAME

The URL path of the Servlet. For e.g. http://IasServer:Port:7777/ptg/rm

_HTTPS_REQUEST_NAME

The HTTPS URL path of the Servlet. For e.g. https://IasServer:Port:7778/ptg/rm

PAsid

The session id of the request. For e.g. 100BoNrXdG

_SESSION

The session id name/value pair. For e.g PAsid=100BoNrXdG

PAservlet

The name of the Servlet. For e.g. rm

AMP_EXPLICIT

10.4.5 XSLT Transformers

Device transformer logic can be implemented in XSL stylesheet. XSL stylesheets are XML documents that specifies the processing rules for other XML documents. An XSLT stylesheet, like java transformers, is written for a particular mobile XML DTD. When it finds the element in source document, it follows the rules defined for the element to format its content. The ServiceContext element is passed as the source document to the stylesheet.

10.4.5.1 Creating XSL Transformer

In this section we will implement a very simple XSL stylesheet which handles only <SimpleTable> mobile xml element. It uses the value of screen width attribute of the logical device, passed as _ScreenWidth element in the ServiceContext, as the width of the generated HTML table. The Stylesheet converts source mobile xml documents to HTML.

Example mobile xml document handled by our custom stylesheet.

<SimpleResult>
   <SimpleContainer>
      <SimpleTable>
         <SimpleRow>
            <SimpleCol>Row1 column1</SimpleCol>
            <SimpleCol>Row1 column2</SimpleCol>
         </SimpleRow>
         <SimpleRow>
            <SimpleCol>row2 column1</SimpleCol>
            <SimpleCol>row2 column2 </SimpleCol>
         </SimpleRow>
      </SimpleTable>
   </SimpleContainer>
</SimpleResult> 

The stylesheet implementation.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:p2g="http://www.oracle.com/XSL/Transform/java/oracle.panama.core.xform.XSJ
ava" exclude-result-prefixes="p2g">
This template matches the root of the document. 
   <xsl:template match="/">
      <xsl:apply-templates select="//SimpleResult"/>
   </xsl:template>

Template for SimpleResult element.

   <xsl:template match="SimpleResult">
      <HTML>
         <BODY>
            <xsl:apply-templates select="SimpleContainer/SimpleTable" />
         </BODY>
      </HTML>
   </xsl:template>

Template for <SimpleTable> element.

   <xsl:template match="SimpleTable">
      <TABLE>

The width attribute of the table is set to the value of _ScreenWidth element.

         <xsl:attribute name="width">
            <xsl:value-of select="//_ScreenWidth" />
         </xsl:attribute>
         <xsl:for-each select="./SimpleRow">
            <xsl:apply-templates select="."/>
         </xsl:for-each>
      </TABLE>
</xsl:template>

Template for SimpleRow element

   <xsl:template match="SimpleRow">
      <TR>
         <xsl:for-each select="./SimpleCol">
            <xsl:apply-templates select="."/>
         </xsl:for-each>
      </TR>
   </xsl:template>

Template for SimpleCol element.

   <xsl:template match="SimpleCol">
      <TD>
         <xsl:value-of select="." />
      </TD>
   </xsl:template>
</xsl:stylesheet>

10.4.5.2 Transformer Version

Oracle9iAS Wireless server supports multiple transformers, one for each version of the mobile XML DTD, for Logical Devices. The run time selects the transformer depending on the DTD version specified in the mobile XML Document. All the mobile xml documents should include the following DOCTYPE declaration

<!DOCTYPE SimpleResult PUBLIC "-//ORACLE//DTD SimpleResult x.y.z//EN" "http://xmlns.oracle.com/ias/dtds/SimpleResultxyz.dtd">

The DTD version is specified by the string "x.y.z", where x is incremented for every major revision of DTD, y is incremented for minor revisions, and z can be incremented by the customer for customer specific DTD enhancements.

For backward compatibility all the mobile xml documents, which do not contain the DOCTYPE declaration, will be assumed to be confirming to 1.0.0 version (i.e pre 9.0.2 version of the DTD)

The algorithm to find the transformer for a mobile xml document confirming with DTD version x.y.z

  1. Find all transformers with major number "x". If no transformers are found then log an error message and return.

  2. From the transformer set returned from step1, find all the transformers with minor number 'y'. If a transformer is found then go to step4

  3. From the transformer set (returned from step1) choose the transformer with minimum minor number which is greater than y. If no such transformer exists then choose a transformer with maximum minor number which is less than y.

  4. From the transformer set returned from step2, choose the transformer with customer version number 'z'. If no such transformer is found then choose the transformer with minimum customer version number which is greater than z. If no such transformer exists then choose a transformer with maximum customer version number which is less than z.

The following HelloWorld.xml confirms to DTD version 1.1.0 (which is the current version of the DTD).

<?xml version = "1.0" encoding = "UTF-8" standalone="yes" ?>
<!DOCTYPE SimpleResult PUBLIC "-//ORACLE//DTD SimpleResult 1.1.0//EN" 
"http://xmlns.oracle.com/ias/dtds/SimpleResult_1_1_0.dtd">
<SimpleResult>
<SimpleContainer>
  <SimpleText>
    <SimpleTextItem>Hello World </SimpleTextItem>
  </SimpleText>
</SimpleContainer>
</SimpleResult>


Note:

For information on using Service Designer to create and manage Transformers, and for all Service Designer functions, see "Managing Transformers" in Oracle9iAS Wireless Getting Started and System Guide.


10.5 Asynchronous Server

10.5.1 Asynchronous Server Architecture

Oracle9iAS Wireless presents a framework to develop mobile applications to be accessed "from anywhere, from any device, using any protocol". The Asynchronous Server Kernel, also known as ASK makes the "any protocol" promise possible.

Conventionally, the entry point into an application server is through the HTTP protocol. This limits applications built on an application server to only clients with Web capability. This server restriction is a problem for mobile market users because the vast majority of mobile users do not have, or are not enabled with Web access. These users are almost certain to have some kind of message capabilities though (such as e-mail, SMS, etc.). Now the dilemma is whether one should build applications for such users specifically, depending on their capability, or ignore them because the application server just cannot deal with the mobile market.

With Oracle9iAS Wireless, the dilemma is solved for developers, without them doing anything at all. With the introduction of ASK, mobile applications can be accessed through the usual HTTP protocol, as well as any other messaging protocols (such as e-mail, SMS, etc.). Developers can focus on building their application logic, and Oracle9iAS Wireless will do the proper connection, session management, and interpretation of user requests. A mobile service is invoked the same way regardless of which protocol handles the incoming requests, offering complete transparency to application developers to allow access to their services.

10.5.2 Key Technical Challenges

10.5.2.1 Multiple transport protocol support

One of the most obvious challenges is to be able to support multiple protocols. It is not desirable to build the same functionality to work with e-mail, then SMS, then some other protocols. Oracle9iAS Wireless offers access to the same application regardless of the protocol used by clients. Hence the immediate challenge is to be able to support multiple protocols uniformly.

10.5.2.2 The asynchronous nature of messaging protocols

In contrast to the HTTP protocol, (commonly referred to as the synchronous protocol) messaging protocols such as SMS or e-mail are asynchronous. It is asynchronous because unlike HTTP, they are not based on a "request and response" model. A single atomic operation is typically one way. For example, when you use a Web browser, you enter a URL and make the request, then you wait for the result to come back. In messaging protocols (such as SMS) sending a message itself completes one operation. Most applications respond to user requests so HTTP is usually adequate. To enable the same application be accessed through asynchronous protocols presents a challenge on how such behavior can be mimicked with protocols such as SMS or e-mail.

10.5.2.3 Supporting Sessions

Another big challenge is that most applications are session based; multiple requests and responses are typically required to complete a task. Applications are able to maintain sessions in the Web world because the client, a Web browser, has built in capabilities such as cookies to facilitate session semantics. This is not the case for an e-mail or SMS client. They do not have any such ability built in to support conversational applications.

10.5.2.4 User Navigation

A Web browser offers a User Interface for navigating through applications (examples include clicking on a hyperlink and traversing through a menu or a series of steps to complete certain functionality). Clients that work with other protocols such as SMS or e-mail typically do not have similar navigation power. The challenge here is to offer similar navigating capability to such clients so that applications can be independent of the protocols.

10.5.2.5 Naming/Addressing an Application

In the Web world, applications are typically assigned a URL. The URL is how the application can be identified and requested. Clients for messaging are typically plain text devices; there is no convention on how to name a service, but consistency across protocols is needed.

10.5.3 Technical Solutions and Features

ASK combines functionality of a HTTP server and portions of a Web browser to provide its functionality.

10.5.3.1 Multiple transport protocol support

This challenge is a relatively easy one. Built on top of the Oracle9iAS Wireless transport system, support for multiple transport protocols is achieved by the nature of the transport system itself. ASK registers to be an application to the transport system to send and receive messages. It further registers one address for each of the protocols it is serving in order to interact with users on those protocols. For example, it can register ask@yourcomany.com for e-mail and 1234567 for SMS. Then ask@yourcompany.com and 1234567 become the URIs for their respective protocols similar to http://yourcompany.com is to the Web world.

ASK itself does not consider the incoming protocols; it is designed to send and receive messages by the means that it is registered to use. The payload (content) of the messages are what ASK interprets and acts upon.

10.5.3.2 The asynchronous nature of messaging protocols

ASK builds logic similar to an HTTP listener to present synchronous semantics over asynchronous protocols. It achieves this by acting as a client to the service the device requested. ASK makes a request to the service on behalf of the user, waits and processes the response from the service, then formats the response and presents it back to the users. Users have the illusion of a response from an earlier request.

10.5.3.3 Supporting Sessions

Upon receiving requests from a user, ASK create a session for the user. This allows conversational applications to function. Unlike in HTTP where session info is kept by the browser (or cookie), all session states are kept in the backend by ASK.

10.5.3.4 User Navigation

ASK transforms elements such as forms or menus, and presents a navigation command for end users. When elements such as forms are returned by a service, ASK retains the format of the form in the backend, and determines the action to take when the form is submitted with all other necessary information. When this user (using the set of command specified by ASK) fills and submits the command, ASK makes a request (based on the current user information stored in ASK) and processes the result again on behalf of the user. You can think of it as if the hyperlinks are stored in the backend when a user clicks on the "face" of the link.

10.5.3.5 Naming/Addressing an Application

Just as assigning a URL to a service in the Web world, to use ASK, a short name must be assigned to services to be ASK enabled. For example, assume the stock quote service has been assigned the path: /finance/quote and can be accessed as http://mycompany.com/finance/stock. Through Content Manager, a short name can be assigned to it (for example, st.). Now any messages ASK receives that begins with st signals a request for the stock quote service. A user can send st orcl to a site-wide address to which ASK is configured to listen, ask@mycompany.com for e-mail or 1234567 for SMS, and get back the stock quote for Oracle Corporation.

It is also possible to specify service-level address to services. Through Content Manager, one can also associate (e-mail) stock@mycompany.com and (SMS) 123FINANCE to the stock quote service. Once this is done, sending just orcl as an email to stock@mycompany.com or as SMS to 123FINANCE would result in receiving the stock quote of Oracle Corporation.

10.5.3.6 ASK Request Authorization

ASK differentiates the user of a request into two categories: guest or registered. Upon receipt of a user request by ASK, the source address of the request message is used to reverse-lookup a Oracle9iAS Wireless user for authentication. A user object can be located if a user has a device address, registered under his profile, the same as the source address of the request message. The located user object is then bound to a newly authenticated session created by the request. Otherwise, a guest user object is bound to the session. Whichever services are authorized to the user will be accessible to requests issued from the device.

Only those services belonging to the guest group are accessible to a guest user. Accessing a non-guest service triggers a returned form challenging the user for name and password. A valid Oracle9iAS Wireless username/password supplied by the user enables the previous session to be upgraded to an authenticated one with the user object identified by the name to be bound. Alternately, a guest user can log in explicitly through a login command, '!L', to avoid ever being challenged.

10.5.3.7 User interface and navigation commands

As discussed earlier, messaging clients typically only present plain text and do not offer conversational navigation capabilities. Recall that ASK transforms and formats responses from services to a certain presentation to enable such capabilities. ASK includes a set of presentation formats and navigational commands similar to what a Web browser has done for the Web world. Hence when a user invokes services using ASK, he or she would see the response in the format transformed by ASK. Further interactions with ASK would have to comply with the format expected by ASK. In this section we will be discussing commands users can issue to ASK. To issue a command is simply sending a message with the correct format. The command text can be put into a subject line or message body.

10.5.3.7.1 System Commands

10.5.3.7.2 Service invocation commands

These are commands to do service invocation, menu selection and parameters filling. There are no reserved command symbols for the service invocation and form commands. Certain commands, such as form command and menu item selection, can be invoked only when there is a current form/menu state maintained in the user's session. More details on form/menu state will be discussed later in this chapter.

10.5.4 Examples on Service Invocation

10.5.4.1 Invoke by Service Short Name

All services that are ASK-enabled should be assigned short names to be accessed by the end user. The short name should be able to uniquely identify a service on the entire site. To invoke a service, a message should be sent to a site-wide address, such as info@oraclemobile.com, to which the ASK is configured to listen. The command line has the format:

<Svc Short Name> <parm1> <parm2> . . .

In the following example, a message is sent to the site-wide address: info@oraclemobile.com, to invoke a stock quote service whose short name is ST. The service requires a stock symbol as its parameter (in this case, ORCL is provided).

Figure 10-12 Invoking by service short name

Text description of async1.gif follows.

Text description of the illustration async1.gif

10.5.4.2 Invoke by service associated device address

Each service may have some device address associated with it. For example, an e-mail address stock@oraclemobile.com can be used to identified a stock service. Since the service has been identified in the destination address of the request message, there is no need to specify the service short name in the command line. Only the service parameters are required in the command line, for example, the stock symbol.

All of the system commands (for example, 'help') can still be issued to the service-associated address. They are interpreted by Async Server in the same way they are sent to the site-wide address.

Figure 10-13 Invoking by service associated device address

Text description of async2.gif follows.

Text description of the illustration async2.gif

10.5.4.3 Menu Capability

The way the features are presented is similar to the HTTP model. A service invocation may trigger the return of a message with the menu. Each menu item is prefixed with a number. Users are able to make selections by issuing another message in which the message content contains the menu item number. This extends the service capability for much better user interaction. A yellow pages service having a short name of yp expects two user parameters, category and area. Users invoke services by providing the values, for example, burger and home (a landmark for the user). The application searches for all the Burger stores in the home area. A returned message from the service result contains a name list of Burger stores. The user then issues another message to get detailed information about the stores in which he is interested.

Figure 10-14 Menu capability

Text description of async3.gif follows.

Text description of the illustration async3.gif

10.5.4.4 Form Capability

A form is the result of a service invocation requesting user input. The ideal user interaction for ASK is to have the user fill in the input parameters on the command line instead of having to fill in the form, which requires more message round trips.

Figure 10-15, "Form capability" demonstrates the possible interaction of a phone book service. The phonedit command enables users to search and edit the phone number for a particular user. It expects a name as its parameter. jdoe is provided in the example. The information of jdoe is returned with a menu, enabling the device user to edit the phone number or remove the user. There are two options for editing the phone number:

  1. Make a selection without entering any parameter: This is represented in box 2a. A form is returned prompting the user to enter the new phone number. The device user creates a new message with the message body containing the new phone number.

Or

  1. Enter the selection with the required parameters. Box 2b demonstrates the scenario. The device user is aware that a form should returned in response to their selection 1 (Change phone). Therefore, the parameter value (phone number) is supplied together with the selection. This saves a message round trip.

Figure 10-15 Form capability

Text description of async4.gif follows.

Text description of the illustration async4.gif

10.5.4.5 Current Menu State

Since a session is maintained for each user, menu navigation is made possible. The term current menu identifies the latest menu a user received from the ASK. The state of the current menu is kept in the user session on ASK. Whenever a menu selection is made by a user, it applies to the current menu. If a menu has not yet been received for the user, the ASK will attempt to locate a service whose short name is the same as the number provided by the user. An error is returned when no such service is found.

A service invocation through short name or device address automatically cancels the menu state created by the previous service invocation. The figure below demonstrates the situation. A menu returns as a response to invoking the phonedit service. A message for requesting the stk service is subsequently issued. It clears the menu state created by the invocation of the phonedit service. An attempt to make a menu selection triggers an error message from the ASK.

Figure 10-16 Current Menu State

Text description of async5.gif follows.

Text description of the illustration async5.gif

10.5.4.6 Current Form State

A current form state is created in the user session whenever the user receives a form message. Subsequent form parameter values can be issued by the user to fill the parameter requested from the previous form message. If the user decides not to fill the form but to invoke another service, the Escape command can be issued to cancel the current form state. Once the form state is clear, any form parameters issued by the user are considered invalid. An error message should be returned in respond to a form parameter without a current form state.

Figure 10-17, "Current Form State" illustrates a form state example. The device user invokes the phonedit service without providing any parameters. A form message is returned to the user expecting the user to fill in the search name. If the device user changes his/her mind and decides to invoke another service (for example stk) the first step is to clear the form state so that ASK will not treat the command stk as the name value expected from the phonedit service. Then, a new stk command can be issued. These two steps are combined into one message by separating the two commands with the default command separator (;).

Figure 10-17 Current Form State

Text description of async6.gif follows.

Text description of the illustration async6.gif

10.5.4.7 Multiple commands in one message

Multiple commands can be issued from one message. They can be issued from the same line, each command separated by the configurable command separator (default [;]). Or, commands can be on different lines. The first blank line or stop command (!s) encountered, marks the end of the command sequence. No command interpretation will be done on text after the mark.

Figure 10-18 Multiple Commands in One Message

Text description of async7.gif follows.

Text description of the illustration async7.gif

10.5.4.8 Parameter separator

Multiple parameters may be required for an Async service.The default parameter separator is a blank space. If a parameter value contains space within it, it can be enclosed by double quote to represent a single parameter value. The parameter separator is configurable at the service level.

The example below illustrates a direction service expecting both the from and destination (the to) addresses. The from address is provided with double quotes to enclose the whole value. The destination is supplied as a landmark, home from the user profile. The second message sent from the user is to request traffic information service. The service is configured to use a comma (,) as the parameter delimiter; users provide the parameter values with (,) to separate them.

Figure 10-19 Parameter Separator

Text description of async8.gif follows.

Text description of the illustration async8.gif

10.5.5 Writing Asynchronous Applications

The way to develop applications for ASK is basically the same as for the Device Portal. Service Provider receives user parameter from the device, and responds with the result (in Mobile XML format). The requirement on the ASK client is low; the ability to send and receive text messages. Therefore, only a subset of the Mobile XML tags are applicable to ASK, as shown in Table 10-6, "Summary of semantics for MobileXML tags".

Developers may choose to have a different logic flow (for example, rendering the results differently) for the ASK device. In this case, they would need to be able to recognize if the request was coming from an ASK device class. This is accomplished by checking the device class attribute of the user request. The request from ASK has the device class attribute value of either messenger, or micromessenger. The information can be acquired from the input arguments for a service written in adapter form, or the HTTP header for services based on HTTP/OC4J adapter. The input argument _DeviceCategory defined in the ServiceContext specifies the device class value for adapter formed services. For HTTP/OC4J based services, the value can be picked up through the HTTP header x-oracle-device.class.

Similarly, any section of the ASK specific Mobile XML result, created by the application, binds the value of messenger or micromessenger to the element attribute deviceclass. ASK processes elements common to all devices (with no value specified in deviceclass), or elements with the attributes containing the value of messenger or micromessenger.

10.5.5.1 ASK enabling MobileXML Application

All mobile XML service can be made ASK enabled from a technical standpoint. The user experience while using ASK is worth considering when deciding how to build an application or ASK enabling an existing application. This is the same practice you might have been applying to decide how you want to render you application to different types of devices (screen size, form factor and such). ASK assumes a client with plain text input so it is even more appropriate to consider user experience. Services that expect many user interactions or have a complicated UI may not work well.

In addition, some of the Mobile XML tags do not make sense for ASK and one should be aware of the specific semantics ASK has for the set of XML tags. Since ASK do not assume any sort of client side browsing capability, it is common that tags which assumes certain keys or actions on the device are not appropriate for ASK. The following table lists all the tags for MobileXML, as well as their semantics in the context of ASK.

Table 10-6 Summary of semantics for MobileXML tags
Mobile XML Tag Semantics

SimpleAction (MobileXML)

Treated the same as the SimpleMenuItem and SimpleHref. Each SimpleMenuItem, SimpleHref or SimpleAction will be prefixed with a number in the device result for async user to make selection.

SimpleAudio (MobileXML)

Ignored--not applicable to async devices.

SimpleBind (MobileXML)

Ignored--not applicable to async devices.

SimpleBreak

A new line is created on the page.

SimpleCache (MobileXML)

Ignored--not applicable to async devices.

SimpleCase (MobileXML)

Ignored --not applicable to async devices.

SimpleCatch (MobileXML)

Ignored-- not applicable to async devices.

SimpleCol

Output the text.

SimpleContainer

Processed--no output is generated.

SimpleDefault (MobileXML)

Ignored--not applicable to async devices.

SimpleDisconnect (MobileXML)

Ignored--not applicable to async devices.

SimpleDisplay (MobileXML)

Ignored--not applicable to async devices.

SimpleDTMF (MobileXML)

Ignored--not applicable to async devices.

SimpleEM (MobileXML)

Output the text.

SimpleEvent (MobileXML)

Ignored--not applicable to async devices.

SimpleExit (MobileXML)

Ignored--not applicable to async devices.

SimpleFinish (MobileXML)

Ignore--not applicable to async devices.

SimpleFooter (MobileXML)

Ignored.

SimpleForm

The form state is maintained in the server so the parameters issued by the user can be paired with their corresponding keys.

SimpleFormItem

The item text is printed on the returned page. User fills the corresponding item values in the same sequence as the item presented on the page.

SimpleFormOption

A list of form options is printed on the returned page with a number prefixed each form option. The user can fill the select item by giving either the prefix number or the option text. For example, a select item of 'State' should contain the option, '1 AL, 2 CA, 3 UT...'. The user can supply the value of '2' or 'CA' to select the option 'CA'. Only Radio box (single selection) is supported on the version.

SimpleFormSelect

Output the text.

SimpleGo (MobileXML)

Ignored--not applicable to async devices.

SimpleGrammar (MobileXML)

Ignored

SimpleHeader (MobileXML)

Ignored.

SimpleHelp

Output the text.

SimpleHref

This is treated the same as SimpleMenuItem. All the SimpleMenuItem is prefixed with a number so the user is able to select the item by responding with the corresponding number.

SimpleImage

Ignored; not applicable to ASK.

SimpleKey (MobileXML)

Ignored--not applicable to async devices.

SimpleMatch(MobileXML)

Ignored--not applicable to async devices.

SimpleMenu

A new line is created on the page. The menu state is maintained in the server.

SimpleMenuItem

The value of the menu item is printed on the returned page with a number prefix to identify the menu item. The target url and the number prefix is stored in the server so the url can be retrieved after the user makes the selection.

SimpleMenuItemField (MobileXML)

Output the text.

SimpleMeta

Ignored--not applicable to async devices.

SimpleMItem(MobileXML)

Ignored--not applicable to async devices.

SimpleName (MobileXML)

Ignored--not applicable to async devices.

SimpleOptGroup (MobileXML)

Ignored--not applicable to async devices.

SimplePrev (MobileXML)

Ignored--not applicable to async devices.

SimpleProperty (MobileXML)

Ignored.

SimpleRefresh (MobileXML)

Ignored--not applicable to async devices.

SimpleReprompt (MobileXML)

Ignored--not applicable to async devices.

SimpleResult

Processed--no output is generated

SimpleRow

Print a new line to the returned page.

SimpleSpeech (MobileXML)

Ignored--not applicable to async devices.

SimpleStrong (MobileXML)

Output the text

SimpleTable

No op

SimpleTableBody

Output new Line

SimpleTableHeader

Output a new line.

SimpleTask (MobileXML)

Ignored--not applicable to async devices.

SimpleText

Print a new line on the returned page.

SimpleTextItem

Output the text.

SimpleTimer

Ignored--not applicable to async devices.

SimpleTitle (MobileXML)

Output the text.

SimpleValue (MobileXML)

Ignored--not applicable to async devices.

10.6 Runtime and Data Model APIs

This section is for advanced users.

10.6.1 Oracle9iAS Wireless Runtime

Oracle9iAS Wireless runtime layer is a servlet in the OC4J servlet container. Oracle9iAS Wireless runtime processes requests from Hypertext Transaction Protocol (HTTP) user agents, async user agents (such as SMS, e-mail, two-way pagers), and autonomous mobile agents, and invokes the services in the repository for these agents. It performs automatic session tracking and terminates the sessions when they expire after the maximum interval of inactivity or when the sessions are invalidated when the users log out from the Oracle9iAS Wireless.

10.6.1.1 Session Management

The Oracle9iAS Wireless runtime tracks the runtime session independently of the Servlet session, by rewriting every URLs with an added parameter "PAsid," which specifies the session id. The session tracking identifies that a sequence of requests are submitted by the same device. The runtime session contains the user information, authentication contexts, adapter contexts, runtime contexts, URL caches, and other states essential for the context sensitive services.

WAP 2.0 devices that implement the WAP HTTP State Management Specification (http://www.wapforum.org/) can support cookies for session management. Most of the commercial WAP gateways manage persistent cookies on behalf of the devices. If the device or gateway does not support cookies, the OC4J servlet container falls back to URL rewriting for session tracking. Since the Oracle9iAS Wireless runtime also tracks the session, it is possible for more than one runtime session to be bound to a single servlet session. For example, two Netscape browsers on the same client PC can open two independent runtime sessions although the browsers share the same servlet session because of the shared cookie repository.

By default, the binding to the Servlet session is enabled and is necessary for the OC4J load balancing and fail over facility. The runtime session states are replicated to other OC4J instances in the "island" so that the device requests can be redirected to another OC4J instance in the island when the first instance fails. The runtime sessions that are bound to the servlet sessions are invalidated when the servlet sessions expire.

The session binding from the runtime session to Servlet session can be disabled by the parameter setting "enable.http.session.binding=false" in the System.properties file. Without binding to the servlet sessions, the runtime sessions are expired when the sessions remain idle for more than what is specified by the "wireless.session.expiration.time" parameter in the site configuration.

Every request from the device is serviced within the context of a valid runtime session. The requests from anonymous devices are also tracked and assigned to individual runtime sessions although the owners of the sessions are the same Guest user, which is an anonymous user. The Oracle9iAS Wireless runtime automatically provisions a "virtual" user in the Wireless repository for each device that can be consistently identified, using the identifiers available in the devices. Runtime sessions for virtual users are opened whenever the device identifiers are present in the requests. The device identifiers may be based on native device identifiers such as the Mobile Identification Number (MIN), Mobile Subscriber ISDN (MSISDN), Ipv6 Address, Electronic Serial Number (ESN), etc. The device identifiers may be also provisioned into the device by the WAP gateway. The WAP Client ID Specification (http://www.wapforum.org/) defines a standard scheme for supporting the device identifiers. If no device identifiers are supplied in the request, the Oracle9iAS Wireless runtime provisions the device identifiers into the devices using the persistent cookies whenever possible.

The Oracle9iAS Wireless runtime uses the device identifiers only to facilitate personalization under the virtual user. The runtime sessions opened under the virtual users have access to the information such as personalized presets and customization profiles in the repository. The device identifier also enables the device to reconnect to the same runtime session for the user, as long as the session has not expired. The device identifiers add robustness to the session management for Oracle9iAS Wireless, enabling continuity of the service in the face of intermittent connection losses. The users may also make telephone calls in between connections to the Oracle9iAS Wireless without losing their contexts.

Device identifiers are not a mean for authentication. Although the runtime sessions for the virtual users are not authenticated, it does not prevent the users from accessing their personalized portals. The users may establish authenticated sessions only if they register with the Oracle9iAS Wireless. The user can supply the user name and password during the registration. The user's personalization profiles and presets are still available to the user after the user becomes registered. The advantages of the registration include the authentication process that gives access to the secured services, such as the e-Wallets and financial transaction services.

The application programs for the services that require the authenticated sessions must add the "PAlogin=true" parameter in the URLs. When the Oracle9iAS Wireless runtime detects the PAlogin=true parameter among the URL parameters in the request for a service, the runtime tries to authenticate the user if the runtime session is not already authenticated. The authentication process, which typically involves the user supplying the user name and password to the Oracle9iAS Wireless Single Sign On (SSO) Server, is performed before the runtime invokes the service being requested. See Section 10.6.2.15, "User-Defined Hooks Examples" for how the folder renderer service can be used to prepare the URLs with "PAlogin" parameter for the secured services in a folder. After the "PAlogin" parameter invokes the authentication process, the application programs for secured services still have the responsibility to check that the session is authenticated. The applications that has direct access to the Oracle9iAS Wireless runtime objects can use isUserAuthenticated() method in oracle.panama.rt.Session interface. Applications written for the HttpAdapters can get the information from the Http header attribute "x-oracle-user.authkind" which has the values "authenticated" or "unauthenticated."

In addition, the applications can also check if the session is secured by the SSL, TLS, or WTLS channels. The application that has direct access to the Oracle9iAS Wireless runtime objects can use isSecure() method in the oracle.panama.rt.Request interface. Applications written for the HttpAdapters can get the isSecure() condition through the HTTP header attribute "x-oracle-device.secure," which has the values "true" or "false."

The authorization for access to a service is performed for each request for all authenticated or unauthenticated sessions. The authorization makes sure that the session user has the privilege to access the service. The default authorization policy does not differentiate whether the session is authenticated or unauthenticated. The unauthenticated sessions of a "virtual" or "registered" user has as much visibility as the authenticated sessions. It is therefore critical for the applications to apply the "PAlogin" parameter to enforce the authentication.

10.6.1.2 Virtual User Concept

The Oracle9iAS Wireless runtime automatically provisions "virtual" users in the Wireless repository for the devices that can be consistently identified, using the identifiers available in the devices. The virtual user option gives the device owners immediate access to the personalization features of the portal, which enhance the user experience. It automates the provisioning process for the carrier and enterprise portal administrators using the emerging WAP Client ID standards.

The device owners can register with Oracle9iAS Wireless to gain access to secured services through authentication. The registration can be done from the setup menus by the device owner. This self-provisioning registration feature further simplifies the administration tasks. The devices with the virtual user support let the registered users connect to Oracle9iAS Wireless and access the personalized services without signing on to the system until they are requested by the secured services to authenticate. The virtual user feature not only improves the accessibility of the portal but also enhances the data mining capability of portal operators since the activities of the devices can be identified with virtual identities.

The virtual user feature can be disabled by the site wide configuration parameter setting "wireless.virtualuser.enabled=false." This property can be modified by the Enable Virtual User option in System Manager>Site>User Provisioning control panel. If the virtual user feature is disabled or if the device does not support device identifier, then the session is opened under the "Guest" user, which must be provisioned in the repository. The Oracle9iAS Wireless bootstrap repository includes the anonymous user "Guest."

Applications that have direct access to the Oracle9iAS runtime objects can check the value of oracle.panama.model.UserType returned by the getUserType() method in oracle.panama.model.User. The User of the runtime session can be retrieved from the getUser() method in oracle.panama.rt.Session. Applications that are written for the HttpAdapter can get the user type information from the HTTP header attribute "x-oracle-user.userkind." The possible values of this attribute are "anonymous," "virtual," or "registered."

10.6.1.3 Runtime API

During the request execution, the Oracle9iAS Wireless runtime dispatches the authentication, authorization, device identification, location acquisition, data logging and other business logics to the respective plug-in modules.

Oracle9iAS Wireless Runtime API provides the Java interfaces to examine the runtime execution states, monitor the runtime execution behavior, and augment the default execution semantics. The Runtime API consists of four Java packages:

These four packages are included in the wireless.jar file. Make sure you have included wireless.jar in your Java classpath when you compile your Java application or plug-in modules that depend on the Runtime API.

10.6.1.4 Hooks

One set of the interfaces in the Runtime API, which is contained in the package oracle.panama.rt.hook, specifies the hooks that can be used by application developers for their customized plug-in modules. For example, the ListenerRegistrationHook registers listeners. Application developers can implement this hook interface for a customized listener registration module that lets the listeners selectively observe the event sources. A custom listener registration module may subscribe the listeners only to the requests for the billable services. Such a listener may add business rules to the runtime controllers.

The Runtime API consists of four public Java packages that provide interfaces for the following functions:

The new customized hook implementations, which implement the respective interfaces and the singleton pattern, are registered in the appropriate entries through System Manager>Site>Wireless Web Server>Hooks control panel in the Webtool.

10.6.1.5 Runtime Objects

The oracle.panama.rt package defines the core of the Runtime API. Adapters that conform to the runtime API must implement the oracle.panama.adapter.RuntimeAdapter interface. The classes that implement the RuntimeAdapter interface can use the Request, Response, Session, and ServiceContext interfaces in the oracle.panama.rt package.

The following sections describe the interfaces and classes in this package. The interfaces are:

The classes in this package are:

10.6.1.6 Request

A request object is used to invoke services. Generally, it defines which service to invoke and the particular parameters needed to invoke that service. It also defines the user, device, and other runtime contexts.

A listener can subscribe to events from a request.

The following methods in the Request interface allow you to access, replace, add, or remove the parameters that are associated with the request object:

Object getAttribute(AttributeCategory category, String name)
Object setAttribute(AttributeCategory category, String name, 
Object attribute) 

The methods access the name and value of the attributes, which can be user parameters, system parameters, or the contexts for adapters, hooks, and listeners.

There are three categories of attributes:

The most important attribute category for Request is PARAMETERS, which contains the query parameters submitted by the user. For HTTP user agents, Oracle9iAS Wireless runtime parses the URL query string to retrieve the parameters. The runtime agents or other internal clients can set these parameters programmatically. Since Oracle9iAS Wireless runtime may cache and rewrite the URL for HTTP user agents, some of the parameters are maintained in the URL cache for the user. Oracle9iAS Wireless runtime may have to parse both the query strings from the HTTP request and the URL cache to build a complete list of query parameters.

Step 2 in Section 10.6.2.1, "Case: A Request Involving Session Establishment and Authentication" shows that each time a new request object is created, Oracle9iAS Wireless runtime passes the request object to the ListenerRegistrationHook to let the hook register listeners.

The following table describes the names of the system-defined parameters which are part of the PARAMETERS AttributeCategory in Request. The left column in the table shows the Java constants that you can use to retrieve the value of the parameter from the request object.

The Mobile XML results can contain the runtime variables, (composed from the names of the parameters) by appending two underscore characters (__) before and after the parameter name. These runtime variables in the Mobile XML results are "place holders" which are replaced by the values of the parameters during the post processing phase (Step 25 in Section 10.6.2.1, "Case: A Request Involving Session Establishment and Authentication") before the final result is returned to the requester.

Table 10-7 System Defined Request Parameters
Java Program Constants Representing the Name of the Parameter in the Request Object The Name of the Parameter in the Request Object Description

Request.USER_NAME

"PAuserid"

Deprecated

Request.PASSWORD

"PApassword"

Deprecated

Request.EFFECTIVE_USER_NAME

"PAeffuserid"

The name of the effective user.

Request.SERVICE_OID

"PAoid"

The object id of the requested service.

Request.SERVICE_PATH

"PAservicepath"

The path of the requested service in the repository.

Request.SESSION_ID

"PAsid"

The session id for tracking user sessions.

Request.REQUEST_LANDMARK

"PArlmk"

The landmark setting for the current request.

Request.SESSION_LANDMARK

"PAslmk"

The landmark setting for the current session.

Request.LOGOFF

"PAlogoff"

The request to log off and invalidate the session.

Request.LOGIN

"PAlogin"

The authentication request.

Request.SESSION_HOME

"PAhome"

The object id of the service to be set as the session home.

Request.GO_SESSION_HOME

"PAgoHome"

A request parameter to invoke the session home service.

Request.REQUEST_USER_PROFILE

"PArprof"

The parameter used to specify the user profile for the request.

Request.SESSION_USER_PROFILE

"PAsprof"

The parameter used to specify the user profile for the session.

Line [4] in the following code example shows how the value of the PArlmk parameter can be retrieved from the Request object. Line [5] shows a statement for setting the Request parameter.

Example:

public void invoke(ServiceContext sc) { 
    . 
    Request request = sc.getRequest(); 
    String value = request.getParameter(Request.REQUEST_LANDMARK); [4]
    request.setParameter(Request.SESSION_LANDMARK, "Redwood City"); [5]
    . 
} 

10.6.1.7 Response

This interface represents the Response objects in Oracle9iAS Wireless runtime. A listener can subscribe to events from a Response. The Response object is the execution result of the prior Request object.

10.6.1.8 Session

This interface represents the session objects in Oracle9iAS Wireless runtime. A valid session is established after an anonymous user, virtual user, or registered user is identified for the session (refer to the Session Management Section above for the user identification process). Any request (or service invocation) can only be executed in a valid session context. A session can either expire after the session exceeds the maximum interval of inactivity or get invalidated when the user requests an explicit log out. Developers can store the session-long information in the corresponding session object.

A listener can subscribe to events from a session.

Step 7 in Section 10.6.2.1, "Case: A Request Involving Session Establishment and Authentication" shows that each time a new session object is created, Oracle9iAS Wireless runtime passes the session object to the ListenerRegistrationHook to let the hook register listeners.

10.6.1.9 ServiceContext

A ServiceContext provides the service request context for a valid and authorized request. A new ServiceContext object is created for each validated request. The ServiceContext stores the input parameters, output parameters, and Mobile XML results. The associated request and session can be accessed from the ServiceContext object.

The Mobile XML result can contain the system defined ServiceContext parameters using the runtime variables as "place holders," which are substituted with values during the post processing phase (Step 25 in Section 10.6.2.1, "Case: A Request Involving Session Establishment and Authentication") before the final result is returned to the requester.

Runtime variables are composed from the names of the parameters, by appending two underscores (__) before and after the parameter name.

Example:

Mobile XML results can contain runtime variables as follows:

target="___REQUEST_NAME__?___SESSION__&amp; PAoid=__PAoid__"

Given the variables above and if the following three conditions exist in the ServiceContext:

Then after the substitution of the runtime variables, the result becomes:

target="/ptg/rm?PAsid=ukAj6hH&amp;PAoid=254"

All the input parameters, output parameters, and Mobile XML result in the ServiceContext are externalized as an XML document.

This XML document is the input document for the transformers. The XSLT stylesheets for the transformers must be written against the DTD for the ServiceContext's XML document.

The following table describes the system-defined ServiceContext parameters which are found among the ServiceContext arguments. The left column in the table shows the Java program constants that represent the names of the parameters in the ServiceContext object.

Table 10-8 The System Defined ServiceContext Parameters
Java Program Constants Representing the Name of the Parameter in the ServiceContext The Name of the Parameter in the ServiceContext Object Description

ServiceContext.DEVICE

"_LOGICAL_DEVICE'

The name of the device model.

ServiceContext.REQUEST_ NAME

"_REQUEST_NAME"

The URI of the servlet.

For example, if the URL is http://www.oracle.com/ptg/r m? PAoid=100,

then the URI of the servlet is:

/ptg/rm.

ServiceContext.HTTP_REQUEST_NAME

"_HTTP_REQUEST_NAME"

The absolute URL of the portal servlet requested through the HTTP protocol.

ServiceContext.HTTPS_REQUEST_NAME

"_HTTPS_REQUEST_NAME"

The absolute URL of the portal servlet requested through the HTTPS protocol.

ServiceContext.ABS_REQUEST_NAME

"_ABS_REQUEST_NAME"

The page-name of the portal servlet requested, for example: http://www.oracle.com/ptg/rm

ServiceContext.SESSION

"_SESSION"

The SessionId URL

For example, PAsid=ukAj6hH

ServiceContext.INP_FIRST_ SERVICE_URL

"_SERVICE_URL"

The URL of the requested service in the repository

For example, /users/smith/news

ServiceContext.INP_FIRST_ SERVICE_NAME

"_SERVICE_NAME"

The name of the requested service in the repository

For example, news

ServiceContext.FIRST_ ACCEPT_LANG

"_FirstAcceptLanguage"

The first language in the list of accepted languages.

ServiceContext.USER

"_User"

The effective user, which may be the authenticated user.

ServiceContext.USER_ LANGUAGE

"_UserLanguage"

The user's preferred language; it should be one of the user agent's accepted languages.

ServiceContext.LONGITUDE

"_Longitude"

The current longitude location.

ServiceContext.LATITUDE

"_Latitude"

The current latitude location.

ServiceContext.SCREEN_ COLS

"_ScreenColumns"

The number of columns that are displayed.

ServiceContext.SCREEN_ ROWS

"_ScreenRows"

The number of rows that are displayed.

ServiceContext.SCREEN_ WIDTH

"_ScreenWidth"

The width of the display.

ServiceContext.SCREEN_ HEIGHT

"_ScreenHeigth"

The height of the display.

ServiceContext.USER_ AGENT

"User-Agent"

The type of the user agent that is obtained from the HTTP header.

ServiceContext.ACCEPT_ LANG

"Accept-Language"

The list of the languages that are accepted by the user agent.

ServiceContext.COUNTRY

"_Country"

The country that contains the current location.

ServiceContext.STATE

"_State"

The state that contains the current location.

ServiceContext.POSTALCODE

"_Postalcode"

The postal area that contains the current location.

ServiceContext.DEVICE_CATEGORY

"_DeviceCategory"

The category of the device, possible values are

"voice"

"microbrowser"

"pdabrowser"

"pcbrowser"

"micromessenger"

"messenger"

ServiceContext.SOFT_KEYS

"_SoftKeys"

The softkeys supported by the device.

ServiceContext.IMAGE_PREFERENCES

"_ImagePreferences"

The image preferences of the device.

ServiceContext.MAX_DOC_SIZE

"_MaxDocSize"

The maximum size of the document handled by the device.

In the following code fragment example, line [5] shows that the Java program constants can be used to refer to the parameters. Line [6] shows that the name of the parameter can be spelled out (case sensitive). The parameter "Accept_encoding" is not one of the parameters in the above table. Line [7] shows that the parameters from the request object are also available among the ServiceContext arguments. However, the ServiceContext parameters are not part of the PARAMETERS attribute category in Request objects, and are not accessible from the Request objects. They can be accessed only from the ServiceContext arguments as shown in the following example.

Example:

public void invoke(ServiceContext sc) { 
    . 
    Arguments args = sc.getInputArguments(); 
    .
    String language = args.getInputValue(ServiceContext.USER_LANGUAGE);[5]
    String encoding = args.getInputValue("Accept_encoding"); [6]
    String landmark = args.getInputValue(Request.REQUEST_LANDMARK); [7]
} 

The Java program constants represent the names of the tags in the XML documents for the ServiceContext. The "ServiceRequest" tag is the root element of the ServiceContext. The "Result" tag contains the Mobile XML result. The "Arguments" tag is a sibling of the "Result" tag; it contains all input and output arguments.

Table 10-9 The XML Tag Names for ServiceContext and Results
Java Program Constants Representing the Names of the XML Tags in the ServiceContext The Name of the XML Tag Description

ServiceContext.SERVICE_REQUEST

"ServiceRequest"

XML element containing service context

ServiceContext.RESULT

"Result"

XML element containing the Mobile XML result.

The following example of the XML document for a ServiceContext shows the "ServiceRequest" tag as the root element of the ServiceContext. Several of these input arguments (tags 21 to 28) are obtained from the HTTP header attributes.

Example of the XML document for a ServiceContext:

1. <ServiceRequest>
       a. <Arguments>
               i. <Inputs>
                    1. <PAsid type="SingleLine" 
usage="true">BVlcv</PAsid> 2. <PAoid type="SingleLine"
usage="true">244</PAoid> 3. <PAservlet type="SingleLine"
usage="true">rm</PAservlet> 4. <PAdebug type="SingleLine"
usage="true">1</PAdebug> 5. <_SERVICE_NAME type="SingleLine"
usage="true">Employee</_SERVICE_NAME> 6. <_SERVICE_NAME_ENC type="SingleLine"usage="true">
Employees</_SERVICE_NAME_ENC> 7. <_SERVICE_URL type="SingleLine" usage="true">
/home/Employees</_SERVICE_URL> 8. <_SERVICE_URL_ENC type="SingleLine" usage="true">
/home/Employees</_SERVICE_URL_ENC> 9. <_LOGICAL_DEVICE type="SingleLine" usage="true">HTML
</_LOGICAL_DEVICE> 10. <_SESSION type="SingleLine" usage="true">PAsid=BVlcv
</_SESSION> 11. <_REQUEST_NAME type="SingleLine" usage="true">/p2g/rm
</_REQUEST_NAME> 12. <_ScreenColumns type="SingleLine" usage="true">0
</_ScreenColumns> 13. <_ScreenRows type="SingleLine" usage="true">0
</_ScreenRows> 14. <_ScreenWidth type="SingleLine" usage="true">0
</_ScreenWidth> 15. <_ScreenHeigth type="SingleLine" usage="true">0
</_ScreenHeigth> 16. <_User type="SingleLine"
usage="true">user1</_User> 17. <_UserLanguage type="SingleLine"
usage="true"/> 18. <_FirstAcceptLanguage type="SingleLine" usage="true">ja
</_FirstAcceptLanguage> 19. <_Longitude type="SingleLine"
usage="true"/> 20. <_Latitude type="SingleLine"
usage="true"/> 21. <accept type="SingleLine" usage="true">image/gif,
image/x-xbitmap, image/jpeg,
image/pjpeg, image/png, */*</accept> 22. <accept-charset type="SingleLine" usage="true">
iso-8859-1,*,utf-8</accept-charset> 23. <accept-encoding type="SingleLine"
usage="true">gzip</accept-encoding> 24. <host type="SingleLine"
usage="true">localhost</host> 25. <cookie type="SingleLine" usage="true">
kurt=NTJCMUIzNzczQTA1QzBFRDAxNzY
3ODdBNEYxNTc0RkYwMDc1Rjc1MjFFU29ubnk=</cookie> 26. <accept-language type="SingleLine"
usage="true">ja,en</accept-language> 27. <connection type="SingleLine"
usage="true">Keep-Alive</connection> 28. <user-agent type="SingleLine"
usage="true">Mozilla/4.5
[en] (WinNT; U)</user-agent> ii. </Inputs> b. </Arguments> c. <Result> <SimpleResult> 1. <SimpleContainer name="Services"> a. <SimpleMenu name="alias" title="Employees"> b. <SimpleMenuItem
target="/p2g/rm?PAsid=BVlcv&#38;
PAckey=6!">Scott</SimpleMenuItem> c. <SimpleMenuItem
target="/p2g/rm?PAsid=BVlcv&#38;
PAckey=7!">Tiger</SimpleMenuItem> d. </SimpleMenu> 2. </SimpleContainer> </SimpleResult> d. </Result> 2.</ServiceRequest>

10.6.1.10 ManagedContext

In many situations, the customized hooks, listeners, and adapters require session-long, application-defined context information to be stored in the session object, so that subsequent calls or requests can access the context information. Furthermore, these application contexts may contain system resources that should be freed when the session is closed.

The application-defined context must implement the ManagedContext interface and provide customized implementation for the invalidate method. The customized hooks, listeners, and adapters can register the session-long application context object with the session through the setManagedContext method. The invalidate method will be called by Oracle9iAS Wireless runtime when the session terminates.

10.6.1.11 RequestFactory

The RequestFactory class is defined in the oracle.panama.rt package. The RequestFactory provides the APIs to programmatically create request objects to be executed. The RequestFactory creates the request objects that, when executed, initiate the runtime controllers to process the service requests by invoking the necessary business processes, such as session management, authentication, authorization, service invocation, and result transformation.

10.6.1.12 SessionHolder

The SessionHolder class is defined in the oracle.panama.rt. package. The SessionHolder is the serializable representation of the runtime Session. It is used to bind the runtime Session to the servlet session as required for the OC4J cluster configuration. Only serializable objects placed in the runtime session and the servlet session are replicated among other OC4J instances in the island. The portal developers can get an instance of this serializable object using the getSessionHolder() method in the Session.

10.6.1.13 Case 1: Application of the RequestFactory Pattern in the HTTP Servlet

This case uses the ParmImpl servlet to illustrate the RequestFactory pattern. The following code example is the doGet() method of the ParmImpl servlet:


 public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException { Request req = RequestFactory.createRequest(request, response); [3] if (req == null) { return; } try { Response resp = req.execute(); [8] } catch (Exception ex) { } finally { req.invalidate(); [11] } }

Line [3] in the above example illustrates the use of the static method createRequest(HttpServletRequest request, HttpServletResponse response) of RequestFactory to create a Request object.

When the Request object is executed in line [8], it returns a Response object.

The Java code in the above example does not include reading or writing of the content in the Response object because the runtime controller directly transfers the content to the HttpServletResponse object.

The execute()method of the Request object starts a control flow which performs the following sequence of processes:

  1. Assign a session to the request.

  2. Parse the URL parameters in the HttpServletRequest.

  3. Authenticate the user if the user credentials are provided among the parameters.

  4. Authorize the requested service.

  5. Invoke the service.

  6. Transform the XML result from the service invocation.

  7. Convert the final XML result to a string.

  8. Set the response string in the HttpServletResponse.

  9. Return from the servlet.

Line [11] in the code example invalidates the completed Request, thereby freeing all the resources associated with the request object.

10.6.1.14 Case 2: Application of the RequestFactory Pattern in the Runtime Agent

The following case illustrates how a runtime agent uses the RequestFactory pattern to request services through the Oracle9iAS Wireless runtime.

import oracle.panama.rt.RequestFactory;
import oracle.panama.rt.Request;
import oracle.panama.rt.Response;
import oracle.panama.rt.Session;
import oracle.panama.rt.ServiceContext;
.
import oracle.panama.model.MetaLocator;
import oracle.panama.model.ModelServices;
import oracle.panama.model.Service;
import oracle.panama.model.User;
import oracle.panama.model.AlertAddress;
.
.
.
 
Session signon(String user, String password) throws PanamaException {
     Request request = RequestFactory.createRequest(user, password);
     request.validate();[17]
     Session session = request.getSession();[18]
     request.invalidate();
     return session;
}
 
String invokeService(Session session, Service service, User user,
AlertAddress address, String symbol) { Request req; Response resp; ServiceContext sc; String content = null; try { req = RequestFactory.createRequest(session, service,
user, address);[28] if (req == null) { return null; } try { req.setParameter("TickerSymbol", symbol); sc = req.validate(); resp = req.execute(); if (sc.isAnyResultPresent()) { content = resp.getContent(); } } catch (Exception ex) { } finally { req.invalidate(); } return content; } } String userName = "orcladmin"; String password = "manager"; String effectiveUserName = "Guest"; String symbols[] = { "orcl", "sunw", "csco" }; void main() { ModelServices models = MetaLocator.getInstance().getModelServices(); User user = models.lookupUser(effectiveUserName); Service service = models.lookupService("YahooQuote"); AlertAddress[] addresses = user.getAddresses(); Session session = signon(userName, password); for (int i = 0; i < symbols.length(); i++) { . . String content = invokeService(session, service, user, addresses[0],
symbol[i]); . . } }

The signon() method signs on the user to the Oracle9iAS Wireless runtime. When the Request object is validated in line [17], the user name and password credentials are used to authenticate the user. Since no service is invoked during the sign-on request, the code example shows that the Request object is not executed.

If there is no exception after validation, the authenticated session is retrieved from the Request object in line [18].

The Session object is used in the invokeService() method for subsequent requests to the runtime. Line [28] in the invokeService() method creates a Request object for an effective user and a specified service. For this operation to succeed, the authenticated user must have administrative privileges over the effective user account.

The address parameter identifies the target device model for the Oracle9iAS Wireless runtime to format the content in the appropriate markup language.

The main routine in the above code example illustrates how it iteratively invokes the service each time with a different input parameter. The contents returned by each service request can be combined into a larger document and sent to the user.

10.6.1.15 Event, Listener

During the establishing of a session, the expiration of a session, or the processing of a request, Runtime can generate a sequence of events to signal the execution progress if any interested listener is registered with these objects. Generally, listeners should not be intrusive to the runtime execution. They should monitor the runtime progress instead of altering its execution behavior. The possible applications for the event package can be a logger, a billing procedure, or a performance monitor tool. The oracle.panama.rt.event package defines the Listener and Event API.

Listeners listen to Events. Listener and Event form an important design pattern in which the Listener is an observer. Three types of listeners are defined:

The ListenerRegistrationHook subscribes the listeners to receive events from the subject, such as Request, Response, or Session.

10.6.1.16 Implementing the RequestListener Interface

The implementor of oracle.panama.rt.event.RequestListener can receive any of the following events:

The timing sequence regarding when the event is generated is discussed in Section 10.6.2, "Reference Model". However, not all the Request-related events will be generated. Which specific Request-related event will be generated is controlled by the enent mask in System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel in the Webtool.

For example, if you want to have your RequestListener receive the request begin event, you should set the Enable 'request begin' Event to true in the System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel in the Webtool. The site configuration property names are:

wireless.http.event.beforeRequest
wireless.http.event.requestBegin
wireless.http.event.requestEnd
wireless.http.event.serviceBegin
wireless.http.event.serviceEnd
wireless.http.event.transformBegin
wireless.http.event.transformEnd
wireless.http.event.requestError
wireless.http.event.afterRequest

Step 11 in Section 10.6.2.1, "Case: A Request Involving Session Establishment and Authentication" indicates that the RequestListener can intercept the input parameters during the requestBegin(RequestEvent) and apply additional business rules to the request parameters before service invocation.

10.6.1.17 Implementing the ResponseListener Interface

The implementor of oracle.panama.rt.event.ResponseListener can receive the Response-related event. The only possible Response-related event is response error. If you want Oracle9iAS Wireless runtime to have your ResponseListener receive the response error event, you should set the Enable 'response error' Event option to true in System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel in the Webtool. The site configuration property name is: wireless.http.event.responseError

10.6.1.18 Implementing the SessionListener Interface

The implementor of oracle.panama.rt.event.SessionListener can receive the Session life cycle events. The possible Session events include:

The timing sequence regarding when the event is generated is discussed in Section 10.6.2, "Reference Model". However not all the Session events will be generated. Which specific Session event will be generated is controlled by the event masks in the System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel in the Webtool.

For example, if you want to have your SessionListener receive the session begin event, you should set the Enable 'session begin' Event option to true in the System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel in the Webtool. The site configuration property names are:

wireless.http.event.beforeSession
wireless.http.event.sessionBegin
wireless.http.event.sessionAuthenticated
wireless.http.event.sessionEnd
wireless.http.event.afterSession

10.6.1.19 Guidelines

The following guidelines describe how to set up the customized Event Listener:

  1. Implement the RequestListener, ResponseListener, or SessionListener interface.

  2. Compile the new Java source files from Step 1 with the wireless.jar file in the classpath.

  3. Modify the event mask entries in the System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel to enable the generation of specific events.

  4. Specify the class names for the RequestListener, ResponseListener, and SessionListener in the System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel of webtool. The site configuration property names are:

    wireless.http.locator.combined.listener.classes
    wireless.http.locator.session.listener.classes
    wireless.http.locator.response.listener.classes
    wireless.http.locator.request.listener.classes
    
    
  5. Restart the Oracle9iAS Wireless instance.

Any of the event listeners may raise the AbortServiceException to signal the runtime controller to reject the request, but this veto signal is effective only if it is raised during one of the following events when the service is yet to be invoked:

The listeners may raise the AbortServiceException during the serviceEnd(), transformBegin(), and transformEnd() events to refuse the service's content to the user, although any durable effect of the service invocation cannot be rolled back.

The sessionEnd(), afterSession(), requestEnd(), and afterRequest() methods should not raise the AbortServiceException.

A listener that implements the Request, Response, and Session listener interfaces is described in the code example in Section 10.6.1.16, "Implementing the RequestListener Interface". The listener in this example listens to all Request, Response, and Session events. This listener logs the response time, service time, and transform time of the requests.

The values placed in the event object persist through the life cycle of the event source and can be retrieved during subsequent events. Alternatively, the listener may place the values in the RUNTIME attribute category of the Request or Session objects. Both techniques allow the listeners to correlate and trace the events from individual event sources.

10.6.1.20 Hooks

The Oracle9iAS Wireless runtime specifies the hook interfaces for standard plug-in modules. The following sections describe the hooks in the order in which they are invoked by the runtime.

In the Oracle9iAS Wireless Runtime API, Hook and Policy form a chain of responsibility design pattern, within which Policy is the default implementation of Hook that can be delegated by the custom implementation.

The following table lists the Hooks and the default Policies that correspond to the hook interfaces:

Table 10-10 Classes that Implement the Default Policies
Hook Name Policy Name

AuthenticationHook

AuthenticationPolicy

AuthorizationHook

AuthorizationPolicy

CallerLocationHook

CallerLocationPolicy

DeviceIdentificationHook

DeviceIdentificationPolicy

FolderRendererHook

FolderRendererPolicy

HomeFolderSorterHook

HomeFolderSorterPolicy

ListenerRegistrationHook

ListenerRegistrationPolicy

LocationServiceVisibilityHook

LocationServiceVisibilityPolicy

MobileIdHook

MobileIdPolicy

NormalizeAddressHook

NormalizeAddressPolicy

PostProcessorHook

PreProcessorHook

ServiceVisibilityHook

ServiceVisibilityPolicy

SessionIdHook

SessionIdPolicy

SignOffHook

SignOffPolicy

SignOnPagesHook

SignOnPagesPolicy

10.6.1.21 The ListenerRegistrationHook

Steps 2 and 7 in Section 10.6.2.1, "Case: A Request Involving Session Establishment and Authentication" show that each time a new Session or Request object is created, runtime passes the Session or Request object to the ListenerRegistrationHook to let the hook register listeners. The listener registration module can be customized to let the listeners selectively observe the event sources.

For example, a custom listener registration policy may subscribe the listeners only to the requests for the billable services. Such a listener may add business rules to the runtime controller.

10.6.1.22 The SessionIDHook

The Oracle9iAS Wireless runtime uses the SessionIdHook to uniquely identify each new session it creates with a Session id. This Session id is used in the URLs for session tracking. It is important for custom Session id modules to generate long Session id strings. Longer Session id strings are less vulnerable to attack.

10.6.1.23 DeviceIdentificationHook

Runtime uses the DeviceIdentificationHook to determine the device model for the user agent. For HTTP clients, the user-agent type is the value of the "User-Agent" attribute in the HTTP header. The DeviceIdentificationHook can implement robust determination of the type of user agents for cases where the user-agent attribute is not supplied in the request.

This hook provides a mapping of the user-agent type to the device model. Runtime agents can specify the Device in the RequestFactory method. If the Device is specified, the runtime controller will not invoke the DeviceIdentificationHook.

Although customization and extensions are supported, the default device identification policy is fully functional.

10.6.1.24 AuthenticationHook

The Oracle9iAS Wireless runtime dispatches the authentication operations to the authentication module that implements the AuthenticationHook. The AuthenticationPolicy provides a public interface to the default authentication policy in Runtime. The default policy uses the user name and password credentials in the Oracle9iAS Wireless Single Sign On (SSO) server.

A different implementation of the AuthenticationHook using an external module may use any custom authentication scheme to validate the user. The external authentication module may optionally fail over to the default authentication policy.

The AuthenticationHook returns the AuthenticationContext if the authentication succeeds. Otherwise, the hook raises the AuthenticationException. The AuthenticationContext that is returned by the authentication module specifies the User object for the Session. This User object may be located in the Oracle9iAS Wireless repository or provisioned by the authentication module on demand.

The AuthenticationContext is passed to the AuthorizationHook for service authorization. The String getAuthenticationType() method in Request can provide the name of the authentication scheme used by the plug-in authentication module, which extends the "BASIC", "DIGEST", or "SSL" authentication schemes supported by the javax.servlet.http package.

Runtime provides infrastructure support to mix and match different authentication, authorization, and provisioning policies by delegating the authentication operation to the AuthenticationHook and the authorization operation to the AuthorizationHook.

Runtime places the AuthenticationContext, which is returned by the AuthenticationHook, in the Session. The AuthenticationContext is passed only to the AuthorizationHook and is not accessible through the public interface.

The AuthenticationHook may either create the user or look up the user in the repository. If the user is provisioned by the external accounting system, the AuthenticationHook will also provision the home folder and group for the user. The user, which is returned through the AuthenticationContext, becomes the authenticated user of the session. Although large-scale customization and extension efforts are supported, the built-in authentication and authorization policies are fully functional.

10.6.1.25 SignOnPagesHook

In the Oracle9iAS Wireless environment, the sign on pages are generated by the SSO server. The SignOnPagesHook is used primarily for authentication against the stand alone repository. This hook is not shown in the execution because it is invoked only when the AuthenticationPolicy raises the AuthenticationFailOverException.

When the SignOnPagesHook generates the sign-on page, the Oracle9iAS Wireless runtime sends that sign-on page to the user, who submits the user's name and password for authentication by the default authentication module in stand alone mode (without SSO).

10.6.1.26 MobileIDHook

Runtime invokes the MobileIDHook to determine the mobile client ID.

The mobile identifier may be supplied by the external accounting system, by one of the fields (such as, the mobile ID field or external ID field) of the user object in the repository, or by one of the attributes in the HTTP header. The HTTP header attribute names can be specified by the "wireless.mobile.id.request.parameter.name" through the System Configuration Webtool. This mobile id is placed in the authenticated session.

10.6.1.27 AuthorizationHook

The authentication operation is performed only one time to establish a session for the user. The authorization operation is performed for each request to the Oracle9iAS Wireless runtime.

The authorization module that implements the AuthorizationHook may use any custom authorization scheme. It is probable for the same party to implement both the AuthenticationHook and the AuthorizationHook. For example, in an environment that uses a pre-billing scheme, the AuthenticationHook provides the AuthenticationContext that indicates the user's prepaid level or type of service to the AuthorizationHook.

The external authorization module may optionally fail over to the default authorization policy by delegating to the AuthorizationPolicy provided in the public package. The default authorization policy authorizes the service using the visibility, validity, ownership, and group membership configuration in the repository.

10.6.1.28 CallerLocationHook

The CallerLocationHook provides the interface to acquire a caller's physical location in terms of latitude and longitude. The Oracle9iAS Wireless provides two different default implementations of the CallerLocationHook interface.

The oracle.panama.rt.common.CallerLocator class provides the simple implementation using the location marks. The location object is one way of specifying the longitude and latitude position. The user can change the location setting in the session through the URL parameter PAslmk. If the automatic location acquisition is disabled, the location setting in the session supplies the current position of the mobile device to the location-based services.

The oracle.panama.rt.common.LocAcq provides the automatic location acquisition implementation if the user specifies the appropriate privacy directive. If the automatic acquisition fails or is disabled through the Enable Mobile Positioning flag in the System Manager -> Site -> Location Management control panel of the webtool or by setting the "wireless.elocation.mp.enable" parameter in the Site Configuration parameter table, the prior location mark semantics will be applied.

See the oracle.panama.mp section for details on how to specify which mobile position server (either Ericsson or SignalSoft, or another customized server) is used to acquire the caller's location.

10.6.1.29 Service

Services are Oracle9iAS Wireless repository objects. A Master Service object contains a RuntimeAdapter, which is chief among plug-in components. Folders are a type of service used for organizing other folders and services in the repository. The following two hooks control how the content of a folder gets rendered:

The FolderRendererHook uses the LocationServiceVisibilityHook to render the contents of the folder. When the user first signs on to the system, runtime invokes the user's home folder. The built-in FolderRendererHook, accessible through the FolderRendererPolicy, combines the contents of the home folder with the folders and services from one or more of the user's groups. The LocationServiceVisibilityHook selects from the location-based subfolders in the folder for those whose regions intersect with the current position of the mobile device.

Each folder can be associated with a folder rendering service which provides customized view of the folder. The default folder rendering policy or the site wide customized folder rendering hook is used only if the folder does not have an associated rendering service, either assigned to it or inheritable from its parent folders.

10.6.1.30 PreProcessorHook, Transformer, and PostPorcessorHook

If the PreProcessorHook is specified, the Runtime invokes the PreProcessorHook to process the Mobile XML result from the service invocation. The Device's Transformer is applied to the result of the PreProcessorHook. If specified, the PostProcessorHook is invoked to process the markup page that is generated by the Device's Transformer.

10.6.2 Reference Model

This section describes the Oracle9iAS Wireless runtime, showing how the hooks and listeners participate in the processing of a service request -- in this case, the request involves authentication and session establishment.

The sequence in the model shows how a service in the repository is invoked after authentication. If no service is specified in the request, as is the case for sign-on pages, the service which is invoked is that of the user's home folder.

10.6.2.1 Case: A Request Involving Session Establishment and Authentication

This is a description of the flow in how runtime processes the events in a request that needs a new session and authentication. The numbers indicate the sequence of the actions in the runtime.

  1. createRequest(HttpServletRequest,HttpServletResponse)

    ParmImpl submits an HTTP request containing input parameters to the RequestFactory to create the Request object.

  2. registerRequestListeners(Request)

    Runtime passes the new request to the ListenerRegistrationHook to let it register listeners.

  3. beforeRequest(RequestEvent)

    The event source Request issues a notification to each of the RequestListeners, passing the RequestEvent object.

  4. execute()

    ParmImpl executes the newly created Request object, which starts the following sequence of activities within the runtime.

  5. createSessionId()

    Runtime dispatches to the SessionIdHook to create a new session id for the PAsid parameter.

  6. createSession()

    Runtime creates a new Session for the given session id.

  7. registerSessionListeners(Request,Session)

    Runtime passes the new Session to the ListenerRegistrationHook to let it register the session listeners.

  8. beforeSession(SessionEvent)

    The event source Session issues a notification to each of the SessionListeners, passing the SessionEvent object.

  9. findDeviceType(String)

    Runtime dispatches to the DeviceIdentificationHook to determine the device model.

  10. parseInputParameters()

    Runtime parses the URL in the HTTP request and extracts the input parameters.

  11. requestBegin(RequestEvent)

    The event source Request issues a notification to each of the RequestListeners, passing the RequestEvent object.

  12. authenticate(String,String,Request)

    Runtime dispatches to the AuthenticationHook to authenticate the user.

  13. getMobileId(Request,Session)

    Runtime dispatches to the MobileIdHook to obtain the mobile id of the user, which can be used by the CallerLocationHook.

  14. sessionBegin(SessionEvent)

    The event source Session issues a notification to each of the SessionListeners, passing the SessionEvent object.

  15. sessionAuthenticated(SessionEvent)

    The event source Session issues a notification to each of the SessionListeners, passing the SessionEvent object.

  16. getCurrentLocation(Request)

    Runtime dispatches to the CallerLocationHook to determine the location of the caller (mobile device).

  17. authorize(User,Service,Request,AutheticationContext)

    Runtime dispatches to the AuthorizationHook to authorize the requested service.

  18. serviceBegin(RequestEvent)

    The event source Request issues a notification to each of the RequestListeners, passing the RequestEvent object.

  19. invoke(ServiceContext)

    Runtime invokes the service in the repository, passing the ServiceContext object.

  20. serviceEnd(RequestEvent)

    The event source Request issues a notification to each of the RequestListeners, passing the RequestEvent object.

  21. transformBegin(RequestEvent)

    The event source Request issues a notification to each of the RequestListeners, passing the RequestEvent object.

  22. process(Request,Element)

    Runtime dispatches to the PreProcessorHook to process the SimpleResult output of the service.

  23. rewriteResultURLs(Element)

    Runtime replaces the original URL with an encoded URL that contains the PAsid and PAckey parameters for the session id and the URL cache key, respectively.

  24. transform(Element,LogicalDevice)

    Runtime invokes the device ResultTransformer to transform the SimpleResult to the device's markup language.

  25. process(String,Arguments,Device)

    Runtime invokes the PostProcessor to parse the content of the device markup page. The PostProcessor replaces the runtime variables (which are "place holders") with the values of the variables. For example, "PAsid=xyzw" replaces ___SESSION__.

  26. process(Request,Response,String)

    Runtime dispatches to the PostProcessorHook to process the device markup page to produce the final result.

  27. transformEnd(RequestEvent)

    The event source Request issues a notification to each of the RequestListeners, passing the RequestEvent object.

  28. writeContent()

    Runtime writes the content to the HTTPServletResponse.

  29. requestEnd(RequestEvent)

    The event source Request issues a notification to each of the RequestListeners.

  30. invalidate()

    ParmImpl invalidates the Request object.

  31. afterRequest(RequestEvent)

    The event source Request issues a final notification to the RequestListeners, passing the RequestEvent object.

10.6.2.2 System Parameters

There are two different kinds of system parameters: static and derived parameters. The following sections discuss these two types of system parameters.

10.6.2.3 Static System Parameters

The Mobile XML results can contain the runtime variables, (composed from the names of the parameters) by appending two underscore characters (__) before and after the parameter name. These runtime variables in the Mobile XML results are "place holders" which are replaced by the values of the parameters during the post processing phase (Step 25 in Section 10.6.2.1, "Case: A Request Involving Session Establishment and Authentication") before the final result is returned to the requester. The following table describes the system-defined ServiceContext parameters which are found among the ServiceContext arguments. The left column in the table shows the Java program constants that represent the names of the parameters in the ServiceContext object. You can access them in one of two ways:

The HTTP headers sent together with the HTTP service request invocation are also considered static parameters. However which HTTP header is present depends on the browser and the gateway. To find out which HTTP headers are present in a request, use the following:

Enumeration in_http_headers = Req.getHeaderAttributes() 

This returns an enumeration of present HTTP headers in the request.

You can retrieve the HTTP header's value by enumerating:

 while (in_http_headers.hasMoreElements())
 {
    String arg = (String) in_http_headers.nextElement();
    System.out.println(arg+"= "+ Reg.getParameter(arg));
}

10.6.2.4 Derived System Parameters

The second kind of system parameters is the derived parameters. A derived parameter's value is usually not present. To make its value present in the valid request object, do the following:

10.6.2.5 General Guidelines for User-Defined Listeners and Hook Implementation

Component developers can develop new types of runtime agents and adapters by using only the classes and interfaces in the public packages provided in the wireless.jar file.

The following steps describe how you provide your own implementation of listeners and hooks.

10.6.2.6 Implementing the Respective Interface

The user-defined listeners and hooks should implement the respective listener interface or the hook interface. For example, if you define your own AuthenticationHook, your new AuthenticationHook Java class should implement the oracle.panama.rt.hook.AuthenticationHook interface.

Furthermore, the new implementation should implement the following Singleton pattern:

class yourClass  implement Xhook  {
     public static Xhook getInstance() {   .... }
...
}

10.6.2.7 Compile Your Java Source

Make sure you have included the wireless.jar in your Java classpath during compilation.

10.6.2.8 Plug in Your Implementation through Property File

Set the corresponding entry in the System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel, or the System Manager -> Site -> Wireless Web Server -> Hooks control panel to specify the name of the class that provides the implementation.

The following table lists the property entry name in the System Manager -> Site -> Wireless Web Server -> Hooks control panel for each hook.

Table 10-12 Property Entry Names for Hooks
Hook Name Property Name

AuthenticationHook

wireless.http.locator.authentication.hook.class

AuthorizationHook

wireless.http.locator.authorization.hook.class

CallerLocationHook

wireless.http.locator.caller.location.hook.class

DeviceIdentificationHook

wireless.http.locator.device.identification.hook.class

FolderRendererHook

wireless.http.locator.folder.render.hook.class

HomeFolderSorterHook

wireless.http.locator.home.folder.sorter.hook.class

ListenerRegistrationHook

wireless.http.locator.listener.registration.hook.class

LocationServiceVisibilityHook

wireless.http.locator.service.visibility.hook.class

PostProcessorHook

wireless.http.locator.post.processor.hook.class

PreProcessorHook

wireless.http.locator.pre.processor.hook.class

ServiceVisibilityHook

wireless.http.locator.service.visibility.hook.class

SessionIdHook

wireless.http.locator.session.id.hook.class

SignOnPagesHook

wireless.http.locator.signon.pages.hook.class

MobileIdHook

wireless.http.locator.mobile.id.hook.class

NormalizeAddressHook

wireless.http.locator.normalizeaddress.hook.class

For example, if you provide your own implementation of the authentication hook, you should set the wireless.http.locator.authentication.hook.class in the System Manager -> Site -> Wireless Web Server -> Hooks control panel to <your class name>.

10.6.2.9 Tips and Hints

When implementing the new listeners, hooks, and adapters, consider also the following points:

10.6.2.10 Concurrent Requests

The Oracle9iAS Wireless runtime supports concurrent instances of requests from user agents through an HTTP connection. Concurrent requests are not permitted for the runtime agent that shares the same administrator session among different effective users. For this type of agent, the runtime serializes the requests under the same session. Concurrency is achieved by introducing more than one instance of the runtime agents, each with its own authenticated session.

10.6.2.11 Recursive Instances of Requests

The Oracle9iAS Wireless runtime supports recursive instances of requests under the same session. Recursive instances of requests may be issued by the plug-in components, for example, to recursively invoke all services under a folder.

10.6.2.12 Query Parameters

The Oracle9iAS Wireless runtime parses the URL query strings from HTTP user agents to retrieve query parameters. For other agents that do not use URL strings, the runtime lets the agents set the query parameters programmatically. The runtime allows the agents to specify the session, user, device, and service using objects instead of names.

10.6.2.13 Runtime Object References

This design constraint requires that plug-in components do not retain references to the runtime objects across invocations.

Plug-in components may execute under asynchronous threads; in this case, the synchronous methods in the components should make snapshots of the runtime objects before handing them to the asynchronous threads.

10.6.2.14 Thread-Safe and High-Concurrency

Since a single instance of the customized listeners and hooks is created according to the Singleton design pattern, the Java class should provide a thread-safe but very high concurrent implementation. Otherwise, the performance of the Oracle9iAS Wireless runtime can be significantly degraded.

10.6.2.15 User-Defined Hooks Examples

The following examples are available in the respective subdirectories under \sample.

The following examples illustrate how you can develop user-defined hooks:

10.6.2.16 Example 1

10.6.2.16.1 Changing the folder look and feel

The look and feel of folders in Oracle9iAS Wireless can be changed in the following ways:

10.6.2.16.2 Configuration parameters

The look and feel of the folder can be changed by modifying the following configuration parameters:

Table 10-13 Configuration parameters
Name type default Effect Notes

wireless.device.login.enable

boolean

true

Display `Login' link

Only displayed when user is not fully authenticated (guest or virtual user)

wireless.device.logout.enable

boolean

true

Display `Logoff' link

Only displayed when user is fully authenticated (explicitly logged in)

wireless.device.userinfo.enable

boolean

true

Display `Setup / User Info' link

wireless.device.customizeservice.enable

boolean

true

Display `Setup / Service' link

wireless.device.globalpreset.enable

boolean

true

Display `Setup / Presets' link

wireless.device.userprofile.enable

boolean

true

Display `Setup / User Profile' link

wireless.device.register.enable

boolean

true

Display `Register' link

Only displayed for guest or virtual user

wireless.device.help.enable

boolean

false

Display `Help' link

Help page can be configured using the wireless.device.help.url

configuration parameter

wireless.device.home.enable

boolean

true

Display `Home' link

10.6.2.16.3 FolderRendererService

Oracle9iAS Wireless also allows an arbitrary service to be run when accessing a folder. This service is attached to the folder using the service designer; please see the service designer documentation for details. The service that renders the folder can either be active for that folder only, or for the given folder and all its children subfolders. The latter is useful for cases such as when one is customizing the folder look and feel for a subtree of folders. Customizing all user home folders is a prime example. If you put all user home folders beneath the folder /Users Home/, the FolderRendererService can then be attached to the /Users Home/ folder, with recursive rendering turned on (see the webtool documentation for details on how to do this). If you want to have different folder rendering for different groups of users, you should group the users home folder under different group folders and attach different folder rendering services to each group folder, like this:

A folder service is written just like any other Oracle9iAS Wireless service, and will get invoked with a regular ServiceContext. The folder to be rendered can be retrieved using the ServiceContext method getCurrentFolder.

10.6.2.17 FolderRendererBean

The service used to render folders can be any Oracle9iAS Wireless service. It is usually convenient to write this service as a JSP, using the OC4J Adapter. In order to facilitate writing a FolderRenderer JSP service, the bean oracle.panama.rt.hook.FolderRendererBean is provided. This class has a number of methods for getting the content normally used by the built-in FolderRenderer: the getHeader, getBody and getFooter methods retrieve the header, body (folder content listing) and footer respectively. All methods in the FolderRenderBean takes a single argument, namely the current ServiceContext. In addition to the methods already mentioned, there are a number of utility methods (such as for getting the current user name), please see the FolderRendererBean JavaDoc for details.

The following example shows how write JSP code that displays a custom header, but reuses the built in folder renderer for displaying the folder content and footer:

<%@page import="oracle.panama.rt.ServiceContext"%>
<%@page import="oracle.panama.rt.hook.FolderRendererBean" %>

<%
    ServiceContext context = (ServiceContext)
        request.getAttribute("oracle.wireless.rt.context");
FolderRendererBean renderer = 
         FolderRendererBean.getInstance();
response.setHeader("Mime-type", "text/xml");
%>
<SimpleResult>
  <SimpleContainer>
    <SimpleText>
      <SimpleTextItem>My custom header</SimpleTextItem>
    </SimpleText>
    <%= renderer.getBody(context) %>
    <%= renderer.getFooter(context) %>
  </SimpleContainer>
</SimpleResult>

10.6.2.18 FolderRendererHook

The third way of customizing the folder is by specifying a hook class that implements the interface oracle.panama.rt.hook.FolderRendererHook. This hook has a single method invoke, which takes as its argument the current ServiceContext and returns the DOM document containing the Mobile XML for the current folder. The hook will be invoked whenever there is no assigned folder rendering service.

10.6.2.19 FolderRendererPolicy

The default (built-in) implementation of the FolderRenderer is provided in the class oracle.panama.rt.hook.FolderRendererPolicy. This class can be subclassed, allowing custom hooks to reuse parts of the built-in functionality.

The main entry point for the FolderRendererHook is the invoke method. In the default FolderRendererPolicy implementation, the invoke method will create a SimpleResult element and in turn call getHeader, getBody and getFooter methods in order to append the header, body (folder content listing) and footer respectively. All methods in the FolderRendererPolicy takes a single argument, namely the current ServiceContext. If you need to add custom headers and footers, the Folder Renderer Policy can be subclassed to override the methods for getHeader and getFooter.

The following code is an example of a FolderRendererHook implementation that inserts a custom header:

import oracle.panama.rt.ServiceContext;
import oracle.panama.rt.hook.FolderRendererHook;
import oracle.panama.rt.hook.FolderRendererPolicy;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

class CustomFolderRenderer extends FolderRendererPolicy 
implements FolderRendererHook {
    public Element getHeader(ServiceContext context) {
            Document doc = context.getXMLDocument();
            Element ret  = doc.createElement("SimpleText");
           Element text = doc.createElement("SimpleTextItem");
           ret.appendChild(text);
            String str = "My custom header";
           text.appendChild(doc.createTextNode(str));
           return ret;
    } 
    // inherit getBody
    // inherit getFooter
}
10.6.2.19.1 Folder Setup Actions

The default folder renderer in the runtime puts the controls for setting up the end user's preferences in the header and footer. The actions that are added in the device header/footer is described by the FolderSetupAction interface. When writing a folder rendering service or hook, it is possible to get information about all actions, including the URL (String), the localized label and whether the action should be displayed or not. Please see the FolderRendererBean and FolderRendererPolicy JavaDoc for a complete list of methods that retrieves FolderSetupActions.

Using the FolderSetupActions allows the user that extends the FolderRenderer to duplicate the built-in setup button semantics and labels, but substitute their own look and feel, for example by using SimpleHrefs instead of SimpleMenuItems. The following code is an example of a FolderRendererHook that does this:

import oracle.panama.rt.ServiceContext;
import oracle.panama.rt.hook.FolderRendererHook;
import oracle.panama.rt.hook.FolderRendererPolicy;
import oracle.panama.rt.hook.FolderSetupAction;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

class CustomFolderRenderer extends FolderRendererPolicy implements 
FolderRendererHook {
  public Element getHeader(ServiceContext context) {
    Document doc  = context.getXMLDocument();
    Element  ret  = doc.createElement("SimpleText");
    Element  text = doc.createElement("SimpleTextItem");
    ret.appendChild(text);
   FolderSetupAction[] actions = new FolderSetupAction[] {
     super.getEditPresetsAction(context),
     super.getEditServicesAction(context),
     super.getEditUserInfoAction(context),
     super.getLoginAction(context),
     super.getLogoffAction(context),
     super.getRegisterAction(context),
}; for(int i = 0; i < actions.length; i++) { if(actions[i].isActive(context)) { Element href = doc.createElement("SimpleHref"); // set the URL of the href href.setAttribute("target", actions[i].getURL(context)); // set the text to display for the href Text label = doc.createTextNode(actions[i].getLabel(context)) href.appendChild(label); text.appendChild(href); } } return ret; } // inherit getBody unchanged // override getFooter with implementation that creates footer // without setup buttons. public Element getFooter(ServiceContext context) { Document doc = context.getXMLDocument(); Element ret = doc.createElement("SimpleText"); Element text = doc.createElement("SimpleTextItem"); text.appendChild(doc.createTextNode("My custom footer")); return ret; } }

10.6.2.20 Example 2

The second example is also a hook example, but it takes advantage of the policy concept. The MyAuthenticator first examines the "badguys" table to make sure the login Oracle9iAS Wireless user is not in the table. If the user is in the table, then the hook rejects the login request. Otherwise, it resumes the default policy implementation in lines 42 and 44.

package hook;

import oracle.panama.rt.hook.AuthenticationHook;
import oracle.panama.rt.hook.AuthenticationPolicy;
import oracle.panama.rt.hook.AuthenticationContext;
import oracle.panama.rt.hook.AuthenticationException;
import oracle.panama.rt.hook.AuthenticationFailOverException;
import oracle.panama.rt.Request;
import oracle.panama.rt.hook.AuthenticationContext;
import oracle.panama.core.util.Locator;
import oracle.panama.core.admin.L;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;


public class MyAuthenticator implements AuthenticationHook {


private static MyAuthenticator myAuthenticator;
private Connection conn;
private PreparedStatement st;

private MyAuthenticator () { 
    try {
        // lookup the db.connect.string in the panama's System.properties file
        String connectString = 
Locator.getInstance().getResource().getSystem().getString("db.connect.string", 
"");
        // constrct the JDBC connect string, always use the THIN driver for
        // simplicity
        int i = connectString.indexOf('/');
        String user = connectString.substring(0, i);
        int j = connectString.indexOf('@', i+1);
        String password = connectString.substring(i+1, j);
        String dbname = connectString.substring(j+1);
        StringBuffer connStrBuf = new StringBuffer("jdbc:oracle:thin:");

        connStrBuf.append("@");
        connStrBuf.append(dbname);
        // load the Oracle's JDBC driver
        Class.forName("oracle.jdbc.driver.OracleDriver");

        // connect to the database
        conn = DriverManager.getConnection(connStrBuf.toString(), user, 
password);
        st = conn.prepareStatement("select name from badguys where name = ?");
    } catch (Exception e) {
        L.e(e);
        conn = null;
    }
}

public static AuthenticationHook getInstance() {
    if (myAuthenticator == null) {
        synchronized (MyAuthenticator.class) {
            if (myAuthenticator == null) {
                myAuthenticator = new MyAuthenticator();
            }
        }
    }
    return myAuthenticator;
}


public AuthenticationContext authenticate(String name, String passwd,
Request request) throws AuthenticationException,
AuthenticationFailOverException { boolean badguy; if (conn == null) return AuthenticationPolicy.authenticateUser(name, passwd, request); try { st.setString(1, name); ResultSet rs = st.executeQuery(); badguy = rs.next(); } catch (Exception e) { L.e(e); return AuthenticationPolicy.authenticateUser(name,
passwd, request); [42]
} if (badguy) { L.e(name+ " is an intruder!"); throw new AuthenticationException(name+" is an intruder!"); } else { return AuthenticationPolicy.authenticateUser(name,
passwd, request); [44]
} } }

10.6.2.21 Register the Authentication Hook

You should also add the name of the class, in this case hook.MyAuthenticator, in the System Manager > Site > Wireless Web Server > Hooks control panel in the Webtool under the wireless.http.locator.authentication.hook.class property.

10.6.2.22 Event Listener Example

The following partial example (the complete "runable" example is under the \sample\listener directory) illustrates how to implement a RequestListener. This RequestListener simply writes the request related information to a log file.

10.6.2.23 Implementing the RequestListener Interface

The RequestListenerSample source file is as follows:

/*
*
$Copyright:
Copyright (c) 1999 Oracle Corporation all rights reserved
$
*/

package listener;

import oracle.panama.rt.Request;
import oracle.panama.rt.Response;
import oracle.panama.rt.Session;
import oracle.panama.rt.AttributeCategory;

import oracle.panama.rt.event.RequestEvent;
import oracle.panama.rt.event.ResponseEvent;
import oracle.panama.rt.event.SessionEvent;
import oracle.panama.rt.event.RequestListener;
import oracle.panama.rt.event.ResponseListener;
import oracle.panama.rt.event.SessionListener;
import oracle.panama.rt.event.AbortServiceException;

public class RequestListenerSample implements RequestListener {       [31]

private final static String BEFORE_REQUEST    = "L__L1";
private final static String REQUEST_BEGIN     = "L__L2";
private final static String SERVICE_BEGIN     = "L__L3";
private final static String SERVICE_END       = "L__L4";
private final static String TRANSFORM_BEGIN   = "L__L5";
private final static String TRANSFORM_END     = "L__L6";
private final static String REQUEST_END       = "L__L7";
private final static String AFTER_REQUEST     = "L__L8";

/**
* The event notification before the start of request
* @param    an event
*/
public void beforeRequest(RequestEvent event) throws AbortServiceException {
     ListenerRegistrationHookSample.println("BEFORE REQUEST -- " +
     event.toString() + "---" + event.getTimeStamp());
     event.put(BEFORE_REQUEST, new Long(event.getTimeStamp()));
     event.getRequest().setAttribute(AttributeCategory.RUNTIME, BEFORE_REQUEST,
     new Long(event.getTimeStamp()));
}

/**
* The event notification when request begins
* @param    an event
*/
public void requestBegin(RequestEvent event) throws AbortServiceException {
      ListenerRegistrationHookSample.println("REQUEST BEGIN -- " +
event.toString() + "---" + event.getTimeStamp()); event.put(REQUEST_BEGIN, new Long(event.getTimeStamp())); event.getRequest().setAttribute(AttributeCategory.RUNTIME, REQUEST_BEGIN,
new Long(event.getTimeStamp())); } /** * The event notification when service begins * @param an event */ public void serviceBegin(RequestEvent event) throws AbortServiceException { ListenerRegistrationHookSample.println("SERVICE BEGIN -- " +
event.toString() + "---" + event.getTimeStamp()); event.put(SERVICE_BEGIN, new Long(event.getTimeStamp())); event.getRequest().setAttribute(AttributeCategory.RUNTIME, SERVICE_BEGIN,
new Long(event.getTimeStamp())); } /** * The event notification when service end * @param an event */ public void serviceEnd(RequestEvent event) throws AbortServiceException { ListenerRegistrationHookSample.println("SERVICE END -- " +
event.toString() + "---" + event.getTimeStamp()); event.put(SERVICE_END, new Long(event.getTimeStamp())); event.getRequest().setAttribute(AttributeCategory.RUNTIME, SERVICE_END, new Long(event.getTimeStamp())); } /** * The event notification when transform begins * @param an event */ public void transformBegin(RequestEvent event) throws AbortServiceException { ListenerRegistrationHookSample.println("TRANSFORM BEGIN -- " +
event.toString() + "---" + event.getTimeStamp()); event.put(TRANSFORM_BEGIN, new Long(event.getTimeStamp())); event.getRequest().setAttribute(AttributeCategory.RUNTIME,
TRANSFORM_BEGIN, new Long(event.getTimeStamp())); } /** * The event notification when transform end * @param an event */ public void transformEnd(RequestEvent event) throws AbortServiceException { ListenerRegistrationHookSample.println("TRANSFORM END -- " +
event.toString() + "---" + event.getTimeStamp()); event.put(TRANSFORM_END, new Long(event.getTimeStamp())); event.getRequest().setAttribute(AttributeCategory.RUNTIME,
TRANSFORM_END, new Long(event.getTimeStamp())); } /** * The event notification when request ends * @param an event */ public void requestEnd(RequestEvent event) throws AbortServiceException { ListenerRegistrationHookSample.println("REQUEST END -- " +
event.toString() + "---" + event.getTimeStamp()); event.put(REQUEST_END, new Long(event.getTimeStamp())); event.getRequest().setAttribute(AttributeCategory.RUNTIME,
REQUEST_END, new Long(event.getTimeStamp())); } /** * The event notification when request error happens * @param an event */ public void requestError(RequestEvent event) throws AbortServiceException { ListenerRegistrationHookSample.println("REQUEST ERROR -- " +
event.toString() + "---" + event.getTimeStamp()); } /** * The event notification after the end of request * @param an event */ public void afterRequest(RequestEvent event) throws AbortServiceException { ListenerRegistrationHookSample.println("AFTER REQUEST -- " +
event.toString() + "---" + event.getTimeStamp()); event.put(AFTER_REQUEST, new Long(event.getTimeStamp())); event.getRequest().setAttribute(AttributeCategory.RUNTIME,
AFTER_REQUEST, new Long(event.getTimeStamp())); // start logging the object cached in the Request ListenerRegistrationHookSample.println("logging the object cached in the request"); Long beforeRequestTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, BEFORE_REQUEST); if (beforeRequestTime != null) ListenerRegistrationHookSample.println("BEFORE REQUEST: " +
beforeRequestTime.longValue()); Long requestBeginTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, REQUEST_BEGIN); if (requestBeginTime != null) ListenerRegistrationHookSample.println("REQUEST BEGIN: " +
requestBeginTime.longValue()); Long serviceBeginTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, SERVICE_BEGIN); if (serviceBeginTime != null) ListenerRegistrationHookSample.println("SERVICE BEGIN: " +
serviceBeginTime.longValue()); Long serviceEndTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, SERVICE_END); if (serviceEndTime != null) ListenerRegistrationHookSample.println("SERVICE END: " +
serviceEndTime.longValue()); Long transformBeginTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, TRANSFORM_BEGIN); if (transformBeginTime != null) ListenerRegistrationHookSample.println("TRANSFORM BEGIN: " +
transformBeginTime.longValue()); Long transformEndTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, TRANSFORM_END); if (transformEndTime != null) ListenerRegistrationHookSample.println("TRANSFORM END: " +
transformEndTime.longValue()); Long requestEndTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, REQUEST_END); if (requestEndTime != null) ListenerRegistrationHookSample.println("REQUEST END: " +
requestEndTime.longValue()); Long afterRequestTime = (Long) event.getRequest().getAttribute(
AttributeCategory.RUNTIME, AFTER_REQUEST); if (afterRequestTime != null) ListenerRegistrationHookSample.println("AFTER REQUEST: " +
afterRequestTime.longValue()); if ((afterRequestTime != null) && (beforeRequestTime != null)) ListenerRegistrationHookSample.println("REQUEST DURATION: " +
(afterRequestTime.longValue() -
beforeRequestTime.longValue())); // start logging the object cached in the RequestEvent ListenerRegistrationHookSample.println("logging the object cached in the request event"); beforeRequestTime = (Long) event.get(BEFORE_REQUEST); if (beforeRequestTime != null) ListenerRegistrationHookSample.println("BEFORE REQUEST EVENT: " +
beforeRequestTime.longValue()); requestBeginTime = (Long) event.get(REQUEST_BEGIN); if (requestBeginTime != null) ListenerRegistrationHookSample.println("REQUEST BEGIN EVENT: " +
requestBeginTime.longValue()); serviceBeginTime = (Long) event.get(SERVICE_BEGIN); if (serviceBeginTime != null) ListenerRegistrationHookSample.println("SERVICE BEGIN EVENT: " +
serviceBeginTime.longValue()); serviceEndTime = (Long) event.get(SERVICE_END); if (serviceEndTime != null) ListenerRegistrationHookSample.println("SERVICE END EVENT: " +
serviceEndTime.longValue()); transformBeginTime = (Long) event.get(TRANSFORM_BEGIN); if (transformBeginTime != null) ListenerRegistrationHookSample.println("TRANSFORM BEGIN EVENT: " +
transformBeginTime.longValue()); transformEndTime = (Long) event.get(TRANSFORM_END); if (transformEndTime != null) ListenerRegistrationHookSample.println("TRANSFORM END EVENT: " +
transformEndTime.longValue()); requestEndTime = (Long) event.get(REQUEST_END); if (requestEndTime != null) ListenerRegistrationHookSample.println("REQUEST END EVENT: " +
requestEndTime.longValue()); afterRequestTime = (Long) event.get(AFTER_REQUEST); if (afterRequestTime != null) ListenerRegistrationHookSample.println("AFTER REQUEST EVENT: " +
afterRequestTime.longValue()); if ((afterRequestTime != null) && (beforeRequestTime != null)) ListenerRegistrationHookSample.println("REQUEST DURATION EVENT: " +
(afterRequestTime.longValue() - beforeRequestTime.longValue())); } }

Line [31] in the above code example declares the implementation of the oracle.panama.rt.event.RequestListener interface.

10.6.2.24 Register the Request Listener

You should also add the name of the listener class, in this case listener.RequestListenerSample, in the System Manager > Site > Wireless Web Server > Event and Listeners control panel in the Webtool under the wireless.http.locator.request.listener.classes property.

10.6.2.25 Register the RequestListener with Each Request Object

You should implement the ListenerRegistrationHook to register your request listener object whenever a new request is created. See the code section between line [62] and line [65] in the code example below.

Your new registration hook class has to implement the oracle.panama.rt.event.ListenerRegistrationHook interface as in line [31] in the code example below. The class also needs to implement the Singleton pattern. See the code section between lines 37 and 39 in the code example below.

package listener;

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.FileNotFoundException;
import java.net.URL;

import oracle.panama.rt.Request;
import oracle.panama.rt.Response;
import oracle.panama.rt.Session;

import oracle.panama.rt.event.RequestListener;
import oracle.panama.rt.event.ResponseListener;
import oracle.panama.rt.event.SessionListener;

import oracle.panama.rt.hook.ListenerRegistrationHook;

import oracle.panama.rt.hook.ListenerRegistrationPolicy;

public final class ListenerRegistrationHookSample implements      [31] 
ListenerRegistrationHook {                      

public final static String LISTENER_LOG_FILE = "ListenerSample.log";
public static PrintStream logPrint = System.out;

private SessionListener sessionListener = null;
private RequestListener requestListener = null;
private ResponseListener responseListener = null;

private static ListenerRegistrationHookSample singleInstance = null;

public static ListenerRegistrationHookSample getInstance() {       [37]
     if (singleInstance == null) {
          singleInstance = new ListenerRegistrationHookSample();
     }
     return singleInstance;
}                                                                  [39]

public void finalize() {
     logPrint.println("RegistrationHook is deallocated -- " +
System.currentTimeMillis()); logPrint.flush(); logPrint.close(); } public static void println(String str) { logPrint.println(str); logPrint.flush(); } private ListenerRegistrationHookSample() { URL url = ClassLoader.getSystemResource(
"listener/ListenerRegistrationHookSample.class"); if (url != null) { String filePath = url.getFile(); int lastSlash = filePath.lastIndexOf("/"); filePath = filePath.substring(1, lastSlash); filePath = filePath + "/" + LISTENER_LOG_FILE; try { FileOutputStream logFile = new FileOutputStream(filePath, true); logPrint = new PrintStream(logFile); } catch (Exception fnfe) { fnfe.printStackTrace(); } } logPrint.println("RegistrationHook is initialized -- " +
System.currentTimeMillis()); logPrint.flush(); } /** * instantiate the sample session listener class and register to sesson * @param request an incoming request * @param session a new session to register listeners */ public void registerSessionListeners(Request request, Session session) { sessionListener = new SessionListenerSample(); if (sessionListener != null) { session.addSessionListener(sessionListener); } // optional, register default session listeners ListenerRegistrationPolicy.registerSessionListeners(request, session); } /** * instantiate the sample request listener class and register to request * @param request a new request to register listeners */ public void registerRequestListeners(Request request) { [62] requestListener = new RequestListenerSample(); if (requestListener != null) { request.addRequestListener(requestListener); } //optional, register default request listeners ListenerRegistrationPolicy.registerRequestListeners(request); } [65] /** * instantiate the sample response listener class and register to response * @param request an incoming request * @param session an existing session * @param response a new response to register listeners */ public void registerResponseListeners(Request request, Response response) { responseListener = new ResponseListenerSample(); if (responseListener != null) { response.addResponseListener(responseListener); } // optional, register default response listeners ListenerRegistrationPolicy.registerResponseListeners(request, response); } /** * unregister the listeners from session. * @param session a session to unregister listeners */ public void unregisterSessionListeners(Session session) { if (sessionListener != null) { session.removeSessionListener(sessionListener); } //optional, unregister default session listeners ListenerRegistrationPolicy.unregisterSessionListeners(session); } /** * unregister the listeners from request. * @param request a request to unregister listeners */ public void unregisterRequestListeners(Request request) { if (requestListener != null) { request.removeRequestListener(requestListener); } //optional, unregister default request listeners ListenerRegistrationPolicy.unregisterRequestListeners(request); } /** * unregister the listeners from response. * @param response a response to unregister listeners */ public void unregisterResponseListeners(Response response) { if (responseListener != null) { response.removeResponseListener(responseListener); } //optional, unregister default response listeners ListenerRegistrationPolicy.unregisterResponseListeners(response); } }

10.6.2.26 Register the Listener Registration Hook

You should also add the name of the listener registration class, in this case listener.ListenerRegistrationHookSample, in the System Manager > Site > Wireless Web Server > Hooks control panel in the Webtool under the wireless.http.locator.listener.registration.hook.class property.

10.6.2.27 Modify the Event Mask

Since the sample request is interested in all the request events, you should make sure that the event mask for all the request-related events is set to true in the System Manager -> Site -> Wireless Web Server -> Event and Listeners control panel of webtool.

10.6.3 Repository Data Model API

The Oracle9iAS Wireless Repository comprises the models for the Model-View-Control (MVC) architecture, while the Oracle9iAS Wireless runtime layer comprises the controllers for the MVC. The repository Model API in oracle.panama.model package lets you develop applications that create, delete, modify, and query the persistent objects in the Oracle9iAS Wireless Repository. Developers of custom adapters and transformers can implement the corresponding Model interfaces to develop the applications that supply the business processes and contents for the Oracle9iAS Wireless portal. The developers can also implement the "controller" applications, through the adapter, listener, or hook components, that manipulate the repository objects to perform provisioning, registration, personalization, accounting, and similar type of functions.

The Oracle9iAS Wireless repository imposes the organizational structure among the objects. For example, a User can belong to multiple Group's. The User is assigned one or more Role's. The user can access the Service's that are accessible to the groups to which the user belongs. However, the implementations of the User interface can access external provisioning systems or repositories, such as the Oracle Internet Directory (OID) and the Oracle Applications User Repository (AOL), to manage the information for the enterprise users and specify the user's roles, the user's group membership, and the particular services that are accessible to the user.

A Folder is a special kind of Service used as a container of the services to build the service trees. A Service or Folder can be assigned to one or more groups. The User can own a collection of DeviceAddresses, a collection of LocationMark's, a collection of customization Profile's, and one or more collections of Presets' which are used in advanced personalization. A default LocationMark and a default Profile can be assigned for each User. The Device interface in the Model API defines the target device protocol (for example: WAP, SMS, or EMAIL), as well as specifies the physical characteristics of the target device that can be used by the adapters and the transformers (for example, screen width and height, screen columns and rows, and number of softkeys).

The intended users of the Model API are developers of customization portals, portlets, custom hooks, listeners, adapters, transformers, and applications such as JSPs, servlets, modules, and other (URL addressable) resources that are invoked through the HttpAdapter. Developers can also develop stand-alone applications which manipulate persistent objects using the Model API. Although these interfaces preserve the data integrity in the repository, they do not enforce access control security. The applications that access the repository through the Model API are not authenticated or authorized by the same Authentication and Authorization mechanisms in the Oracle9iAS Wireless runtime layer. In facts, the Model APIs are used by trusted components to develop and customize the authentication and authorization policies. The OracleMobile Online Studio, the System, Service, and Content Management Webtools, and the Customization Portals provide authentication and authorized access control to the repository. Developers should apply extreme caution when developing services using the interfaces in the Model API, and should take appropriate measures to prevent any undesired side effects when these services are invoked by the end users.

10.6.3.1 Data Model Cache and Synchronization

The repository objects are cached in the Java instances main memory when they are accessed from the Data Model API. These objects are removed from the main memory cache only after they are not accessed through the API for a time-to-live interval. This interval can be configured from "Cache Object Life Time" property in System Manager -> Site -> Runtime Configuration control panel in the webtool. If the repository object is modified and committed into the repository from one of the Java instances; all other Java instances will automatically reload the modified object from the repository. You can specify the number of cache synchronization threads from the System Manager -> Site -> Object Cache Synchronization control panel in the webtool.

10.6.3.2 Interfaces and Interface Hierarchy

The following sections describe the interfaces within the interface hierarchy in the Model API. These interfaces are contained in the oracle.panama.model package. For a sample application that illustrates the use of some of the interfaces, see Section 10.6.4.1, "Sample Code". The oracle.panama.model package also provides the following three locator and factory objects to access the model objects.

10.6.3.3 MetaLocator

MetaLocator, which is in the oracle.panama.model is used to access the ModelFactory and ModelServices.

10.6.3.4 ModelFactory

ModelFactory, which is in the oracle.panama.model package, provides the factory to create model objects.

10.6.3.5 ModelServices

ModelServices, which is in the oracle.panama.model package, provides the locator or façade to access model objects.

10.6.3.6 ModelObject

The ModelObject is the root interface that represents the common behavior and properties of all repository objects. It is included in the oracle.panama.model package. The figure below illustrates the inheritance hierarchy among all of the interfaces in the oracle.panama.model package.

Figure 10-20 Model API Inheritance Hierarchy.

Text description of modapi1.gif follows.

Text description of the illustration modapi1.gif

The subinterfaces in the ModelObject interface hierarchy are all persistent objects. These subinterfaces are (in alphabetical order):

The following sections describe each subinterface.

10.6.3.7 Adapter

Adapter extends the ModelObject interface. Adapter is the repository container for the RuntimeAdapter, which is the interface that is to be implemented by all custom adapters. The Adapter incorporates the RuntimeAdapter classes into the repository and supports the loading and initialization of the RuntimeAdapter.

10.6.3.8 Device

Device extends the ModelObject interface. A Device is the definition of the target logical device protocol. It can, for example, be WML11 for WML specific devices, but also WML_Nokia7110 for Nokia specific WML. Other examples are SMS and EMAIL. Device contains the Transformer objects.

Observe that the same physical device can support multiple logical devices; a phone, for example, can support both the SMS and WAP protocols.

10.6.3.9 DeviceAddress

DeviceAddress extends the ModelObject interface. DeviceAddress contains the device-specific address, such as a phone or an email address. The DeviceAddress takes precedence over the AlertAddress, which is deprecated in this release.

10.6.3.10 Group

Group extends the ModelObject interface. A Group is a collection of users. It is used to publish specific services to the group members. A user can access those services that are accessible to the group to which the user belongs.

10.6.3.11 LocationMark

LocationMark extends the ModelObject interface. It is a persistent object that represents the named and geocoded physical address.

10.6.3.12 PresetCategory

The PresetCategory extends the ModelObject interface. PresetCategory defines the structure and attributes of the Presets. Each PresetCategory contains a collection of PresetDescriptors, which provides the meta information for the attributes in the Presets relation.

10.6.3.13 PresetDescriptor

The PresetDescriptor extends the ModelObject interface. PresetDescriptor defines the meta data for an attribute in the Presets relation. The meta data of an attribute include the name, type, size, format, and description of the attribute.

10.6.3.14 Presets

The Presets interface extends the ModelObject interface. A Presets object contains a set of preset values whose structure and relation is defined by a PresetCategory. The Presets are owned by the User objects, and incorporates the personalized user preferences and frequently used input parameters for the services into the repository.

10.6.3.15 Profile

The Profile interface extends the ModelObject interface. The User can have one or more Profiles that encompass the user's customizations of the service trees. The Profile for a User can specify a preferred ordering of services in a folder.

10.6.3.16 Service

Service extends the ModelObject interface. Service is an "abstract" interface and handles all generic aspects of a service.

It contains the following subinterfaces:

10.6.3.17 Transformer

Transformer extends the ModelObject interface. Transformer is the base interface for all transformation sub-classes. It is the repository container for the real transformation implementation (Java or XSL). It performs loading and initialization of the custom transformer classes that implements the oracle.panama.rt.xform.RtTransformer interface. It also provides the XSLT transformers for the XSLT stylesheets.

It has the following subinterfaces:

10.6.3.18 User

The User interface extends the ModelObject interface. The User represents the identity of the user and facilitate personalization in the Oracle9iAS Wireless portals.

Each user can be assigned a private root folder to contain the user's personal quicklinks. The user can access the services in the groups to which the user belongs. The implementation of the User interface may access external provisioning system or enterprise repositories such as Oracle Internet Directory (OID) to manage the information about the user.

10.6.4 Sample Code that Uses the Data Model API

The following sample code illustrates how you can provision new objects into the Oracle9iAS Wireless repository using the interfaces in the Model API. We choose the standalone class to introduce the sample codes, although other type of components, such as adapters, hooks, listeners, and servlets can be used to illustrate the Model API. The example only shows the search, create, delete, and commit operations in the Model API but does not include the necessary business logics.

The numbers that appear in brackets next to a line of code in the listing are referenced in the discussion to correlate the explanation with the corresponding lines in the code itself.

The MetaLocator interface is used to lookup the ModelFactory and ModelServices. The getInstance() method in this interface gets the singleton instance of this MetaLocator. The methods getModelFactory and getModelServices look up the ModelFactory and the ModelServices.

Typically, to create a new object, you should check first if the object already exists. To look up any object, you use the ModelServices interface and the method lookupX(java.lang.String name), where X is the interface name of the object. In this sample code, to create a new user (the code section for creating a new user starts in line [2]), you first look up the user by using the lookupUser(userName) method in the ModelServices interface (line [3]), as the following line of code shows:

modelServices.lookupUser(userName); 

Lookup operation should be the first step before creating any new persistent object in the Repository. The lookupUser(userName) method searches for the user by name and, if the User by that name is found, returns the User object. If the user with that name cannot be found, the method throws the PanamaRuntimeException.

Next, you check if the group to which the user belongs (or should belong) already exists (line [4]). Following the convention for looking up any object, you use the ModelServices interface and the lookupGroup(groupName) method to look up a group by name. If the group is found, the method returns the Group object. If the group is not found, the method throws the PanamaRuntimeException.

After checking if the user and the group already exist, you create the new user object (line [5] to line [6]):

{
     user = modelFactory.createUser(userName, groups); 
} else {
     user = modelFactory.createUser(userName);
}
user.setPassword(userPassword);
user.setEnabled(true); 

You must save the newly created user. Each newly created object must be saved after it is created (line [7]):

modelFactory.save();

Save applies to all created or modified objects in the current thread. The objects are saved to the persistent storage and the transaction is committed. The method throws PanamaException if it is unable to save the work.

The searchUser() method in the sample code (line [8]) illustrates how to search a User object. To enumerate over a set of users (for example, all the users whose names start with the letter "B"), you use the ResultSetEnumeration (line [9]) returned by the method findUsers (line [10]). The method findUsers uses the pattern matching on the names. See also lines [11] and [12] in the listing of the complete sample code.

You should close the ResultSetEnumeration (line [13]) to release the database cursor, which otherwise will remain open.

To delete a User, you use the deleteUser method following the sample code section in line [14]. The user name must be exact in line [15]. ModelServices.lookupUser() method rejects the pattern matching templates by throwing exceptions. The user object is deleted in line [16].

10.6.4.1 Sample Code

import java.util.Vector;

import oracle.panama.PanamaException;
import oracle.panama.PanamaRuntimeException;

import oracle.panama.model.MetaLocator;
import oracle.panama.model.ModelFactory;
import oracle.panama.model.ModelServices;
import oracle.panama.model.ResultSetEnumeration;
import oracle.panama.model.User;
import oracle.panama.model.Group;

/**
 * This is a sample program demonstrates the usage of the model API.
 */
public class SampleModelClient {

    private ModelFactory modelFactory;
    private ModelServices modelServices;
    
    public SampleModelClient() {
        MetaLocator metaLocator = MetaLocator.getInstance();       [1]
        modelFactory = metaLocator.getModelFactory();
        modelServices = metaLocator.getModelServices();
    }

    /**
     * Get all group names
     */
    private String[] getGroupNames() throws PanamaException, 
PanamaRuntimeException {
        String[] names;
        ResultSetEnumeration result = null;
        try {
            // Find all user groups - use a wildcard for the name expression
            result = modelServices.findGroups("*");
            Vector buffer = new Vector();
            while (result.hasMoreElements()) {
                Group group = (Group)result.next();
                String name = group.getName();
                buffer.addElement(name);
            }
            names = new String[buffer.size()];
            buffer.copyInto(names);
        } catch (PanamaRuntimeException ex) {
            throw ex;
        } finally {
            if (result != null) {
                result.close();
                result = null;
            }
        }
        return names;
    }

    /**
     * Create a new user.
     */
    private void createUser(String userName, String userPassword, String 
groupName)    [2]
                           throws PanamaException, PanamaRuntimeException {
        try {
            // First check if the user does not already exists
            modelServices.lookupUser(userName);                    [3]
            // If we are here the user must already exists
            return;
        } catch (PanamaRuntimeException ignore) {}
        Group group = null;
        try {
            // Get the group to add the user
            group = modelServices.lookupGroup(groupName);          [4]
        } catch (PanamaRuntimeException ex) {
            // A PanamaRuntimeException is thrown if the group is not found
            group = null;
        }
        User user;
        // modelFactory.createUser() will automatically create a
        // home folder for the new user.
        if (group != null) {
            Group[] groups = new Group[1];
            groups[0] = group;
            user = modelFactory.createUser(userName, groups);      [5]
        } else {
            user = modelFactory.createUser(userName);
        }
        user.setPassword(userPassword);
        user.setEnabled(true);                                     [6]

        // save the newly created object
        modelFactory.save();                                       [7]
    }

    /**
     * Search for users.
     */
    private User[] searchUser(String userNamePattern)              [8]
                              throws PanamaException, PanamaRuntimeException {
        User[] users;
        ResultSetEnumeration result = null;                        [9]
        try {
            result = modelServices.findUsers(userNamePattern);     [10]
            Vector buffer = new Vector();
            while (result.hasMoreElements()) {                     [11]
                User user = (User) result.next();                  [12]
                buffer.addElement(user);
            }
            users = new User[buffer.size()];
            buffer.copyInto(users);
        } catch (PanamaRuntimeException ex) {
            throw ex;
        } finally {
            if (result != null) {
                result.close();                                    [13]
                result = null;
            }
        }
        return users;
    }

    /**
     * Delete a user.
     */
    private void deleteUser(String userName)                       [14]
                            throws PanamaException, PanamaRuntimeException {
        try {
            if (userName != null && userName.length() > 0) {
                User user = modelServices.lookupUser(userName);    [15]
                user.delete();                                     [16]
                
                // Save the changes
                modelFactory.save();
            }
        } catch (PanamaRuntimeException ex) {
            throw ex;
        }
    }

}

10.7 Adapters

Adapters are used to securely fetch application content and prepare it for device adaptation. Out-of-the-box, Oracle9iAS Wireless includes the HTTP Adapter. The HTTP Adapter is used to retrieve content from any HTTP/XML/J2EE server and application. The HTTP Adapter is compliant with HTTP 1.1. It supports HTTPS, cookies, and redirecting.

The method for creating mobile applications has been simplified in this release. Previously, it was common to create a Java Adapter for each mobile application. This would embed some of the application logic in an Adapter and some of the logic in the application itself. In order to leverage J2EE standards, the HTTP Adapter is recommended for mobile development. The complete mobile application can reside on any web server. The HTTP Adapter will point to the application URL to retrieve Oracle9iAS Wireless XML output. See the XML Developer's Guide section of this book for more information.

10.7.1 HTTP Adapter

The HTTP Adapter fetches the Mobile XML content from the external HTTP/ HTTPS URLs. It acts as a proxy browser (which understands mobile xml) on behalf on the mobile device. Init Argument:

INVOKE LISTNER: This argument specifies the class path of the HTTP Adapter Listener. Refer to the javadoc of oracle.panama.adapter.http.event.HttpAdapterEventListener for more details on HttpAdapterEventListener Input Arguments.

Input Arguments:

  1. URL: This argument specifies the URL to the data source

  2. REPLACE_URL: This argument specifies whether the adapter should replace the relative URLs inside the fetched mobile xml document with absolute ones

  3. FORM_METHOD: This argument specifies the HTTP method that should be used to open the data source URL

  4. INPUT_ENCODING: This argument specifies the character encoding used by the adapter to send form parameters to the data source URL.

The HTTP adapter supports all the standard browser features:

  1. Cookie Support: The HTTP Adapter implements the version 0 of the Cookie Specification by Netscape (http://www.netscape.com/newsref/std/cookie_spec.html). The HTTP Adapter stores the Cookies sent by the external URL's in the current session. And sends the relevant cookies (retrieved from the session) with the external HTTP URL request. The cookies are valid only for a session and are not stored persistently.

  2. HTTPS Support: The HTTP Adapter can access https protocol based URL's. Before using https - the client certificates should be configured using the System Management Tool. Refer to the System Management Tool's documentation for more details.

  3. Relative URL support: The Mobile XML returned by the external URL can use absolute or relative URL's as targets. The following mobile xml document uses both relative and absolute URL.

    Example XML Document, showing the usage of relative and absolute URLs.

    <?xml version = "1.0" encoding = "UTF-8" standalone="yes" ?>
    <!DOCTYPE SimpleResult PUBLIC "-//ORACLE//DTD SimpleResult 1.1.0//EN"
                                                     
    "http://xmlns.oracle.com/ias/dtds/SimpleResult_1_1_0.dtd">
    <SimpleResult>
    <SimpleContainer>
    <SimpleHref target="http://Oracle9iAS 
    Wireless.oracle.com/HelloWorld.xml">Absolute URL</SimpleHref>
    <SimpleHref target="HelloWorld.xml">Relative URL </SimpleHref>
    </SimpleContainer>
    </SimpleResult>
    
    
  4. HTTP Adapter URL Prefix Configuration Parameter: If the Input argument URL doesn't start with http or https, then the value of the site configuration parameter "HTTP Adapter URL Prefix" is prepended to the value of input argument URL. Refer to the "Site Configuration" document to find more details on how to set the value of "HTTP Adapter URL Prefix" parameter.

  5. HTTP Redirects: The HTTP Adapter honours the HTTP response code 301 to 305 and follows the redirected URL's, specified by HTTP Location header.

  6. Post Redirect Support: The HTTP Adapter support post based redirects. To send a post based redirect the external application should send HTTP header x-oracle-mobile-redirect with value true, and mobile xml form as the response content.

    The following jsp file sends a Post redirect to the URL http://Oracle9iAS Wireless.oracle.com. The param1=value1 is passed as post data to the URL

    <%
    response.setHeader("x-oracle-mobile-redirect", "true");
    response.setHeader("Content-Type", "tex/vnd.oracle.mobilexml");
    %>
    <?xml version = "1.0" encoding = "UTF-8" standalone="yes" ?>
    <!DOCTYPE SimpleResult PUBLIC "-//ORACLE//DTD SimpleResult 1.1.0//EN" 
    "http://xmlns.oracle.com/ias/dtds/SimpleResult_1_1_0.dtd">
    <SimpleResult>
       <SimpleContainer>
          <SimpleForm name="ProcessSignOnForm" mimetype="text/vnd.oracle.mobilexml" 
    target="http://Oracle9iAS Wireless.oracle.com/MyApp" method="post">
             <SimpleFormItem name="param1" value="value1" type="hidden"/>
          </SimpleForm>
       </SimpleContainer>
    </SimpleResult>
    
    
  7. Proxy Server Support: HTTP Adapter can access external URL's through a HTTP proxy server. The proxy settings can be specified using the Site Configuration Tool.

  8. Referring to non mobile XML documents: The HTTP Adapter rewrites all the targets specified in the mobile xml document so that they point to the HTTP Adapter. The mobile xml attribute "mimetype" can be used be indicate that the "target" points to a non-mobile xml document and should not be rewritten.

  9. Support for GET and POST HTTP methods: HTTP Adapter uses the following logic to find the HTTP Request method to be used:

    • If the device sent a request through HTTP listener, then the method used by the device to send the Request to the Oracle9iAS Wireless server is used

    • Else if the input argument method has a non-null value, then the value of method is used

    • Else by default GET method is used.

  10. Referral support: HTTP Adapter sends the HTTP Header Referer to specify the previous URL. This can be used by external applications to trace the context of the current request. By default, the Referer header is not sent, the mobile xml attribute "sendreferer" is used to indicate that the Referer header should be sent.

    The following mobile xml document shows the usage of the sendreferer attribute.

    <?xml version="1.0" encoding="UTF-8"?>
    <SimpleResult>
    <SimpleContainer>
    <SimpleHref target="HelloWorld.xml" sendreferer="true">Send Referer</SimpleHref>
    <SimpleHref target="HelloWorld.xml" sendreferer="false">Don't Send Referer 
    </SimpleHref>
    </SimpleContainer>
    </SimpleResult>
    
    
  11. Device Information such as type of device and user Information like location, locale preferences etc. are passed as HTTP headers.

    Following is the list of HTTP headers sent by the HTTP Headers.

    Table 10-14 HTTP headers and their descriptions
    Header Name Description

    x-oracle-user.locale

    The locale preference of the User. For example, en-US

    x-oracle-user.deviceid

    The device identifier of the device.

    x-oracle-user.userkind

    The type of the User. Possible values are anonymous, virtual, registered

    x-oracle-user.authkind

    Whether is user is authenticated. Possible values are authenticated, unauthenticated

    x-oracle-user.name

    The name of the User. This header is sent only if the Disclose Identity option is selected by the user.

    x-oracle-user.displayname

    This display name of the User. This header is sent only if the Disclose Location option is selected by the user.

    x-oracle-user.location.x

    This header is sent only if the Disclose Location option is selected by the user.

    x-oracle-user.location.y

    This header is sent only if the Disclose Location option is selected by the user.

    x-oracle-user.location.addressline1

    x-oracle-user.location.addressline2

    x-oracle-user.location.addresslastline

    x-oracle-user.location.block

    x-oracle-user.location.city

    x-oracle-user.location.county

    x-oracle-user.location.state

    x-oracle-user.location.postalcode

    x-oracle-user.location.postalcodeext

    x-oracle-user.location.country

    x-oracle-user.location.time

    x-oracle-user.location.type

    x-oracle-user.location.timesincelastupdate

    x-oracle-device.orientation

    The orientation of the device. Possible values are landscape and portrait.

    x-oracle-device.device

    The type of device. Possible values are voice, microbrowser, pdabrowser, pcbrowser, micromessenger, messenger.

    x-oracle-device.maxdocsize

    The maximum size of the document (in bytes) that can be handled by the device.

The HTTP Adapter should be used to build mobile XML aware applications. The application can be built using any web programming technology like Java Server Pages (JSP), Servlet, Perl or Active Server Pages (ASP) and can be hosted on any web server. In Oracle9iAS Wireless 2.0 HTTP Adapter is the preferred way to build mobile xml applications.

10.7.2 Other Adapters

10.7.2.1 OC4J

The OC4J Adapter is used to fetch mobile xml content by invoking a JSP page in the same Java VM. The JSP page can access the request context information. The OC4J adapter is only for internal use of Oracle9iAS Wireless.

10.7.2.2 Web Integration

The Web Integration adapter retrieves and adapts Web content. The Web Integration adapter works with Web Interface Definition Language (WIDL) files to map source content to Portal-to-Go XML. Typically, the source format for the Web Integration adapter is HTML, but you can also use the adapter to retrieve content in other formats, such as XML. Portal-to-Go provides a visual tool for creating WIDL files, the Web Integration Developer. To create a WIDL file, you identify the elements of a Web page that you want to make accessible to a service. You then associate output and input parameters to the source elements that you want to access in a Portal-to-Go service.


Note:

The Web Integration adapter is deprecated in this release.


10.7.2.3 SQL Adapter

The SQL Adapter allows service designers to create services based on SQL Statements on Stored Procedures. Any database with JDBC driver is supported. The SQL Adapter uses pool of database connections. The connection pool parameters can be specified as init arguments of the adapter.


Note:

The SQL adapter is deprecated in this release.


10.7.3 Creating Your Own Adapter

Customers can implement their own adapters by implementing oracle.panama.adapter.RuntimeAdapter interface (refer to javadoc). In this section we will implement a simple RMIAdapter, which fetches mobile xml content by invoking RMI methods.

Lets look at the implementation of the adapter

package oracle.panama.adapter.rmi;

import java.io.StringReader;

import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;

import java.lang.reflect.Method;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;

import java.net.MalformedURLException;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.NotBoundException;

import org.w3c.dom.Element;
import org.w3c.dom.Document;

import oracle.panama.PAPrimitive;
import oracle.panama.Argument;
import oracle.panama.Arguments;
import oracle.panama.ArgumentType;
import oracle.panama.OutputArguments;
import oracle.panama.adapter.RuntimeAdapter;
import oracle.panama.adapter.RuntimeAdapterHelper;
import oracle.panama.adapter.AdapterException;

import oracle.panama.rt.ServiceContext;
import oracle.panama.core.xml.XML;

/**
  * A Simple RMI Adapter - invokes RMI methods to fetch mobile xml content
  */

All the adapters implement RuntimeAdapter interface

public class RMIAdapter implements RuntimeAdapter {

    // init arguments
    private Arguments initArgs = null;

    // input arguments
    private Arguments inputArgs = null;

    // output arguments
    private OutputArguments outputArgs = null;

    private boolean initialized = false;

    // reference to remote object
    private Object remoteObject = null;

    // remote interface
    private String remoteInterface;

    // hash table containing the method name to Method object mapping
    private Hashtable accessibleMethods = null;

    // Init argument - specifies the rmi url of the remote object
    private static final String RMI_OBJECT_URL = "RMI_OBJECT_URL";

    // Init argument - specifies the remote interface
    private static final String REMOTE_INTERFACE = "REMOTE_INTERFACE";

    // Input argument - specifies the remote method name to invoke
    private static final String METHOD_NAME = "METHOD_NAME";

The getInitArguments() method returns the init arguments required to initialize the adapter. The values of these arguments are specified during the creation of Master Service. The UI tools like Service Designer use this method of display the list of init that are required for creating a master service.

The RMI Adapter has following init arguments

This method returns the Input Arguments expected by the Adapter.

    /**
     * Get the input Arguments
     * @return    input arguments
     */
    public Arguments getInputArguments() throws AdapterException {
        return inputArgs;
    }

This method returns the Output Arguments

    /**
     * Get the output Arguments
     * @return    an array of output arguments
     */
    public OutputArguments getOutputArguments() throws AdapterException {
        return outputArgs;
    }

The init method initializes the adapter. The init adapter of the method is called once, when the master service pointing to the adapter is invoked or the getMergedInputArguments() method of the MasterService is called. The content of the init method must be synchronized to ensure that the class is not initialized by another thread.

The init method of RMIAdapter does the following

The method returns an array of accessible method names

    // returns the array of accessible method names
    private String[] getAccessibleMethodNames() {
        Enumeration enum = accessibleMethods.keys();
        Vector v = new Vector();
        while (enum.hasMoreElements()) {
            String methodName = (String) enum.nextElement();
            v.add(methodName);
        }

        String[] methodNames = new String[v.size()];
        methodNames = (String []) v.toArray(methodNames);
        return methodNames;
    }

The invoke method is called when a client invokes a master service pointing to this adapter. The method executes the client request and returns the mobile xml result to the master service.

The method takes one argument of type ServiceContext. For each end user request received by the Oracle9iAS Wireless Server a ServiceContext object is created. The ServiceContext object contains all the user input arguments and arguments specified in Alias and Master Service.

/**
     * Invoke the adapter using the input and output parameters in the
     * service context.
     * @param serviceContext   the context that contains input parameters
     */
    public Element invoke(ServiceContext serviceContext) throws AdapterException 
{
        checkState();
        // Get the input argument metod name
        String methodName =
                serviceContext.getInputArguments().getInputValue(METHOD_NAME);

If the method name is not specified the mobile xml displaying the list of available methods as menu items is returned

        if ((methodName == null) || "".equals(methodName)) {
            return getMethodMenuElement(serviceContext);
        } else {

The specified method is executed.

            return invokeRemoteMethod(methodName);
        }
    }

The destroy() method releases the resources acquired by the adapter in the init method.

    /**
     * Destroy the provider.
     */
    public void destroy() {
       remoteObject = null;
    }

Utility method to check if the adapter is initialized.

    private void checkState() throws AdapterException {
        if (initialized == false) {
            throw new AdapterException("Adapter is not initialized");
        }
    }

The invokeRemoteMethod() method invokes the remote method and converts the returned String to an XML DOM Element.

    private Element invokeRemoteMethod( String methodName) throws 
AdapterException{
        Method method = (Method) accessibleMethods.get(methodName);
        if (method == null) {
            throw new AdapterException("method "+ methodName + " is not 
available");
        }

        try {
            // invoke the remote method
            String retString = (String) method.invoke(remoteObject, new 
Object[0]);
            Element elt = XML.makeElement(new StringReader(retString));
            return elt;
        } catch (Exception ex) {
            throw new AdapterException(ex);
        }
    }

The getMethodMenuElement() method returns mobile xml element for displaying available methods as menu items.

    private Element getMethodMenuElement(ServiceContext serviceContext) {
        // Returns SimpleMenu containing method names
        Document doc = serviceContext.getXMLDocument();
        Element simpleResultElt = PAPrimitive.createSimpleResult(doc, null);
        Element simpleContainerElt = PAPrimitive.createSimpleContainer(doc, 
"MethodMenu");
        simpleResultElt.appendChild(simpleContainerElt);
        Element simpleMenuElt = PAPrimitive.createSimpleMenu(doc, "SimpleMenu");
        simpleContainerElt.appendChild(simpleMenuElt);

        Enumeration enum = accessibleMethods.keys();
        while (enum.hasMoreElements()) {
            String methodName = (String) enum.nextElement();
            Method m = (Method) accessibleMethods.get(methodName);
            String target = 
RuntimeAdapterHelper.getURLPAoidParameter(serviceContext.getInputArguments());
            target += "&" + METHOD_NAME + "=" + m.getName();
            Element simpleMenuItemElt =
                PAPrimitive.createSimpleMenuItem(doc, m.getName(), target, 
false);
            simpleMenuElt.appendChild(simpleMenuItemElt);
        }
        return simpleResultElt;
    }

}

The following sample RMI implementation can be used to test the RMI Adapter

SampleInterface.java: Remote Interface

package oracle.panama.adapter.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface SampleInterface extends Remote {
    // Returns Hello World message
    String sayHelloWorld() throws RemoteException;

    // Returns the current time
    String getTime() throws RemoteException;
}

SampleImpl.java: Remote Implementation

package oracle.panama.adapter.rmi;

import java.io.*;
import java.util.Calendar;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.LocateRegistry;

import org.w3c.dom.*;
import oracle.xml.parser.v2.*;
        
public class SampleImpl extends UnicastRemoteObject implements SampleInterface {

    public final static int RMI_REGISTRY_PORT = 2099;

    public SampleImpl() throws RemoteException {
        super();
    }
        
    public String sayHelloWorld() {
        return createMobileXMLMessageString("Hello World!");
    }

    public String getTime() {
         return 
createMobileXMLMessageString(Calendar.getInstance().getTime().toString());
    }

    String createMobileXMLMessageString(String message) {
        StringBuffer buf = new StringBuffer(1024);
        buf.append("<?xml version = \"1.0\" encoding = \"UTF-8\" 
standalone=\"yes\" ?>");
        buf.append("<!DOCTYPE SimpleResult PUBLIC \"-//ORACLE//DTD SimpleResult 
1.1.0//EN\" \"http://xmlns.oracle.com/ias/dtds/SimpleResult_1_1_0.dtd\">");
        buf.append("<SimpleResult>");
        buf.append("<SimpleContainer>");
        buf.append("<SimpleText>");
        buf.append("<SimpleTextItem>");
        buf.append(message);
        buf.append("</SimpleTextItem>");
        buf.append("</SimpleText>");
        buf.append("</SimpleContainer>");
        buf.append("</SimpleResult>");
        return buf.toString();
    }

        
    public static void main(String args[]) {
        
        // Create and install a security manager
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }
        try {
 // Create Registry
            LocateRegistry.createRegistry(RMI_REGISTRY_PORT);
            SampleImpl obj = new SampleImpl();

            // Bind this object instance to the name "HelloServer"
            Naming.rebind("//localhost:"+ RMI_REGISTRY_PORT+ "/Sample", obj);
            System.out.println("Sample bound in registry");
        } catch (Exception e) {
            System.out.println("Sample err: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Steps involved in testing the RMI Adapter

  1. Create $ORACLE_HOME/wireless/server/classes/oracle/panama/adapter/rmi directory

  2. Compile RMIAdapter.java and copy the class file in $ORACLE_HOME/wireless/server/classes/oracle/panama/adapter/rmi directory

  3. Compile SampleInterface.java and SampleImpl.java

  4. Generate RMI Stubs and Skeleton using rmic tool

  5. Copy SampleInterface.class, SampleImpl.class, SampleImpl_Stub.class and SampleImpl_Skel.class files in $ORACLE_HOME/wireless/server/classes/oracle/panama/adapter/rmi directory.

  6. Load adapter into repository.

  7. Create a Master Service pointing to this adapter.

  8. Publish the Master Service.

  9. Invoke the service from a phone simulator.


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index