OpenSwing Framework - advanced graphics Swing components - server side integration with Spring

6. Business logic and data access tier development

Business logic and data access layers can reside both in the server-side tier of a distributed application (such as a web application) or they can be embedded in the same program that includes the user interface (such as two tier client-server application).

OpenSwing provides utility classes to use with server-side applications, to simplify the development of this tier.

OpenSwing provides a utility class to use with the data access tier, indipendently from the position of this tier (embedded in the gui or esecuted in the server-side application).

In the next paragraphs utility classes for server-side tier and data access tier will be described.

 

6.1 Utility classes used in server-side tier

OpenSwing support to server-side issues is intentionally limited: it provides a java servlet, with several customization levels; this servlet can be used as server-side controller for all HTTP requests generated in the client-side application. The servlet includes a database connection system, that can be customized and a user authentication system.

This component can be integrated with one' s own server-side framework (such as Spring) o entirely replaced.

The limited support for this layer depends on the presence in the market of excellent solutions for server-side issues: OpenSwing does not want to be an alternative solution to these frameworks, rather than to provide an integration solution that connect the client-side layer with these frameworks.

Anyway an application can be fully developed using OpenSwing components only.

 

6.1.1 Server-side controller

The java servlet provided with OpenSwing is based on the class org.openswing.swing.server.Controller; a java servlet always requires a web.xml file on which the servlet is declared; the OpwnSwing servlet requires that the web.xml file contains also additinal parameters that are read then the servlet is initialized by the web container of the Application Server. These initialization parameters are used to istantiate via reflection a set of classes; each class has a dedicated task, described below.

Here is an example of web.xml file, having the initialization parametes required by the OpenSwing Controller servlet:

 

<?xml version="1.0" encoding="UTF-8"?>

 

<!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>

<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>org.openswing.swing.server.Controller</servlet-class>
<init-param>
<param-name> actionClasses </param-name>
<param-value>demo5.server.DemoActionClasses</param-value>
</init-param>

<init-param>
<param-name> connectionSource </param-name>
<param-value>org.openswing.swing.server.PoolerConnectionSource</param-value>
</init-param>

<init-param>
<param-name> resourceFactory </param-name>
<param-value>demo5.server.XMLResources</param-value>
</init-param>

<init-param>
<param-name> loginAction </param-name>
<param-value>org.openswing.swing.server.LoginAction</param-value>
</init-param>

<init-param>
<param-name> sessionIdGenerator </param-name>
<param-value>org.openswing.swing.server.DefaultSessionIdGenerator</param-value>
</init-param>

<init-param>
<param-name> logger </param-name>
<param-value>org.openswing.swing.logger.server.ConsoleLogger</param-value>
></init-param>

<init-param>
<param-name> controllerCallbacks </param-name>
<param-value>demo5.server.DemoControllerCallbacks</param-value>
</init-param>

<init-param>
<param-name>objectsReceiver</param-name>
<param-value>org.openswing.swing.util.server.HessianObjectReceiver</param-value>
</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>controller</servlet-name>

<url-pattern>controller</url-pattern>

</servlet-mapping>

</web-app>

 

All initialization parameters are required and they have the following meaning:

  • “actionClasses” – class of type org.openswing.swing.server.ActionsCollection that contains associations <service name, Action type object> or <service name, GenericActon type object>
  • “connectionSource” – class of type org.openswing.swing.server.ConnectionSource dedicated to database connections retrieval (if needed)
  • “resourceFactory” – class of type org.openswing.swing.server.ServerResourcesFactory dedicated to internationalization settings retrieval (see internationalization settings paragraph)
  • “loginAction” – class of type org.openswing.swing.server.LoginAction dedicated to user authentication
  • “sessionIdGenerator” – class of type org.openswing.swing.server.SessionIdGenerator dedicated to sessione identifiers generation, passed to the clients in the Response object
  • “logger” – class of type org.openswing.swing.logger.server.Logger dedicated to server-side log management
  • “controllerCallbacks” – class of type org.openswing.swing.server.ControllerCallbacks , an application specific class that contains additional initialization logic for the web application.

The afterInit() method of this interfacce is automatically invoked by the Controller servlet after its initialization and can be used to add further logic, that depends on the specific application.

6.1.1.1 Objects Serialization

As default behavior, objects sent by the client side to Controller servlet are serialized by using standard java serialization; that serialization mechanism has problems when objects to send are runned with different versions of java: if the client application is running with a specific version of java and the server application with another one, then a serialization error could occour. In this scenario, it can be useful to include an alternative serialization mechanism, such as the one provided by the Hessian library; OpenSwing optionally supports this mechanism: to activate it with Controller servlet, the web.xml file must be changed by including also instructions reported in blue color in the XML above.

On the client side the same serialization mechanism must activated, instead of the java standard serialization. To activate it on the client side the following instruction must be included before sending any message to the server, so it can be added as the first instruction of the main class (see ClientApplication classes included in all sample applications):

ClientUtils.setObjectSender(new HessianObjectSender());

 

6.1.2 Action classes collection

The base class org.openswing.swing.server.ActionsCollection usually is derived to define one's own class that will contains associations <service name, Action class instance> or <service name, GenericAcrion class instance>.

An action class could be:

  • a class that implements org.openswing.swing.server.Action interface and that is automatically istantiade when the servlet is initialized and whose method is automatically invoked by the servlet when the controller receives a request from the a client that match the service name of the action class; usually the action class contains business logic related to the service it represents.Only one method is allowed per action class.
  • a class that extends org.openswing.swing.server.GenericAction class and that is automatically instantiated each time the controller receives a request from the a client whose service name matches a method signature within the action class. More methods can be included in the same action class, each one can be invoked by client side, identified by its name and signature.

Therefore ActionsCollection class operates as an index of all action classes supported by the application and that can be remotelly invoked by the clients; a programmer can fill the hashtable contained in the ActionsCollection with action classes that compose the server-side application; the list of associations <service name, action class instance> could be retrieved by accessing a file (such as an XML file) and action classes created by reflection.

The base class ActionsCollection adds some default services, that the Controller servlet can invoke:

  • <”changeLanguage”, action class to use for changing language > - this class receive as argument the language identifier to set; language identifier is set to UserSessionParameters object that is stored in the server session and that is associated to a specific client; the class UserSessionParameters provides a setLanguageId() method to set the current language used for this client, so that all action classes that needs to know the current language can query UserSessionParameters to retrieve the language identifier.
  • <”closeApplication”, action class to use for removing session data related to a specific client > - this action class is invoked when a client has been disconnected: it removes the UserSessionParameters object from the server session and unregister the session identifier associated to the client disconnected.
  • <”databaseAlreadyExixts”, action class to use for checking the presence of a database schema> - this action class invokes the ConnectionManager.isConnectionSourceCreated() method to check if there exists a ConnectionSource object and it return a VOResponse object that contains a Boolean object indicating the database support (or not). This method is useful during the setup of a web application, to know whether the database has been already created or not: it the database has not been installed and configured yet, then a custom logic can be activated to correctly define ConnectionSource object.
  • <”exportDataGrid”, org.openswing.swing.export.server.ExportAction> - this class receive as argument a org.openswing.swing.export.java.ExportOptions object that contains current export options provided by the remote grid control and used to generate an Excel document; gthe generated document is temporarily stored in server session and identified by a document indentifier, having the format: “doc"+System.currentTimeMillis()+".xls"; this identifier is given back to the client and used to open a web pages whose URL requires the document by specifing the document identifier: the servlet intercept this request, check the document identifier, extract (and remove) the document form server session and return it to the browser on the client in the shape of an array of bytes and having a content type compatible with the extension defined in the document identifier (i.e. .xls).

 

6.1.3 Database connection manager

OpenSwing provides an interface org.openswing.swing.server.ConnectionSource that is initialized when the servlet is started (i.e. on web application starup) and is dedicated to database connection retrieval (if needed).

This interface declares the following methods:

  • public Connection getConnection(ServletContext context) throws Exception – return a database connection;
  • public void releaseConnection(Connection conn,ServletContext context) – release a database connection (e.g. to a database connection pooler, according to the connection manager configured);
  • public boolean initPooler(HttpServlet servlet) – this method is called by the servlet throuth the method ConnectionManager.initConnectionSource() to initialize the database connection manager; this method must be defined to initialize the connection manager, such as a DataSource retrieved from the Application Server via JNDI mechanism.

 

OpenSwing provides some default implementations of this interface:

  • org.openswing.swing.server.DataSourceConnection – this implementation is based on the datasource defined in the Application Server; the datasource name is defined through the “dataSourceName” parameter written in web.xml file.
  • org.openswing.swing.server.PoolerConnectionSource – this implementation is based on an opensource library that provided a database connection pooler; this implementation can be used when no DataSource object is available, e.g. with Tomcat.

    This class requires a file names "pooler.ini" stored in “WEB-INF/classes/” folder and having the following properties:

    •  "logLevel" – possible values: debug = 4, info = 3, warn = 2, error = 1, fatal = 0

    •  "driverClass" – JDBC driver class name

    •  "maxCount" – maximum number of opened connections inside the pooler

    •  "minCount" – minimum number of opened connections inside the pooler

    •  "user" - database username

    •  "password" – database password

    •  "url" - JDBC database connection URL

    •  "loginTimeout" - timeout (in seconds) on database login ("0" no timeout)

    •  "holdTimeout" - timemout (in seconds) on holding opened a connection

    •  "waitTimeout" - timeout (in milliseconds) on waiting an available connection

    The following are pre-defined:

    •  "logLevel" = 1

    •  "maxCount" = 5

    •  "minCount" = 1

    •  "loginTimeout" = 0

    •  "holdTimeout" = 1000

    •  "waitTimeout" = 10000

  • org.openswing.swing.server.NoConnectionSource – this implementation can be used when no database is requiredm such as with applications that read/write files.

 

Of course a programmer can define a custom implementation of ConnectionSource interface, according to the needs.

 

6.1.4 Server-side log

A singleton class org.openswing.swing.logger.server.Logger is available on the server-side layer to log messages and can be referred from any action class; this class supports the following static log methods:

  • public void error(String username, String className, String methodName, String errorMessage, Throwable exception)
  • public void debug(String username, String className, String methodName, String debugMessage)
  • public void warn(String username, String className, String methodName, String warnMessage)
  • public void info(String username, String className, String methodName, String infoMessage)
    used to log error conditions, debug messages, warnings and information messages respectively.


This class is intialized by the Controller servlet during servlet initialization: the init() method of Logger class is called and an object of org.openswing.swing.logger.server. LoggerMethods is passed as argument; LoggerMethods is an interface that declare the 4 log methods described above. Logger class redirects all info, warn, debugm error calls to the analogous methods in LoggerMethods implementation class.


OpenSwing provides two implementation of LoggerMethods interface:

  • org.openswing.swing.logger.server . ConsoleLogger – to log messages to console
  • org.openswing.swing.logger.server.Log4JLogger - to redirect log messages to the open-source library Log4J.

 

 

6.2 Utility class useful for data access

OpenSwing provides a utility class that allows to map value objects to SQL instructions for data reading (queries) or data saving (insert, update). This class simplify ORM mapping (Object-To-Relational Mapping) activity, between value objects used in presentation tier and database where these objects are stored in a entity-relational model.

The singleton class org.openswing.swing.server.QueryUtil provides the following utility methods:

  • public static Response getQuery(Connection conn, UserSessionParameters userSessionPars, String baseSQL, ArrayList values, Map attribute2dbField, Class valueObjectClass, String booleanTrueValue, String booleanFalseValue, ServletContext context, boolean logQuery) – execute SQL statement defined by the “baseSQL” argument, related to a query SQL instruction that must return only one record (a detail query) and create a value object via reflection mechanism of type “valueObjectClass”; the value object created is filled with the values read from the select fields; the mapping between query's select fields and value object's attributes is defined through the hashtable passed as “attribute2dbField” attribute, that contains associations: <attribute name, select field>; the select field must be written exactly as it occours in the select (e.g. “tablename.fieldname”).
    The arguments “booleanTrueValue” and “String booleanFalseValue” are used to decode varchar fields into Boolean type attributes, that will be binded to check-box on the client-side.


    The argument “logQuery” define whether log the query to execute.


    This method returns as response an object of type ErrorResponse in case of errors or otherwise an object of type VOResponse containing the value object just created.

  • public static Response getQuery(Connection conn, UserSessionParameters userSessionPars, String baseSQL, ArrayList values, Map attribute2dbField, Class valueObjectClass, String booleanTrueValue, String booleanFalseValue, ServletContext context, GridParams gridParams , boolean logQuery) – execute SQL statement related to a query SQL instruction that must return a list of records (a grid query) and create a list of value objects via reflection mechanism of type “valueObjectClass”; the value objects created are filled with the values read from the select fields; the mapping between query's select fields and value object's attributes is defined through the hashtable passed as “attribute2dbField” attribute, that contains associations: <attribute name, select field>; the select field must be written exactly as it occours in the select (e.g. “tablename.fieldname”).
    The SQL really executed is the concatenation of the “baseSQL” with optional filters conditions and sorting conditons included in GridParams type argument.


    The arguments “booleanTrueValue” and “String booleanFalseValue” are used to decode varchar fields into Boolean type attributes, that will be binded to check-box on the client-side.


    The argument “logQuery” define whether log the query to execute.


    This method returns as response an object of type ErrorResponse in case of errors or otherwise an object of type VOListResponse containing the list of value objects just created.


    Thr resultset generated from the query execution is completely read, so that the list of value objects is related to whole resultset. The VOListResponse object contains also the number of records read and a flag “moreRows” indicating if there are other records to read next the ones just read: since the resultset is completely read, the flag is always set to “false”.

  • public static Response getQuery(Connection conn, UserSessionParameters userSessionPars, String baseSQL, ArrayList values, Map attribute2dbField, Class valueObjectClass, String booleanTrueValue, String booleanFalseValue, ServletContext context, GridParams gridParams, int blockSize , boolean logQuery) – execute SQL statement related to a query SQL instruction that must return a list of records (a grid query) and create a list of value objects via reflection mechanism of type “valueObjectClass”; the value objects created are filled with the values read from the select fields; the mapping between query's select fields and value object's attributes is defined through the hashtable passed as “attribute2dbField” attribute, that contains associations: <attribute name, select field>; the select field must be written exactly as it occours in the select (e.g. “tablename.fieldname”).
    The SQL really executed is the concatenation of the “baseSQL” with optional filters conditions and sorting conditons included in GridParams type argument.


    The arguments “booleanTrueValue” and “String booleanFalseValue” are used to decode varchar fields into Boolean type attributes, that will be binded to check-box on the client-side.


    The argument “logQuery” define whether log the query to execute.


    This method returns as response an object of type ErrorResponse in case of errors or otherwise an object of type VOListResponse containing the list of value objects just created.


    Thr resultset generated from the query execution is scrolled until the position indicated by the GridParams.getStartPos() and records are read starting from this point: for each record read a value object is created and filled with the select field values; the reading algorithm read at most “blockSize” records. The VOListResponse object contains also the number of records read (at most “blockSize” records) and a flag “moreRows” indicating if there are other records to read next the ones just read.


    This method must be invoked to read a block of rows at a time, i.e. when the resultset has big dimensions and so fully resultset read is not realistic, because it requires too much time and too much memory.

  • public static Response getQuery(Connection conn, UserSessionParameters userSessionPars, String select, String from, String where, String group, String having, String order, ArrayList values, Map attribute2dbField, Class valueObjectClass, String booleanTrueValue, String booleanFalseValue, ServletContext context, GridParams gridParams, int blockSize , boolean logQuery) – as the previous method, but the base SQL is expressed as the composition of several arguments: select, from, where (optional: can be null or ""), group (optional: can be null or ""), having (optional: can be null or ""),order (optional: can be null or ""). This solution can be useful with complex queries (such as nested selects or unions).
  • public static String getSql(UserSessionParameters userSessionPars, String baseSQL, ArrayList values, Map filteredColumns, ArrayList currentSortedColumns, ArrayList currentSortedVersusColumns, Map attributesMapping) – returns a SQL script composed of the concatenation of “baseSQL” argument and optional filter conditions and sorting conditions specified through GridParams argument. This method can independently from getQuery() methods to perform a custom data access logic, not based on ORM mapping described above.
  • public static String getSql(UserSessionParameters userSessionPars, String select, String from, String where, String group, String having, String order, ArrayList values, Map filteredColumns, ArrayList currentSortedColumns, ArrayList currentSortedVersusColumns, Map attributesMapping) – returns a SQL script composed of the concatenation of “baseSQL” expressed as the composition of several arguments and optional filter conditions and sorting conditions specified through GridParams argument. This method can independently from getQuery() methods to perform a custom data access logic, not based on ORM mapping described above. "baseSQL" is defined through: select, from, where (optional: can be null or ""), group (optional: can be null or ""), having (optional: can be null or ""),order (optional: can be null or ""). This solution can be useful with complex queries (such as nested selects or unions).
  • public static Response insertTable(Connection conn, UserSessionParameters userSessionPars, ValueObject vo , String tableName, Map attribute2dbField, String booleanTrueValue, String booleanFalseValue, ServletContext context, boolean logSQL) – execute an insert SQL statement, starting from the value object passed as argument; the “attribute2dbField” argument contains associations <attribute name, database field>; the SQL is composed from the collection of attributes defined in “attribute2dbField” argument: all database fields mapped in this argument contribute to SQL definition;
    The arguments “booleanTrueValue” and “String booleanFalseValue” are used to decode varchar fields into Boolean type attributes, that will be binded to check-box on the client-side.


    The argument “logQuery” define whether log the SQL to execute.


    This method returns as response an object of type ErrorResponse in case of errors or otherwise an object of type VOResponse containing the value object just inserted.

  • public static Response insertTable(Connection conn, UserSessionParameters userSessionPars, ArrayList vos , String tableName, Map attribute2dbField, String booleanTrueValue, String booleanFalseValue, ServletContext context, boolean logSQL)
  • execute insert SQL statement for each value object in the list passed as argument; the “attribute2dbField” argument contains associations <attribute name, database field>; the SQL is composed from the collection of attributes defined in “attribute2dbField” argument: all database fields mapped in this argument contribute to SQL definition;
    The arguments “booleanTrueValue” and “String booleanFalseValue” are used to decode varchar fields into Boolean type attributes, that will be binded to check-box on the client-side.


    The argument “logQuery” define whether log the SQL to execute.


    This method returns as response an object of type ErrorResponse in case of errors or otherwise an object of type VOListResponse containing the list of value object just inserted.

  • public static Response updateTable(Connection conn, UserSessionParameters userSessionPars, HashSet pkAttributes, ValueObject oldVO, ValueObject newVO, String tableName, Map attribute2dbField, String booleanTrueValue, String booleanFalseValue, ServletContext context, boolean logSQL ) – execute an update SQL statement, starting from the two value objects passed as arguments: the old v.o. that represents the current record in the database and the new v.o. that represents the updated record; the “attribute2dbField” argument contains associations <attribute name, database field>; the SQL is composed from the collection of attributes defined in “attribute2dbField” argument: all database fields mapped in this argument contribute to SQL definition: the SET part is composed using the new v.o. that represents the updated record and the WHERE part is composed from the old v.o. that represents the current record in the database + the primary key of the table that is defined through the “pkAttributes” argument. In this way the update operation is performed only if the record to update has not been modified after the record reading that produced the old value object.
    The arguments “booleanTrueValue” and “String booleanFalseValue” are used to decode varchar fields into Boolean type attributes, that will be binded to check-box on the client-side.


    The argument “logQuery” define whether log the SQL to execute.


    This method returns as response an object of type ErrorResponse in case of errors or otherwise an object of type VOResponse containing the value object just updated.

 

A programmer can exploit these methods inside the action classes to implement the business logic.

6.3 Utility class to use with Hibernate

It is possible to combine Hibernate and OpenSwing graphics components. To facilitate data reading from Hibernate ORM layer for a GridControl, a utility class is provided: org.openswing.swing.util.server.HibernateUtils. This class provides two utility methods that wrap Query usage:

  • getAllFromQuery - fetch all data retrieved through a Query object, starting from a Session object; this method requires some arguments provided by the GridControl's DataLocator to automatically apply filtering/sorting conditions
  • getBlockFromQuery - fetch a page of data (the first one, the latter, the next/previous) retrieved through a Query object, starting from a Session object; this method requires some arguments provided by the GridControl's DataLocator to automatically apply filtering/sorting conditions

By means of these methods, it is possible to automatize data fetching for a GridControl, by supporting pagination, data filtering and data sorting.

See "demo17" sample application to see an example of usage of Hibernate and OpenSwing.

 

6.4 Utility class to use with iBatis

It is possible to combine iBatis and OpenSwing graphics components. To facilitate data reading from iBatis ORM layer for a GridControl, two utility classes are provided: org.openswing.swing.util.server.IBatisUtils and org.openswing.swing.util.server.IBatisParamsWrapper. The first class provides a utility method that wraps iBatis's queryForList usage:

  • getBlockFromQuery - fetch a page of data (the first one, the latter, the next/previous) retrieved through a SqlMapClient object; this method requires some arguments provided by the GridControl's DataLocator to automatically apply filtering/sorting conditions. This operations are accomplished by means of the IBatisParamsWrapper class that maps grid's attributes with iBatis object attributes.

By means of this method, it is possible to automatize data fetching for a GridControl, by supporting pagination, data filtering and data sorting.

See "demo19" sample application to see an example of usage of iBatis and OpenSwing.

 

6.5 Utility class to use with JPA/EJB 3/TopLink Essentials

JPA (Java Persistence API) requires Java 5 EE or SE (JDK 1.5 or 1.6).

There are several implementations of object persistence (such as TopLink Essentials or Hibernate Entity Manager) based on JPA. It is possible to combine JPA and OpenSwing graphics components. To facilitate JPA data reading for a GridControl, a utility class is provided: org.openswing.swing.util.server.JPAUtils. This class provides two utility methods that wrap Query usage:

  • getAllFromQuery - fetch all data retrieved through a Query object, starting from a EntityManager instance; this method requires some arguments provided by the GridControl's DataLocator to automatically apply filtering/sorting conditions
  • getBlockFromQuery - fetch a page of data (the first one, the latter, the next/previous) retrieved through a Query object, starting from a EntityManager instance; this method requires some arguments provided by the GridControl's DataLocator to automatically apply filtering/sorting conditions

By means of these methods, it is possible to automatize data fetching for a GridControl, by supporting pagination, data filtering and data sorting.

See "demo35" sample application to see an example of usage of JPA/TopLink Essentials and OpenSwing.

 

<< Previous Chapter | Next Chapter >>

Licence | Contacts | ©2007 Mauro Carniel SourceForge.net Logo