Last week we used the Eclipse WTP Web service Wizard to create the TZA Property Insurance Web service. We automatically created a series of plumbing code (within the com.teradata.tza.insurance.service and com.teradata.schemas.tza.insurance.service packages) plus a single Implementation (PropertyInsuranceSoapBindingImpl.java) class that the author is expected to customize. This class provides an SOA Presentation Veneer (User Interface) that can act as an entry point into the TZA-InsuranceService Business Process.

This week we will demonstrate how to "Wire" up the different parts of the project in order to connect the Web service Presentation Veneer into the Business Process, Business Objects and Repository layer and therefore on through to the database and the data tables.

Return to the TZA-InsuranceService project by starting Eclipse and opening up the FridayNightProject workspace.

Workspace Launcher

Add external Libraries / JAR files to the "/lib" directory.

Within a Dynamic Web application where we wish to use external Libraries or JAR files we place them into the WEB-INF/lib directory. WTP created this when the TZA-InsuranceService project was created and the Web services Wizard added specific Jar files required for doing Axis based Web services.

Project Explorer with WTP Base Libraries

Now when we need to add an external library such as Log4j we can download a copy of the required library (typically these downloads come as a large .ZIP or .TAR file from which you can extract any required jar files using an approach appropriate to your Operating System, such WinZip on Windows) and save the required jar files to the WEB-INF/lib directory of your project (i.e. C:\Projects\FridayNightProject\TZA-InsuranceService\web\WEB-INF\lib).

Add JDBC Driver

The first thing we do to populate the TZA-InsuranceService project is add the JDBC JAR files to the WEB-INF/lib folder.

  • Add the Teradata JDBC Driver JAR’s you downloaded and used as part of the getting-started-with-teradata-plug-in-for-eclipse exercise.
  • Copy the two JAR files, namely tdgssconfig.jar and terajdbc4.jar from the download location (typically C:\TeraJDBC)
  • Paste them into the WEB-INF/lib folder within the TZA-InsuranceService project.

Add Apache Commons JAR's

JAR's from the Apache Commons project (http://commons.apache.org/) are used in this and other projects for Logging and Database Connection Pooling.

Externally you need to download Apache Commons Pool and Apache Commons DBCP JAR's to the WEB-INF/lib directory of the project.

Apache commons-pool can be obtained from http://commons.apache.org/pool/.

  • Download the latest commons-pool.jar file to the WEB-INF/lib directory of the TZA-InsuranceService project.

Apache commons-dbcp can be obtained from http://commons.apache.org/dbcp/.

  • Download the latest commons-dbcp.jar file to the WEB-INF/lib directory of the TZA-InsuranceService project.

Note commons-logging.jar was added to WEB-INF/lib last week by the Eclipse WTP Web service Wizard so you don’t need to do it manually.

Add spring-framework JAR

We will be using the spring-framework to wire our application together. Download the spring-framework from http://www.springframework.org/download and extract spring.jar into your WEB-INF/lib directory.

  • Download the latest spring.jar file to the WEB-INF/lib directory of the TZA-InsuranceService project.

Add Log4J.

Log4J is used to implement the Logging Interface used within commons-logging. Download the log4j package from http://logging.apache.org/log4j/1.2/download.html. Extract the latest log4j.jar file (at the time of writing this was Log4j.1.2.15.jar) in to your WEB-INF/lib directory.

  • Download the latest log4j.jar file to the WEB-INF/lib directory of the TZA-InsuranceService project.

Add tdcommons-context.

We use Context Capture to maintain a record of application context throughout the Thread of Execution. To utilize this Teradata Common Component download tdcommons-context.ZIP and unzip tdcommons-context.jar into your WEB-INF/lib directory.

  • Select tdcommons-context.zip (Open with WinZip) and export tdcommons-context.jar into the WEB-INF/lib directory of the TZA-InsuranceService project.

Add tdcommons-access.

The Teradata Access approach is used to provide a consistent approach to accessing a Teradata Database through a JDBC based Data Source / Connection Pool. To utilize this Teradata Common Component download tdcommons-access.ZIP and unzip tdcommons-access.jar into your WEB-INF/lib directory.

  • Select tdcommons-access.zip (Open with WinZip) and export tdcommons-access.jar into the WEB-INF/lib directory of the TZA-InsuranceService project.

Add TZA-InsuranceProcess

TZA-InsuranceProcess provides a utility JAR file that ultimately will contain all of the Business Processes used within TZA-Insurance (for now it only contains the Simple Quotation Engine we built a couple of weeks ago).

  • Within the TZA-InsuranceProcess project Right Click on TZA-InsuranceProcess.jar within the /dist directory and select Copy.
  • Paste this file into the WEB-INF/lib directory of the TZA-InsuranceService project.

Refresh Eclipse

Whenever changes are made to the directory structure of an Eclipse Project (out with the Eclipse environment i.e. when exporting from WinZip to the hard disk directly) it is necessary to let Eclipse know what is going on "under the covers".

  • Select the TZA-InsuranceConsole project and use the F5 function key to refresh the environment
  • Alternatively Right Click on TZA-InsuranceConsole and select the Refresh option.

WEB-INF/lib Classpath reference

As this is a Dynamic Web application all libraries held within WEB-INF/lib are automatically considered to be on the application classpath. There is no need to make a specific User Library reference to them. The completed WEB-INF/lib directory structure will look like this.

Project Explorer with Final IS Libraries

Creating the getQuote Method

Last week we hard coded the getQuote Web service method of the TZA Property Insurance Web service (PropertyInsuranceSoapBindingImpl) as so:

    public com.teradata.schemas.tza.insurance.service.QuoteResponse
        getQuote(com.teradata.schemas.tza.insurance.service.QuoteRequest quoteRequest)
            throws java.rmi.RemoteException, com.teradata.tza.insurance.service.ParameterFault 
    {
    	// Initialize the QuoteReponse and QuotationDetails
    	com.teradata.schemas.tza.insurance.service.QuoteResponse quoteResponse =
    		new com.teradata.schemas.tza.insurance.service.QuoteResponse();

    	com.teradata.schemas.tza.insurance.service.QuotationDetails quotationDetails =
    		new com.teradata.schemas.tza.insurance.service.QuotationDetails();

    	quotationDetails.setClientOrgCode(quoteRequest.getClient().getOrgCode());
    	quotationDetails.setCurrencyCode("USD");
    	quotationDetails.setExpiryDate(new java.util.Date());
    	quotationDetails.setQuotation(new java.math.BigDecimal("100.00"));
        quotationDetails.setReferenceNumber(new Integer(new java.util.Random().nextInt()).toString());

        // Add the QuotationDetails to the QuoteResponse
        quoteResponse.setQuotation(quotationDetails);

        return quoteResponse;
    }

This was fine for our initial stab at creating, demonstrating and testing a Web service Presentation Veneer, where we were concentrating on the mechanics of WS-I, Contract First Web service development. However, now we need to get back to understanding the Business Service or Process this Presentation Veneer is intended to represent.

If you recall, the getQuote Web service method of the TZA Property Insurance Web service, implemented by PropertyInsuranceSoapBindingImpl.java, provides a means to request a Property/House insurance quotation based upon the fundamental characteristics of the Property/House to be insured. The base quotation calculation is done based upon physical characteristics such as Property value, age, number of rooms, security status etc, however the ultimate arbiter of the calculation (all other property details being equal) is the Risk Factors associated with the physical location of the property, which for TZA-Insurance means the US Zip Code (so bigger than just Kansas Toto).

Two weeks ago (FNP #7 – A Console Veneer) we showed how to provide a simple Console Application Presentation Veneer on top of the Simple Quotation Engine business process embodied within the TZA-InsuranceProcess.jar. Within that example we hard coded all of the variables about the “Canary Property” except for the ZipCode, which we took as our single input parameter from the console or command line.
In order to implement the getQuote Web service method we need to understand that ALL of the parameters associated with the Property that we wish to obtain an insurance quotation for will be provided as part of the Stateless Web service call and will require to be validated prior to their application to the underlying (Simple) Quotation Engine.

However, for the purposes of this simple example we will rightly assume that the WTP Web service, auto generated code (that implements both the Client and Server side of the TZA Property Insurance Web service) is correct and that we only need to validate the correctness of the information provided such as is the State Code provided even a valid US State (ie. AL, CA, TX, etc).

State Code Validator

The only real validation we do, within this stage of the Friday Night Project, is to check that the State Code provided as part of the getQuote Web service method actually exists. As we may wish to provide for other validation routines / processes later we create a new package to contain the validation routines associated with this Presentation Veneer.

Create a new package within src/java to hold the validation routines

  • Right Click on src/java and select New -> Class
  • Set the Package Name to "com.teradata.tza.insurance.service.validation".
  • Set the class Name to StateValidator.
  • Click Finish and a template source file will open within the Eclipse editor.
package com.teradata.tza.insurance.service.validation;

public class StateValidator {

}

The StateValidator class can then be built up by replacing the template code with the following code segment within the StateValidator.java file using copy and paste:

package com.teradata.tza.insurance.service.validation;

public class StateValidator 
{
	java.util.Hashtable<String, String> validStateCodes = new java.util.Hashtable<String, String> ();

	public StateValidator()
	{
		validStateCodes.put("AL", "AL");
		validStateCodes.put("AK", "AK");
		validStateCodes.put("AS", "AS");
		validStateCodes.put("AZ", "AZ");
		validStateCodes.put("AR", "AR");
		validStateCodes.put("CA", "CA");
		validStateCodes.put("CO", "CO");
		validStateCodes.put("CT", "CT");
		validStateCodes.put("DE", "DE");
		validStateCodes.put("DC", "DC");
		validStateCodes.put("FM", "FM");
		validStateCodes.put("FL", "FL");
		validStateCodes.put("GA", "GA");
		validStateCodes.put("GU", "GU");
		validStateCodes.put("HI", "HI");
		validStateCodes.put("ID", "ID");
		validStateCodes.put("IL", "IL");
		validStateCodes.put("IN", "IN");
		validStateCodes.put("IA", "IA");
		validStateCodes.put("KS", "KS");
		validStateCodes.put("KY", "KY");
		validStateCodes.put("LA", "LA");
		validStateCodes.put("ME", "ME");
		validStateCodes.put("MH", "MH");
		validStateCodes.put("MD", "MD");
		validStateCodes.put("MA", "MA");
		validStateCodes.put("MI", "MI");
		validStateCodes.put("MN", "MN");
		validStateCodes.put("MS", "MS");
		validStateCodes.put("MO", "MO");
		validStateCodes.put("MT", "MT");
		validStateCodes.put("NE", "NE");
		validStateCodes.put("NV", "NV");
		validStateCodes.put("NH", "NH");
		validStateCodes.put("NJ", "NJ");
		validStateCodes.put("NM", "NM");
		validStateCodes.put("NY", "NY");
		validStateCodes.put("NC", "NC");
		validStateCodes.put("ND", "ND");
		validStateCodes.put("MP", "MP");
		validStateCodes.put("OH", "OH");
		validStateCodes.put("OK", "OK");
		validStateCodes.put("OR", "OR");
		validStateCodes.put("PW", "PW");
		validStateCodes.put("PA", "PA");
		validStateCodes.put("PR", "PR");
		validStateCodes.put("RI", "RI");
		validStateCodes.put("SC", "SC");
		validStateCodes.put("SD", "SD");
		validStateCodes.put("TN", "TN");
		validStateCodes.put("TX", "TX");
		validStateCodes.put("UT", "UT");
		validStateCodes.put("VI", "VI");
		validStateCodes.put("VA", "VA");
		validStateCodes.put("WA", "WA");
		validStateCodes.put("WV", "WV");
		validStateCodes.put("WI", "WI");
		validStateCodes.put("WY", "WY");
	}

	public boolean isValid(String stateCode)
	{
		return validStateCodes.containsValue(stateCode);
	}
}

PropertyInsuranceSoapBindingImpl

In order to implement the getQuote method of the TZA Property Insurance Web service, we will be overwriting sections of the PropertyInsuranceSoapBindingImpl.java file we hard coded last week. Start by replacing the entire getQuote method with the following code:

    /**
     * PropertyInsurance.getQuote(quoteRequest)
     */
    public QuoteResponse getQuote(QuoteRequest quoteRequest) throws java.rmi.RemoteException, ParameterFault
    {
        log.info("getQuote");
        
        // At first point of Application Entry (Re)Initialize ThreadLocalContext
        ThreadLocalContext.setClientUser(quoteRequest.getClient().getUsername());
        ThreadLocalContext.setGroup(quoteRequest.getClient().getOrgCode());
        ThreadLocalContext.setAction((new Exception().getStackTrace()[0].getMethodName()));
    
        /**
         * TODO Authenticate the ClientDetails, meantime Require TZA_Broker, TZA_User and TZA_Password
         */
        ClientDetails client = quoteRequest.getClient();
        if (!client.getOrgCode().equals("TZA_Broker") ||
            !client.getUsername().equals("TZA_User") ||
            !client.getPassword().equals("TZA_Password"))
        {
            ParameterFault parameterFault = new ParameterFault();
            parameterFault.setFaultString("Invalid Property Parameter");
            parameterFault.setFaultReason("Invalid ClientDetails");
            throw (parameterFault);
         }
    
        /**
         * TODO Fully check the quoteRequest parameters
         */
        StateValidator stateValidator = new StateValidator();
        if (!stateValidator.isValid(quoteRequest.getProperty().getState()))
        {
            ParameterFault parameterFault = new ParameterFault();
            parameterFault.setFaultString("Invalid Property Parameter");
            parameterFault.setFaultReason("Invalid State Code");
            throw (parameterFault);
        }
        
        // map from UI Layer PropertyDetails Object to BusinessProcess Layer Property Object
        Property property = mapProperty(quoteRequest.getProperty());
        
        // Initialize the QuoteReponse and QuotationDetails  
        QuoteResponse quoteResponse = new QuoteResponse();
        QuotationDetails quotationDetails = new QuotationDetails();
        quotationDetails.setClientOrgCode(quoteRequest.getClient().getOrgCode());
        quotationDetails.setCurrencyCode("USD");            
        quotationDetails.setReferenceNumber(new Integer(new java.util.Random().nextInt()).toString());

        // Define the Quotation Expiry Date as 30 days from now
        Calendar expiryDate = Calendar.getInstance();
        expiryDate.setTime(new Date());
        expiryDate.add(Calendar.DATE,30);
        quotationDetails.setExpiryDate(expiryDate.getTime());
        
        // Map into the WebApplicationContext through the servletContext of the TZA-InsuranceService 
        ServletContext servletContext = ((HttpServlet)MessageContext.getCurrentContext().getProperty(HTTPConstants.MC_HTTP_SERVLET)).getServletContext();
        WebApplicationContext webAppContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
        
        // finally we can load and use the quotationEngine bean that is managed by Spring 
        QuotationEngine quotationEngine = (QuotationEngine) webAppContext.getBean("sqlQuotationEngine");
        
        try
        {
            // run the Quotation Engine to get the Quotation Amount
            quotationDetails.setQuotation(quotationEngine.getQuotation(property));
            
            // Place the QuotationDetails into the Final response
            quoteResponse.setQuotation(quotationDetails);
        }
        catch (ApplicationException appEx)
        {
            ParameterFault parameterFault = new ParameterFault();
            parameterFault.setFaultString("ApplicationException");
            parameterFault.setFaultReason(appEx.toString());
            throw (parameterFault);
        }
        catch (SystemException sysEx)
        {
            ParameterFault parameterFault = new ParameterFault();
            parameterFault.setFaultString("SystemException");
            parameterFault.setFaultReason(sysEx.toString());
            throw (parameterFault);
        }
        
        return quoteResponse;
        
    } // end getQuote

As we enter the getQuote method we establish a number of the ThreadLocalContext values (based upon information in the Web service request) and validate some of the input parameters (issuing a Parameter Fault Exception if any of them are incorrect).

By convention we isolate the Presentation Veneer (UI) Layer Business Objects from the Business Service Layer Business Objects. While the com.teradata.schemas.tza.insurance.service.PropertyDetails class may seem identical to the com.teradata.tza.insurance.process.businessObject.Property class this may not always be the case so it is good practice to provide simple mapping functions to manage the transition from one domain to another. Add the following method to your code to provide the mapping:
 

    private Property mapProperty(PropertyDetails propertyDetails)
    {
	// Note: We use a local copy of the PropertyDetails when going from the User Interface to the Business Process 
    	Property property = new Property();
		
    	property.setAlarmed(propertyDetails.isAlarmed());
	property.setBuildingsAccidentalCover(propertyDetails.isBuildingsAccidentalCover());
	property.setBuildingsAmountInsured(propertyDetails.getBuildingsAmountInsured());
	property.setBuildingsCover(propertyDetails.isBuildingsCover());
	property.setCity(propertyDetails.getCity());
	property.setContentsAccidentalCover(propertyDetails.isContentsAccidentalCover());
	property.setContentsAmountInsured(propertyDetails.getContentsAmountInsured());
	property.setContentsCover(propertyDetails.isContentsCover());
	property.setHouseNameNumber(propertyDetails.getHouseNameNumber());
	property.setNumBedrooms(propertyDetails.getNumBedrooms());
	property.setOwnership(new Ownership(propertyDetails.getOwnership().toString()));
	property.setPropertyType(new PropertyType(propertyDetails.getPropertyType().toString()));
	property.setSecurityPatrolled(propertyDetails.isSecurityPatrolled());
	property.setSingleItemLimit(propertyDetails.getSingleItemLimit());
	property.setState(propertyDetails.getState());
	property.setStreetAddress1(propertyDetails.getStreetAddress1());
	property.setStreetAddress2(propertyDetails.getStreetAddress2());
	property.setStreetAddress3(propertyDetails.getStreetAddress3());
	property.setStreetAddress4(propertyDetails.getStreetAddress4());
	property.setYearBuilt(propertyDetails.getYearBuilt());
	property.setZipCode(propertyDetails.getZipCode());
        
	return property;
    }

We create the QuoteResponse and QuotationDetails objects, much as we did last week, within the getQuote method, but this time we use the Application Context (managed by the Spring Framework) to get access to the QuotationEngine that we can now use to get an actual Insurance Quotation based upon the details of the Property described in our Web service call.

To complete the code (and clear any errors) you will need the following import statements:

import com.teradata.commons.context.ThreadLocalContext;

import com.teradata.tza.insurance.process.exception.SystemException;
import com.teradata.tza.insurance.process.exception.ApplicationException;

import com.teradata.tza.insurance.process.businessObject.Property;
import com.teradata.tza.insurance.process.businessObject.Ownership;
import com.teradata.tza.insurance.process.businessObject.PropertyType;

import com.teradata.tza.insurance.process.quoteEngine.businessProcess.QuotationEngine;

import com.teradata.schemas.tza.insurance.service.*;
import com.teradata.tza.insurance.service.validation.*;

import java.util.Calendar;
import java.util.Date;

import javax.servlet.http.HttpServlet;
import javax.servlet.ServletContext;
import org.apache.axis.MessageContext;
import org.apache.axis.transport.http.HTTPConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

You will also need to define the logger you are going to use:

    /** the logger */
    private static Log log = LogFactory.getLog(PropertyInsuranceSoapBindingImpl.class);

Using the Spring Framework to wire the Presentation Veneer to the Business Process

The Spring Framework can be used to wire up the Java Objects within a Java EE applications such as Dynamic Web applications. Spring uses XML based configuration files to define which concrete implementation of a given Interface is to be used. It can also be used to include supporting libraries that your code may wish to use. In the Insurance Service Application we will use it to include the Apache DBCP Connection Pool, which is an essential part of allowing Enterprise class Web applications to operate in a responsive manner.

applicationContext.xml

To use spring we add a new XML file to the web/WEB-INF directory called applicationContext.xml. This file allows us to "wire" Plain Old Java Objects (POJO's) together and is used to configure how the application will operate.

  • Right Click on web/WEB-INF within the TZA-InsuranceService project.
  • Select New -> File and set the File Name = applicationContext.xml

New File applicationContext.xml

  • Click Finish and an empty file will open within the Eclipse editor.

The applicationContext.xml file can then be built up by adding the following context information using copy and paste.

<?xml version="1.0" encoding="UTF-8"?>
<beans
 xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Define the ApplicationDescription -->
    <bean id="applicationDescription" class="com.teradata.commons.context.ApplicationDescription">
	   <property name="applicationName" value="TZA-InsuranceService"/>
       <property name="version" value="01.00.00.00"/>
    </bean>

    <!-- Import the TZA-InsuranceProcess QuoteEngine context -->
    <import resource="classpath:com/teradata/tza/insurance/process/quoteEngine/sqlQuoteEngineAppContext.xml" />

	<!-- JDBC Teradata Access Object Session manager - Used by Quotation Engine -->
	<bean id="jdbcTaoSessionManager"
		  class="com.teradata.commons.access.JdbcTaoSessionManager">
		<property name="dataSource" ref="dataSource"></property>
		<property name="queryBandConfig" ref="queryBandConfig"></property>
	</bean>
		
    <!-- =================== Query Band Configuration Bean ==============================  -->    
    <bean id="queryBandConfig" class="com.teradata.commons.access.QueryBandConfig">
       <property name="queryBandingEnabled" value="${query-banding-enabled}"/>
    </bean>

	<!-- Property Configurer used to bring in the JDBC.Properties -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
            </list>
        </property>
    </bean>
  
   <!-- dataSource Bean based on Apache Commons Database Connection Pool using JDBC properties -->
   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="validationQuery" value="${dbcp.validationQuery}"/>
        <property name="maxWait" value="${dbcp.maxWait}"/>
        <property name="maxIdle" value="${dbcp.maxIdle}"/>
        <property name="maxActive" value="${dbcp.maxActive}"/>
	</bean>
 </beans>

The file starts by describing the namespaces that we will use within the configuration file. We define the applicationDescription Bean Properties which allows us to fill in Static Properties through configuration rather than through code. We import the sqlQuotationEngineAppContext.xml Application Context file through its fully defined class path and then define the Session Manager and Query Band Config beans. Finally we load up the jdbc.properties configuration and define the dataSource (Apache Commons DBCP Connection Pool) that we will use.

web.xml

In order to have spring use this application context it is necessary to add one line of code to the web.xml file that normally runs a Dynamic Web Application.

  • Open web.xml (TZA-InsuranceService/web/WEB-INF/web.xml and add the following:
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

web.xml with Context Listener

Configuring the JDBC Driver / Connection Pool

We use a configuration file (jdbc.properties) to manage the properties of the JDBC Connections within the DBCP Connection Pool. To add this to the runtime class path you need to place the configuration file into the src/config folder of your project.

  • Right Click on src/config within the TZA-InsuranceService project.
  • Select New -> Other.. -> General -> File -> Next ->
  • Set the File Name = jdbc.properties

New File jdbc.properties

  • Select Finish and an empty file will open within the Eclipse editor.

The jdbc.properties file can then be built up by adding the following using copy and paste.

# Properties file with JDBC-related settings.
# Applied by PropertyPlaceholderConfigurer from "applicationContext.xml".
# Targeted at system administrators, to avoid touching the context XML files.

# Teradata Instance information - 
server=Local-13
dbs.port=1025

# Name of the Default Database we are going to use
base.db=TZA_DB

# JDBC-related settings.
jdbc.driverClassName=com.teradata.jdbc.TeraDriver
jdbc.url=jdbc:teradata://${server}/DATABASE=${base.db},DBS_PORT=${dbs.port},TMODE=ANSI
jdbc.username=TZA_USER
jdbc.password=TZA_PASS

# query-banding-enabled
# Enables Query Banding. Use only for TD version 12 or higher.
query-banding-enabled=false

# DBCP-related settings.
dbcp.validationQuery=select current_timestamp
dbcp.maxWait=300
dbcp.maxIdle=10
dbcp.maxActive=50

Note you may need to change the server and dbs.port values to reflect your preferred Teradata instance.

Configuring Logging

TZA-InsuranceService uses a Log4j configuration file to manage what is logged and how. To add this to the runtime class path you need to place the configuration file into the src/config folder of your project.

Of course you have done all this already when you built TZA-InsuranceConsole so just go grab (Right Click -> Copy) the log4j.xml file from the src/config directory of that project and dump it into the src/config directory of TZA-InsuranceService (Right Click -> Paste).

Refresh Eclipse

Whenever changes are made to the directory structure of an Eclipse Project (out with the Eclipse environment) it is necessary to let Eclipse know what is going on "under the covers".

  • Select the TZA-InsuranceService project and use the F5 function key to refresh the environment.
  • Alternatively Right Click on TZA-InsuranceService and select the Refresh option).

With these changes your Project Explorer view should now look like this:

Project Explorer with Config

Testing TZA-InsuranceService getQuote

Having completed all the changes necessary to wire the getQuote method into the TZA-InsuranceProcess sqlQuotationEngine we can now test out the TZA-InsuranceService (make sure your Teradata is running as we are going down the full application vertical here).

Start the Application Server

If you had closed down your application server you will need to start it up. Even if you left it running since last week, changes to the Java code and configuration as extensive as the ones we have made today will require that the application server be restarted in order to load up the new classes into memory.

  • Start / Restart the Server using the Start Icon on the Server View

Start Server

Start the Web service Test Client

You will probably need to start up the Web service Test Client again also. You can simply browse to it by pointing your favourite Web browser at http://localhost:8080/TZA-InsuranceServiceClient/samplePropertyInsuranceProxy/TestClient.jsp. Alternatively you can stay within Eclipse.

  • Open up the TZA-InsuranceServiceClient project WebContent/samplePropertyInsuranceProxy/ directory.
  • Right Click TestClient.jsp
  • Select Run As.. -> Run on Server -> Finish
  • Within the Web Services Test Client browser select the getQuote method in the Methods frame.
  • Scroll down through the Inputs frame and Select the Invoke button.
  • Examine the Web service response in the Result frame

Web services Test Client

You can play around with the Input Parameters to make sure that the Quotation Engine is truly using the parameters in its calculation.

Changing the Risk Factors

The other aspect that controls the Quotation amount generated by the Quotation Engine is the contents of the ZipCodeRiskFactors table (remember these are multipliers so don’t stray too far from the 1.0 base values). BTEQ Gurus can try going into the ZipCodeRiskFactors table of TZA_DB and changing the risk factor values for a given Zip Code Range to make sure the quotation amount changes accordingly.

If you don’t know what BTEQ is don’t worry there is another (some might say better) way. Go back to the TZA-Database project we did a few weeks ago, the purpose of which was to allow us to Build the TZA_DB and populate its tables with data. However, it can also be used to rebuild the Database using ANT and SQL. Open up the InsertTZA_Data.sql file and change some of the 1.0 base values in the Insert statement associated with the Zip Code Range you are using in the Web service request. When you run the default ANT task within the TZA-Database project it will clear out all the existing Data and Tables in your TZA_DB instance and recreate these with your new values.


So that is it for another Friday Night Project (strictly speaking it’s a gloomy Saturday afternoon but who’s counting). You now have a Teradata driven, Connection Pool enabled, WS-I, Contract First, Web service - vey cool.

Here’s one last thing to think about before next week, if you were paying close attention when you were testing out the Web service you might have noticed that the first time you hit “Invoke” there was a delay before the result appeared, while each subsequent invocation seems to come back really quickly (restart the server to prove it to yourself). The delay is due to the establishment of the Connection Pool on that first Database access with subsequent database accesses getting an already open connection from the pool. This approach is critically important for the performance of Web and Web service applications. Next week we will expand on this thought as we consider what an application can do to achieve improved performance through collaborating with the Database on Workload Management.