home
products
education
support
partners
company

introduction

get started

articles

manual

tutorials

reference docs

case studies

knowledge base

goodies

screenshots

demos

echoes

Carousel zone


SourceForge.net Logo

home

forums

downloads

bugs

mailing list
XUI Zone - manual

number of ratings 0
average rating 0.00

26 Advanced Routes and Services

[This is a feature of Carousel]

This chapter will look at how routes and services can be used to hook the XUI client application up to webservers. The first piece of functionality to be covered is handling session management and user authentication. In order to do this the built-in servlet session and authentication service proxy classes are used to make up a route.

Session Management and User Authentication

Code Sample 26-1 - The client side routes.xml file

This route is made up of two service proxy layers. The first will take care of handling session management with a servlet engine. The second is a service proxy which passes the routed data to a servlet. The service proxy attributes should now be pointed out. The selfmanaged attribute of the SessionManager lets the class know that it should take care of storing and forwarding the session key. The modelid attribute informs the SessionManager of the path within the datamodel where the session id is to be stored once retrieved. The URL attribute of the XHttpClientServiceProxy class informs it of the URL which will receive the routed data.

In order for the servlet engine to receive the requests, the datasets, routes, services and starup file need to be packaged and deployed to the servlet engine along with the Carousel.jar library. The server needs its own startup.properties file and its own routes file. The startup file which the XServiceServlet class uses by default is carouselserver.properties . If this needs to be different the XServiceServlet will need to be subclassed and its protected startupFile variable will need to be set.

Code Sample 26-2 - The carouselserver.properties file

ModelData=serverdatasets.xml

The startup file thus points to another file detailing the data sources:

Code Sample 26-3 - The serverdatasets.xml file

.

If the KalIDEoscope editor is being used to setup the routes and services these files will be created in the resources/server directory.

Code Sample 26-4 - The serverroutes.xml file

The server version of the file has a single service proxy layer as compared to its client counterpart which has two. The code to setup and call the service now needs to be written.

Code Sample 26-5 - Code to call the ServletRoute service

XBaseModel model = ( XBaseModel ) XProjectManager.getModel().get( "ServletService" );

XServiceModelNode node = ( XServiceModelNode ) model.get();

ServiceContext context = new ServiceContext();

ServiceProxyArgs args = context.getArgs();

Object result = node.get( context );

System.out.println( args.getReturnParam( SessionManager.ARG_NAME_RETURN_SESSION ) );

There are no parameters required for the call and the established session key can be output using the return parameters. If this route is used again it will take care of synchronising the client with the already established server session. If the developer wishes to take over control of handling the session key the selfmanaged attribute should be set to false on the client routes file. The call now needs to be changed to pass the session key and to store it when it returns. It is important to note that the SessionManager will work with the selfmanaged attribute set to true only if the same route is used every time for contacting the webserver. If the SessionManager is going to be used in several routes then the selfmanaged attribute should be set to false and the developer should taked care of storing and passing the sessionkey for each call. Alternatively the modelid attribute can be set which informs the SessionManager of the path into the data model where the session key is stored between calls.

Code Sample 26-6 - Modified code to pass and store the sessionkey

private String sessionKey;

private void call()

{

XBaseModel model = ( XBaseModel ) XProjectManager.getModel().get( "ServletService" );

XServiceModelNode node = ( XServiceModelNode ) model.get();

ServiceContext context = new ServiceContext();

ServiceProxyArgs args = context.getArgs();

args.setPassParam( SessionManager.ARG_NAME_PASS_SESSION, sessionKey );

Object result = node.get( context );

sessionKey = ( String ) args.getReturnParam( SessionManager.ARG_NAME_RETURN_SESSION );

}

Now that the session is being synchronised between the client and server, user authentication can be built into the route. There is a user authentication service proxy built into Carousel which needs to be subclassed in order to be used on the server side. The default class can be used on the client. This subclass is defined below.

Code Sample 26-7 - The LogonService service proxy

package net.xoetrope.mortgage.services;

import com.xoetrope.service.AuthenticationService;

public class LogonService extends AuthenticationService

{

protected boolean checkCredentials( String userID, String password )

{

if ( userID.compareTo( "joe" ) == 0 )

return true;

else

return false;

}

}

checkCredentials() is the overloaded function which is used on the server to check the logon credentials of the passed userid and password. Of course, a little more work needs to be done in order to carry out a meaningful authentication. The modified client and server route files are as follows:

Code Sample 26-8 - The client side routes.xml file

and on the server side the equivalent file is:

Code Sample 26-9 - The server side serverroutes.xml file

The client side route uses the basic authentication service proxy whereas its counterpart on the server uses the LogonService subclass. The LogonService could just as easily be used on the client but the developer may not want to make their server logic available for decompilation.

Creating a custom client-server service proxy

This next example will take the FileSave and StateManager service proxy classes discussed in the previous chapter and merge them in a route with the SessionManager and LogonService service proxy classes in order to save the application data on a webserver. First modify the two route files to declare the new route which is to be utilised.

Code Sample 26-10 - The modified client-side routes.xml file

Code Sample 26-11 - The modified server-side serverroutes.xml file

again, the server-side equivalent is:

The StateManager layer is omitted from the server side route because it only manipulates data on the client. So now it is possible, using the same service proxy classes that were used to save data on the client machine, to persist that same data to the server in a seamless way. There is a new service proxy class, ServletFileSave , defined which takes care of the server side saving of the data. There is another difference between the client and server route definitions and that is the savepath attribute which is set for the ServletFileSave service proxy on the server. This is the location where files will be stored on the server.

Code Sample 26-12 - The ServletFileSave class

package net.xoetrope.mortgage.service;

import com.xoetrope.service.file.FileSave;

import java.io.File;

import java.util.Hashtable;

import net.xoetrope.optional.service.ServiceContext;

import net.xoetrope.optional.service.ServiceProxyArgs;

import net.xoetrope.optional.service.ServiceProxyException;

import net.xoetrope.optional.service.XRouteManager;

public class ServletFileSave extends FileSave {

private String savePath = null;

public Object call( String method, ServiceContext context )

{

Object ret = null;

ServiceProxyArgs args = context.getArgs();

try {

String mode = ( String )args.getPassParam( ARG_NAME_MODE );

if ( side == XRouteManager.CLIENT_SIDE ) {

ret = callNextProxy( method, context, null );

}

else {

if ( mode.compareTo( ARG_VALUE_SAVE ) == 0 )

saveFile( savePath + File.separatorChar +

args.getPassParam( ARG_NAME_FILENAME ).toString(),

args.getPassParam( ARG_NAME_CONTENTS ).toString() );

else if ( mode.compareTo( ARG_VALUE_OPEN ) == 0 )

args.setReturnParam( ARG_NAME_CONTENTS,

openFile( savePath + File.separatorChar +

args.getPassParam( ARG_NAME_FILENAME ).toString() ) );

ret = callNextProxy( method, context, null );

}

}

catch ( ServiceProxyException e ) {

e.printStackTrace();

}

return ret;

}

public void setAttributes( Hashtable attribs )

{

if ( side == XRouteManager.SERVER_SIDE )

savePath = ( String )attribs.get( "savepath" );

}

}

The setAttributes function overloads the same function in the service proxy super class and is called when the route is first created. In this example, the savePath variable will only be set when the route is on the server side. In the call function a similar check is made to see which side the service proxy is operating on. On the client side the call is merely proxied to the next service proxy and on the server side the saveFile and openFile methods of the super class are used to save and open the files. The only change in the calling code is made to the name of the service which is called.

Code Sample 26-13 - The change to the code setting up the service.

XBaseModel model = ( XBaseModel ) XProjectManager.getModel().get( "ServletService" );

Using datasets to attach to a database

This section will take a look at how to use a datasets file to define a database connection and how to use it to retrieve data from the database. The first thing to be done is to create the database.xml file.

Code Sample 26-14 - The database.xml file

The datasets file needs to contain at least one Connection entry which is used to establish the database connection. In this example the database being used is a MySQL database on the localhost machine. It will be located on the webserver and the database.xml file needs only to be deployed on the server. The Connection entry has several attributes which are explained as follows:

Table 26-1 -

Attribute

Description

id

The name of the 'Connection'. This is used by the 'ResultSet' elements so that the correct connection is used in retrieving data.

driver

The jdbc driver class which is used to establish connections

url

The database connection URL

user

The user which is to be used to connect to the database

pwd

The password of the user

There are two ResultSet declarations defined both of which are given an id. The conn attribute defines the Connection against which the query is to be run. In the two ResultSet elements defined, PreparedStatements are being used. Now that the database.xml file has been defined, it needs to be referenced by the datasets.xml file.

Code Sample 26-15 - The amended datasets.xml file

The new entry is defined as type database and uses the filename attribute to reference the new file. This example will look at how the mortgage application can used in conjunction with the database to send and retrieve data. The first query to be implemented is SearchMortgages which will search the existing mortgage applicants and return the results to the client application. Both of the route files need to be amended to use Carousel's QueryService which will take care of running the SQL queries.

Code Sample 26-16 - The clientside routes.xml file

Code Sample 26-17 - The serverside serverroutes.xml file

Now the code which calls the new route can be written.

Code Sample 26-18 - Code to call the SearchMortgages Query

XBaseModel model = ( XBaseModel ) XProjectManager.getModel().get( "ServletService" );

XServiceModelNode node = ( XServiceModelNode ) model.get();

ServiceContext context = new ServiceContext();

ServiceProxyArgs args = context.getArgs();

args.setPassParam( QueryService.ARG_NAME_QUERYID, "SearchMortgages" );

args.setPassParam( QueryService.ARG_NAME_NUMPARAMS, 1 );

args.setPassParam( QueryService.ARG_NAME_PARAMNAME + "0", "searchtext" );

args.setPassParam( QueryService.ARG_NAME_PARAMVALUE + "0", "%" + searchEdit.getText() + "%" );

Object result = node.get( context );

System.out.println( args.getReturnParam( QueryService.ARG_NAME_RESULTSET ) );

The XServiceModelNode and ServiceContext objects are accessed in the usual way. In this example the AuthenticationService and the SessionManager service proxy classes both have their 'selfmanaged' attributes set to true so there is no need to pass the userid and sessionkey parameters. All of the parameters referenced in the code are for the QueryService service proxy. These parameters meaning is defined as follows:

Table 26-2 - The QueryService parameters

Parameter name

Description

ARG_NAME_QUERYID

The name of the Query as defined in the database.xml file which is to be executed.

ARG_NAME_NUMPARAMS

The number of parameters required to populate the PreparedStatement

ARG_NAME_PARAMVALUE

This is the name which is used for each of the PrepartedStatement parameters. It must be concatenated with the zero based index of the parameter being set

ARG_NAME_PARAMVALUE

The value of the PreparedStatement parameter. It must be concatenated with the zero based index of the parameter being set

ARG_NAME_RESULTSET

The returned data in XML format

When the new serverroutes.xml is deployed to the server the client application can be run and the ARG_NAME_RESULTSET parameter will contain data in the following format:

Code Sample 26-19 - The data return in the ARG_NAME_RESULTSET parameter

This data can be used by the developer in whatever way they see fit. It can be loaded into an XML document or loaded into the model using the XOptionalDataSource.loadTable call but in order to expand this example the data will now be used to populate a swing table. In order to make this easier a new service proxy, TransformService , will be introduced. The two route files need to be amended to make use of this service proxy layer.

Code Sample 26-20 - The clientside routes.xml file

Code Sample 26-21 - The serverside serverroutes.xml file

The TransformService will carry out a transformation on the XML data returned in the ARG_NAME_RESULTSET parameter. The transformation will be carried out by a file with the same name as the ARG_NAME_QUERYID . So in this case the transformation will be carried out by a file called SearchMortgages.xsl as shown below:

Code Sample 26-22 - The SearchMortgages.xsl file

firstname

Firstname

surname

Surname

firstname

surname

The effect that this transformation will have on the XML is as follows:

Code Sample 26-23 - The data transformed through the SearchMortgages.xsl file

This is the format which is used by the XTable2 class in the XUI optional package. In order to carry out this binding, the calling code needs to be changed once more.

Code Sample 26-24 - Use the transformed XML to populate the XTable2 table

public void doSearch()

{

XBaseModel model = ( XBaseModel ) XProjectManager.getModel().get( "ServletService" );

XServiceModelNode node = ( XServiceModelNode ) model.get();

XBaseModel searchMdl = ( XBaseModel )XProjectManager.getModel().get( "searchresults/applicants" );

searchMdl.clear();

ServiceContext context = new ServiceContext();

ServiceProxyArgs args = context.getArgs();

args.setPassParam( QueryService.ARG_NAME_QUERYID, "SearchMortgages" );

args.setPassParam( QueryService.ARG_NAME_NUMPARAMS, 1 );

args.setPassParam( QueryService.ARG_NAME_PARAMNAME + "0", "searchtext" );

args.setPassParam( QueryService.ARG_NAME_PARAMVALUE + "0", "%" + searchEdit.getText() + "%" );

node.get( context );

System.out.println( args.getReturnParam( QueryService.ARG_NAME_RESULTSET ) );

addResultsTable( searchMdl );

repaint();

doLayout();

}

private void addResultsTable( XBaseModel mdl )

{

if ( tbl != null )

remove( tbl.getParent().getParent() );

tbl = new XBaseTable( this, 200, 100, 400, 200 );

XTableModelAdapter tma = new XTableModelAdapter( mdl );

tbl.setTableModelAdapter( tma, null );

tbl.setHeaderStyle( "tableheader" );

repaint();

}

The addResultsTable takes the ARG_NAME_RESULTSET xml and uses it to construct an XTableModelAdapter . A style is applied to the table and the page is repainted and the doLayout function is called.

Binding a ResultSet to screen components

The user will now want to select an applicant from the table and open up the individual record for editing. The second ResultSet is used to retrieve the data and its data is transformed once more using the TransformService . The code to call the service is as follows:

Code Sample 26-25 - Code to retrieve an applicants details

public void openApplication()

{

if ( wasMouseClicked() ) {

int row = tbl.getSelectedRow();

XBaseModel mdl = tbl.getRow( row );

String appID = ( String )( ( XBaseModel ) mdl.get( "application_id" ) ).get();

XModelHelper.setTempVar( "selectedMortgage", appID );

XBaseModel model = ( XBaseModel ) XProjectManager.getModel().get( "ServletQuery" );

XServiceModelNode node = ( XServiceModelNode ) model.get();

XBaseModel mortMdl = ( XBaseModel )XProjectManager.getModel().get( "MortApp" );

mortMdl.clear();

ServiceContext context = new ServiceContext();

ServiceProxyArgs args = context.getArgs();

args.setPassParam( "Mode", "Query" );

args.setPassParam( "QueryType", "RetrieveMortgage" );

args.setPassParam( "ModelPath", "currentISO" );

args.setPassParam( "numParams", 1 );

args.setPassParam( "paramname0", "appID" );

args.setPassParam( "paramvalue0", appID );

Object result = node.get( context );

XModelHelper.setTempVar( "currentID", mortMdl.get( 0 ).getId() );

pageMgr.showPage( "Personal" );

}

}

A new XSL file needs to be defined for the RetrieveMortgage query which will transform the result set data into a format which can be used by the front end.

Code Sample 26-26 - XSL file to transform the RetriveMortgage query

When the data is returned the screens will populate with the data which has been returned by the query.

Using KalIDEoscope to edit the routes

As seen in the previous chapter, the KalIDEoscope editor can be used to build up routing information for a project. It is now worth looking at the steps involved in setting up the routes at the beginning of this chapter using the editor. Open the route manager and set up the client side route as shown below.

Now the corresponding server side route can be set as shown below.

IF the project is saved now the client route file resources/routes.xml will contain the ServletRoute with layers for SessionManager and XHttpClientServiceProxy and the server routes file resources/server/serverroutes.xml will contain the ServletRoute with a single layer for the ServerSessionManager .

In order to create the custom Authentication service, right click on the server side ServletRoute , click New ServiceProxy Layer and select net.xoetrope.service.AuthenticationService from the list of ServiceProxy classes. When the AuthenticationService is selected from the list of ServiceProxy classes the New ServiceProxy dialog is shown as below.

The reason for this is that the AuthenticationService class is defined as an abstract class and as such needs to be subclassed in order to be used. The reason for this is that the project specific authentication code needs to be written for the checkCredentials function. The default classes package has the services package appended to it and is shown in the class name text field. The new class name should be appended to the package name. The Base Class dropdown is automatically set to com.xoetrope.service.AuthenticationService . The attributes which have been inherited from the base class are listed in the attributes section. This is so that these attributes can also be set for the new class. It is possible to add custom attributes if necessary. Select the Create the class checkbox and click OK and the new class will be created and opened for you in the netBeans editor. If you check the ServerRoute you will see that the new LogonService ServiceProxy has been added as a layer in the route.

The checkCredentials function now needs to be overloaded in order to take care of the server side authentication.

Now it's just a simple matter of adding the new LogonService as a layer into the client ServerRoute . Save the project and open the customroutedefs.xml file and it should appear something like follows.

Code Sample 26-27 - The customroutedefs.xml file

comments


If you were logged in you could rate this article or add a comment.