The IFS Web Client implements a large programming framework and several caching and pooling mechanisms. As a developer of IFS Web Client pages you will have to know the programming framework. Knowledge of the caching and pooling mechanisms is also useful, and in some cases clearly beneficial or even needed.
The IFS Web Client Java pages use a number of Java classes in the Java frame work. These are collected in the package ifs.fnd.
Almost all Java classes in the IFS Web Client framework are derived (Java
keyword: extends
) from the ASPObject class. This class is
responsible for the common error handling and logging.
All Java classes that can be reused at runtime by storing their instances in the Page Pool are derived from the class ASPPoolElement. This class implements the common behavior of all objects that can be cached in the Page Pool. All states and possible state transitions are defined here.
This diagram displays selected classes that a Web Client Java page programmer could be interested in.
The ASPManager is the most important utility class in the IFS Web Client. For the application programmer the ASPManager will foremost be used for its various widely used methods ranging from many areas.
The ASPPage class is the logical container object for all objects on a web page. Behind the curtains for a programmer, this class is responsible for performance optimizations. For an Java programmer, this class is only interesting for the fact that many of the objects later used will be instantiated from this class.
The ASPBlock class corresponds to a LU. It is a container for all fields.
ASPField represents fields. This class defines various properties of input HTML entities, like the input-tag and the select-tag.
ASPBlockLayout class is responsible for producing HTML layouts that are automatically generated.
ASPTable produces a multi-row table.
The ASPCommandBar class is responsible for the IFS Web Client generated toolbar buttons.
ASPRowSet is the class that represents the underlying data for the ASPBlock. So a specific ASPRowSet object contains all the rows fetched from the database for its ASPBlock. After the introduction of the new activity programming model ASPRowSer was made abstract and it was extended into FndDataSet for the new model and BufferedDataSet for the existing model. These changes how ever only matter to the pages written using the new programming model.
The following diagram explains the relationship between these objects. Please note that the ASPTable is outside of the ASPBlock container for historical reasons. Technically this is true, but you can imagine it being a part of the ASPBlock container.
ASPBuffer is a class for storing structured data in the IFS Web Client. An ASPBuffer consists of a number of items (in an array-style structure) that can be accessed either by name or order. Each item consists of a name identifier, status, value and the type of the value. The value can either be a singular value, like an integer or string, or it can be another ASPBuffer object.
ASPContext is responsible for storing session state. An ASPContext object contains both the current data set in the IFS Web Client (current state), and the data set as fetched from the database (dbstate). You can also store other states with this class. (Note, however, that global variables for a specific user are stored in cookies). The context is stored as an ASPBuffer structure:
The ASPTransactionBuffer is responsible for sending buffers and commands to the IFS Exteded server. It uses the ASPCommand class, which in turn uses the ASPQuery class, to build SQL commands. The ASPTransactionBuffer has three actions; submit, validate and perform. When executing any of these actions, the ASPTransactionbuffer will build an ASPBuffer that it sends to the IFS Exteded server. This buffer will contain the SQL commands, the current rowset from the ASPContext and, sometimes, additional information. The actions will return a respond ASPBuffer. The action "submit" will additionally add this buffer to the ASContext current state and dbstate.
An instance of ASPCommand class represents a command in a Transaction Buffer. A command contains the following parts:
ASPQuery class that represents a query is a subclass of ASPCommand. It may be defined using SQL syntax, or it can be created automatically based on an ASPBlock. The result of a query is an ASPBuffer containing database records or rows. Each row is returned as a sub-buffer named "DATA". The result may also contain an extra sub-buffer named "INFO".
An instance of the ASPProfile class is created for each combination of user and URL (ASPPage) and then cached in the profile cache (ASPProfileCache class). The profile information is stored as a buffer structure, but can be serialized and stored in the database. And the opposite, the serialized profile information stored in the database can be de-serialized to a buffer structure.
The role of the ASPPopup class is creating popup menus. This class is used in ASPTable and ASPBlockLayout, but can also be used on customized pages.
The ASPGraph class is used to generate business graphics. Different types of graphs can be created using this class. It's possible to create graphs in both pages and Portlets.
The following classes are used with the new programming model:
The FndWebFeature interface class is used to implement the new programming model into web pages. When a java page is implemented with this class, the framework will automatically process it with the new programming model.
The FndQueryDataAdapter interface class is used to implement the query functionality into the adapter class used by the feature pages.
The FndPopulateDataAdapter interface class is used to implement the table population functionality finto the adapter class used by the feature pages.
The FndSaveDataAdapter is implemented to add the save/edit/delete functionality into the adapter class used by the feature pages.
The Page Pool mechanism was developed to improve performance.
Java is a very user-friendly language; it is almost impossible to cause the program to crash because of wrong pointer references like in C or C++ languages. However it has a price. Java spends a lot of CPU time and uses memory resources to create and allocate new objects. A normal page consists of a number of objects, like context, log, command bars, blocks, fields, row sets, etc. Each of these objects has its own internal structure of other objects - both from the IFS Web Client framework and standard Java objects.
Creating the entire page structure for the requested Web page each time the page is requested, takes 80% of the total CPU time of the request and fragments the memory heap. Instead of creating the entire object structure for each request the current version of IFS Web Client offers the mechanism for reusing once created objects.
The entire page structure is created only once - on the very first request. After the request is finished the entire structure is stored in the Page Pool and can be reused by subsequent requests, even if instantiated by another user.
Note that one of advantages of object-oriented programming is reusing implemented code. But what is mentioned here is reusing the objects that are already instantiated rather then code. How it is possible?
As mentioned previously, instantiating a Java object takes time. One of the reasons is that the Java Virtual Machine must first allocate memory on the heap for the object and then put the reference to the newly created object in its internal hash tables for future use of Garbage Collector, who's role is to remove all unused objects from the memory.
The Web browser sends a request to a Web page on the Web server, The server creates a new thread and instantiates all necessary Java objects, uses them to get data from the database, the data is then mapped into the HTML code and sent back to the browser; the browser leaves the Web server and lets the useful Java objects be destroyed. The already instantiated Java objects could be kept in a place and then reused when other requests to the same page are made. The solution to the problem is the Page Pool.
So, in other words, the Page Pool is where the IFS Web Client framework
caches the instantiated Java objects. The top-level object that serves as
container for all other objects defining the entire structure of the page is an
instance of the ASPPage class. As you can see later in this section, all objects
that can be stored in the Page Pool in scope of the current ASPPage object, have
to be instantiated in the preDefine()
method. Then calling the
method setDefined()
in ASPPage will put the entire object structure
into the Page Pool.
The Page Pool is accessed through a hash table. The key to the hash table is the URL and the output is an unlocked instance (object) of the ASPPage class.
When a page is started, an instance of the ASPManager class is created. This instance (we will call it the "manager object") tries to get an instance of corresponding ASPPage from the Page Pool based on the current URL. If there is no object returned, the manager object creates a new instance of the ASPPage class and puts it into the Page Pool - this happens on the very first request to a particular Web page (URL).
This new page object has a status Undefined (more about possible
states later in this section). The IFS Web Client framework tests the status and
if it is Undefined, then the function preDefine()
is called
for instantiating objects that belong to the new page. After that, the page
object (an instance of ASPPage) is set to Defined by calling the setDefined()
method.
An instance of ASPPage that is in use has the status "locked" in the Page Pool. When the Page Pool (implemented by class ASPPagePool) looks for an instance of ASPPage in the internal hash table and if all pages are "locked", the Page Pool will not wait for a page to become "unlocked". It will create a new one with the whole structure of other objects, by cloning an existing one. An instance of ASPPage in the Page Pool is automatically turned into "unlocked" when the execution of the page is terminated.
So far we have only talked about pages, not portlets. However as you can see later in this section, a portlet is also an instance of ASPPage and will be treated as such by the Page Pool. The only difference in the implementation is that the key to the internal hash table is not an URL, but the portlet class name.
For better understanding of mechanisms in pooled objects we must take a look at the class hierarchy and the state diagram.
The diagram below shows the state diagram implemented by the ASPPoolElement class, which is the super class for all pooled objects.
An instance of the ASPPage class, which is also a Pool Element, acts as a
container of other Pool Element objects (instances of ASPPoolElement) such as
instances of ASPBlock, ASPField, ASPTable, etc. These objects have attributes,
some of them are changeable and some are not. Example: an instance of ASPField
can be hidden (by calling setHidden()
) in the single record layout,
but visible (the unsetHidden()
method call) in the multi record
layout. The attribute "hidden" is then predefined as a mutable
attribute (changeable) by the IFS Web Client framework. If a mutable attribute
in a Pool Element object is changed while the object is in the Undefined
state (ex. set a field to be hidden in the preDefine()
method), the
value of the mutable attribute is considered as a default value. If a mutable
attribute in such object is changed while the object is in the Defined
state, the state of the object is changed to Dirty and the changed value
of the mutable attribute must be reset to its default value before the object
can become Defined again.
An instance of ASPPage keeps track of the contained objects that inherit from ASPPageElement (a subclass to ASPPoolElement), like blocks, context or log. Then each of those objects keeps track of their own "children" (instances of ASPPageSubElement), like fields, command bars or row sets.
Initially the page is in state Undefined, which means that both the
page object (instance of ASPPage) and all other contained objects (instances of
ASPPageElement and ASPPageSubElement) are in this state. Calling the setDefined()
method on the page instance will cause the call to the freeze()
method to be
executed on all contained objects. First when all objects change their state to Defined
also the page object will do the same and then the page will be stored in the
Page Pool. Changing the value of any mutable attribute of an object contained
directly or indirectly by the page will cause the state transition of the object
to the Dirty state. The object then will notify its container, which also
changes its state and notify its container, and so on.
A Dirty page (that means being already in use by any thread) can be cloned together with the entire structure of contained objects, but cannot be activated for use in another thread. On cloning, the structure of new objects will be created directly in the Defined state. Consequently only the default values of mutable attributes are copied to the new objects.
The page-pool needs to be cleaned periodically since there could be a large number of unused pool objects occupying the memory. This is particularly important with the introduction of multi language support in IFS Web Client 3.7.0 and higher because the same web page (URL) may have more than one pool key based on the different languages used to access it. Therefore the page pool may grow faster than before, which further underscores the need for a page pool cleaning mechanism
The page pool cleaner uses a time-out based method to remove least used objects from the page pool and free up memory. This is done by assigning a timestamp to each object in the pool which will hold the time it was last accessed. The Pool Cleaner which is implemented as a low priority thread would scan the page pool at specific time intervals looking for objects that have occupied memory for more than a given time period. When the pool cleaner finds a timed out object it will be removed from the page pool and subsequently the Java garbage collector will be able to free up memory used by these objects.
The following segment of the webclientconfig.xml shows the parameters under the section ADMIN/PAGE_POOL that can be configured for the page pool cleaning thread.
<admin>
<page_pool>
<clean_interval>30</clean_interval>
<thread_priority>3</thread_priority>
<template_timeout>180</template_timeout>
<clone_timeout>30</clone_timeout>
</page_pool>
</admin>
Another cache used by the IFS Web Client framework is the Context cache. The main goal of this cache is to preserve the user related data, like business data fetched from the database, for given number of previous requests from the Web browser. The context cache is needed because of the stateless nature of the web. There are no built-in mechanisms in Web servers to preserve context (user related data) during the workflow.
In earlier versions of IFS Web Client, all user data was serialized and send to the browser together with the response from the web server.
When using the context cache, each request will generate an unique identifier, which will be send to the browser in the response object, instead of the whole context. The next request sent from the same browser (to the same URL) will send the previous page id. The IFS Web Client framework uses this page id to fetch the proper context from the Context cache and will continue with the workflow.
In earlier versions (3.5.1) of IFS Web Client a hash table data structure was used for the Context cache and it was not defined as a session object. Also each context slot had a time out and all expired context slots where removed from time to time. Since the Context cache was not stored as a session object we had problems regarding clustering web servers.
So the Context cache algorithm was re-written in IFS Web Client 3.6.0 and stored as a session object. In this version the context cache is a matrix of contexts. Rows in the matrix are different flows and each flow can store a given number of history contexts. Obsolete flows are removed using a round-robin algorithm.
The context cache is no longer a matrix of contexts but a link list of contexts per browser window. The IFS Web Client framework sets a unique name for each browser window, if the programmer has not given a name. The window name is stored in a hidden field and is used to find the correct session object where the window specific contexts are stored.
However sending the window name is not always practical during a GET request. In such cases we use a temporary context list (called star [*] context cache), such contexts stay at this temporary context until the framework gets to know the window name.
Large amount of context objects stored in the session may adversely affect session replication in a clustered environment. This issue was addressed in SP2. In order to reduce the size of the user's session, history context objects were moved out of session memory and placed in a data structure common to all users in the container's memory. The user's session now contains only the last context object (per browser window) which is required during the next POST request. In addition to this the temporary [*] context cache is also kept in the user's session. Furthermore the max_flows parameter which now controls the number of history contexts maintained out of session memory has been reduced to 5. Therefore a user can go back in the browser's history a maximum five times and submit a page.
There are different parameters describing the behavior of the Context cache that can be set in webclientconfig.xml configuration file. The parameter <max_flows> is the maximum number of history we support in one browser window and <temp_flows> is the size of the temporary context list described above.
For details about how to trim the Context cache refer to the IFS Web Client Administrator Guide.
Yet another cache implemented in the IFS Web Client framework is the Profile Cache. This cache is also implemented as a hash table. IFS Web Client has built-in support for handling user customized object properties. The framework is general and supports customization of any object. Many types of objects are customizable using this framework. Among the objects that implement the interface are layouts (ASPBlockLayout), tables (ASPTable class), command bar (ASPCommandBar), portals (ASPPortal) and blocks (ASPBlock).
Customized data is stored on page basis, so the key in the internal hash table is a combination of the current URL and the user id. Note that both configuration data for the whole portal and particular portlets are stored in the same profile entry.
Profiles are stored permanently in the database, but on the very first request to a particular page issued by the user, the profile data is fetched from the database and stored in the internal hash table for subsequent calls to the same URL. All modifications made to the profile will cause the framework to store the profile in the database. But the opposite, all changes done to the database storage will not be automatically reflected in the cache; the Profile Cache must be cleared (for example by restarting the Web server) for the data to be refreshed.
There are number of parameters for controlling of the behavior of the Profile Cache. Even here we have a time-out definition, which will cause the framework to remove oldest entries from the internal hash table. But unlike the Context Cache, this fact will not affect the current flow - the profile will be simply reread from the database if it is missing in the hash table.
An IFS Web Client based application consists of both dynamic and static
content. The dynamic content, in form of HTML pages generated by servlet based
Java framework or JSP pages, is processed by an Application Server (a Java EE
container), while the static content, in form of static HTML pages, images, JS
files containing JavaScript code to be executed at the client side, and so on,
should normally be served by a dedicated Web Server to gain better
performance.
However because a part of the static content is generated by the framework (ex: js
files, business graphics etc.) the IFS Web Client framework has to have access
to the file system the Web Server is executing from. Normally, in a single
machine installation, this is not a problem, but in an environment build upon
different physical machines, either due to clustering or just simple isolation
of the Web Server from the Application Server, this behavior will lead to a
problem.
Another issue arises when packaging the application. Normally a web application
is packed as a single WAR (Web ARchive) file, eventually packed as a part of a
larger Java EE application in a single EAR file. Some Application Servers are
capable of executing an application without needing to unpack the file to an
exploded structure on disk. But because IFS Web Client generates some static
contents and in this way modifies its own structure, it is not possible to
execute from within a packed EAR or WAR file.
The Dynamic Object Cache mechanism was introduced to address these issues. The
purpose of this cache is to hold objects (.js files, business graphics etc.)
generated by the framework in memory and hence avoid writing them onto files on
disk. The URL's (that point to these objects) on the generated HTML page are
modified to indicate that the object is found in the dynamic cache.
example: /b2e/secured/dynacache/enterw/CustomerInfo-en.js
If a URL matches the pattern "secured/dynacache/*" then the request is forwarded
to the RequestHandler servlet which in turn fetches the requested object from
the cache. The response is then streamed backed to the client after setting the
correct mime type and other header information.
The cache is implemented as a hashtable internally. The key to each object in
the hashtable is
derived from the URI that points to it. The URI segment after the "dynacache/"
is used as the key. Therefore the key to the object shown in the above URI example
would be enterw/CustomerInfo-en.js
Another important feature of the Dynamic Object cache is that it is stored in
the user's session. The reason for doing this is to support clustering that may
use non-sticky sessions.