Tabular data sources provide table structured, cached data to the XMA application. Usually, many applications have to deal with some kind of data that won't change very often. Examples are lists of values where the end user may select one out of the list in a combo box. Some call these lists domains and many companies have their own software systems to manage these domains like SPARDAT's domain system.
Since these kinds of lists do change infrequently (as compared to regular business data), it would be a waste of resource to transfer them on every page from the XMA server to the client. Therefore, XMA provides a data source plugin that provides data in the form of tables at the XMA client and the server using a caching mechanism, see the following figure:
The XMA application has access to a table using the interface ITabularDataSource. This interface is able to return tables ( as ITabularData object ) if a valid table specification (to be explained later) is provided.
The red arrows in the figure above show a typical flow of control through the plugin if the XMA client requests a particular table:
After the client calls ITabularDataSource , the XMA client runtime looks up the client cache (see arrow [2]).
If it has been found in the client cache, it is returned, otherwise the XMA client runtime contacts the server runtime (see arrow [3]).
The server runtime first looks up its own in memory cache at the server [4].
If the table is not located in the server cache either, the XMA server runtime contacts the right ITableProvider which finally must provide the table data, see [5]. For some types of data sources, the providers are included in the XMA server runtime. A XMA project may provide additional providers in order to define their custom data sources.
Of course, in reality the lookup operation would stop at some point if the table is either found in the clients or servers cache and is not expired.
To successfully access a data source, the caller of ITabularDataSource must provide a data source specification which simply is a String. The specification must follow the following syntax (example):
type=rsc,name=at.spardat.myappl.countriesA comma separated list of attributes as key - value pairs. The attribute
type is reserved and should be used to discriminate among
different types of data sources. Depending on type, more
attributes usually will be required. The following type is
reserved:| type | meaning |
| rsc | the table is loaded from a resource bundle, see ResourceBundleProviderServer The syntax is type=rsc,bundle=at.spardat. ... .BundleName |
Table 6.10. Predefined Data Source Types
The provider for this source type is served from within the XMA server runtime (see ResourceBundle data sources). There is no need to write custom code.
Tabular data sources are implemented using XMA's plugin concept. Therefore, before a particular table may be accessed, the implementation of the ITabularDataSource plug-in must be retrieved. Starting point at the XMA client is the XMASessionClient, which provides access to the PluginManager:
PluginManager piManager = yourSession.getPluginManager();
ITabularDataSource dataSourcePlugin = (ITabularDataSource) piManager.getPlugin (ITabularDataSource.class);
At the server-side of XMA, the PluginManager is a singleton
within the web-application: PluginManager piManager = PluginManagerServer.getInstance();
ITabularDataSource dataSourcePlugin = (ITabularDataSource) piManager.getPlugin (ITabularDataSource.class);
Once you have got an instance of the plugin, a table is
accessed using the method ITabularData ITabularDataSource.getTable (String spec, XMASession session)See also Specification of data sources. The ITabularData interface provides access to deliberately structured tables using row and columns indexes, where the cells of the tables are of type Atom.
If you know that the table is a domain-table, you may use the method
ITabularDomData ITabularDataSource.getDomTable (String spec, XMASession session)
provides a more adequate interface for accessing domain values by key.
If in the GUI designer an XMA Combo is created, then a data source can be specified in the combo's properties. This combo box then is filled with the values from the specified data source. See XMA Combo
A data source implementation based at the Java resource bundle mechanism is already offered by XMA. This is a convenient way to define a smaller set of domain values used for the XMA Combo. Such a data source is defined like this (also see ResourceBundleProviderServer):
type=rsc,bundle=at.spardat.myappl.server.domains.MyBundleNote that the property file has to reside in a server side package of your application. Normally a package is chosen which is accessible from all XMA components. This is a package which is copied to the application's commonserver.jar file (see CommonServer.jar). An example how the actual property files reside in the package structure is shown below. The property files can be defined language dependent:
at.spardat.myappl.server.domains.MyBundle.properties at.spardat.myappl.server.domains.MyBundle_de.properties at.spardat.myappl.server.domains.MyBundle_en.properties
The property file itself is a comma separated value (CSV) file. Here an example for a property file which serves as domain and can be used as data source by the XMA Combo is listed:
COLS = COD_KEY,SHORT_VALUE,LONG_VALUE,VALID_FROM,VALID_TO 10 = "y", "y", "yes",D20030101,D20030720 20 = "n", "n", "no",D20030101,D20030719
It is possible to add additional columns, the VALID_FROM,VALID_TO columns do not need to have values.
As shown above the property files can be defined language
dependent. Then the data source retrieves the values from the file
which matches the JVM language setting of the XMA client (as
user.language=en). By default the JVM takes the
language setting from the operation system (if it is not defined
otherwise). Although the language setting of the XMA client is used
(which is transferred to the XMA server), the actual resolving of the
right property file is done at the XMA server, where the property files are existing.
The java.util.ResourceBundle mechanism resolves property
files this way (see the official Java API documentation for details):
Try to retrieve the property file according to the requested language setting (as MyBundle_en). In XMA this is the client's language setting.
If no matching file was found then try to retrieve the
property file according to the default
java.util.Locale (for example if the default
Locale is GERMAN: MyBundle_de). In XMA this is the
server's default
Locale.
If no matching file was found then try to retrieve the property with no language extension (as MyBundle)
Locale cannot be
controlled by the application. Therefore, when defining a data source
property file, one should never rely at any default settings to get
the right language. So, if the application regards some language as
its default, it should always define two property files for one
language. For example English is regarded as default: at.spardat.myappl.server.domains.MyBundle.properties at.spardat.myappl.server.domains.MyBundle_en.properties
This always ensures that, if the client requests English, it will get the English version and if it requests some other language, for which no property file is defined, then also the English version (serving as default) is retrieved. If you do not want to maintain two versions of the same file you can also extend your build script so that language files regarded as default are always copied to files without language extension.
If your application must provide tabular cached data that cannot be served from the predefined providers in XMATabularDataSourceServer you may define your custom providers by doing the following steps:
Create a subclass ( X in the following) of XMATabularDataSourceServer
Specify X as the server implementation class of the data source plugin, see: Configuration of the Data Source Plugin.
Create a class implementing the interface ITableProvider , call it MyProvider in the following. The task of MyProvider is to query tables for a particular custom data source type from the origin data store. That might be a database or some other back end legacy system.
In the default constructor of X , call the method addTableProvider and thereby associate your class MyProvider with a data source type. The data source type is merely a String that may be chosen freely as long as it does not clash with the predefined data source types in the XMA runtime.
An example for the simplest own implementation of a XMATabularDataSourceServer would look like this:
public class MyDataSourceServer extends TabularDataSourceServer {
public MyDataSourceServer() {
super();
addTableProvider("mytype", new LOWTableProvider());
}First, ITableProvider requires you, of course, to
provide the table data. You must implement the method
provideTable , that must (among other things to be
explained later) return either a TabularData
or a TabularDomData
object. To fill a TabularData -object, the
following steps are required:
Define the names of the columns using the method
TabularData.addColumn(String name).
Add rows to the table using the method
TabularData.addRow (TabularDataRow r). A row itself
is filled using multiple calls to TabularDataRow.add(Atom
value), which requires Atom
-objects to provide the table cell values.
TabularData.addColumn(String
name), you may use the convenience-method
TabularDomData.addDomColumns(). In order to fill the
domain-table with values, your added cells must comply with the
structure defined in ITabularDomData
.An example for an own ITableProvider implementation which reads country information from a data source, in this case the implementation is extended from RessourceBundleProviderServer:
public class LOWTableProvider extends RessourceBundleProviderServer {
/**
* The names of the reserved columns
*/
private static final String[] DOM_COLS =
{ "COD_KEY", "SHORT_VALUE", "LONG_VALUE", "VALID_FROM", "VALID_TO" };
public ProviderResultServer provideTable(
XMASession session,
TableSpec spec,
long lastModified) {
String domName = getDomName(spec);
ProviderResultServer result = null;
if (domName.equals("country")) {
result = provideMyTable(,spec, lastModified);
}
if (result == null) {
throw new SysException("No domaine \"" + domName + "\" found.");
}
return result;
}
private ProviderResultServer provideMyTable(
TableSpec spec,
long lastModified) {
try {
//This method reads the actual DS (e.g. database)
ArrayList countries = getCountryList();
TabularData table = new TabularDomData();
for (int i = 0; i < DOM_COLS.length; i++) {
table.addColumn(DOM_COLS[i]);
}
for (int i = 0; i < countries.size(); i++) {
Land land = (Land) countries.get(i);
TabularDataRow row = new TabularDataRow(table);
row.add(new Atom(land.iso()));
row.add(new Atom(land.kurz()));
row.add(new Atom(land.name()));
row.add(Atom.EMPTY_DATE);
row.add(Atom.EMPTY_DATE);
try {
table.addRow(row);
}
catch (IllegalArgumentException e) {
}
}
ProviderResultServer result = new ProviderResultServer();
result.table_ = table;
return result;
}
catch (Exception e) {
throw new SysException(
e, "Domain cannot be read.");
}
}
private String getDomName(TableSpec spec) {
String domName = spec.getProperty("name");
if (domName == null || domName.length() == 0) {
throw new SysException("Domain name not specified.");
}
return domName;
}
}The ITableProvider implementor is requested to provide three parameters that control how long tables may stay in client and server caches and therefore how outdated a particular table might be in terms of the client application requesting a table:
getExpireDurationClientSecs. Defines how many seconds a table may be fetched from the XMA clients cache without asking the XMA server whether the table is still valid.
getExpireDurationServerSecs. Defines how many seconds a table may be fetched from the XMA servers in memory cache without asking the ITableProvider whether the table is still valid.
lastModified. This denotes the last modification time of a table. Whenever a table is requested from an ITableProvider, a lastModified might be provided from the client requesting the table. That indicates that the client already has had a copy in its cache and that the copy is about to expire. The ITableProvider should compare the time stamp with the actual last modification time. If it didn't change, the ITableProvider does not need to return the table but merely indicates the not-changed fact signalling the client that its copy is still valid for getExpireDurationXXXSecs seconds. If an ITableProvider is not able to calculate this times tamp (for example because the origin system does not provide this information), the data source plugin uses a probabilistic algorithm and computes a time stamp from the hash value of the table. The probability that the table changes and the computed time stamp does not change (which would be the case where the algorithm fails), is 10e-9.
Every plugin in XMA must be configured in the xma-app.xml -file. The following configuration items must be given:
| Interface: | |
| Client side implementation class: | |
| Server side implementation class: | May be either at.spardat.xma.datasource.XMATabularDataSourceServer if you do not need custom data sources. If your project needs custom dada sources you must specify a class derived from TabularDataSourceServer that registers additional data source providers, see Writing custom data source providers. |
Table 6.11. data source plugin configuration