Level: Introductory Soumita Ghosh (soumita.ghosh@in.ibm.com), System Software Engineer, IBM Software Labs, India Sobha Rani Cheruku (scheruku@in.ibm.com), Associate Software Engineer, IBM Software Labs, India Akhilesh K. Tiwary (aktiwary@in.ibm.com), Staff Software Engineer, IBM Software Labs, India
28 Sep 2006 Learn how to expose an IBM® Informix® user-defined routine or user-defined datatype on the Web as a Web service. You'll see how to use a JavaBean for interacting with the Informix UDR or UDT, deploying as a Web service using Rational® Application Developer.
Introduction
A common requirement these days for database application developers is to be able to expose functions that access data on the Web. In this article, we show you how to expose an Informix user-defined routine (UDR) or user-defined datatype (UDT) on the Web as a Web Service, as part of service-oriented architecture. We'll use a JavaBean for interacting with an Informix UDR or UDT, and deploy it as a Web Service using Rational Application Developer (RAD).
For our example, we have created a customer table on the Informix server, and will be accessing the table to retrieve customer details. Customer ID is used as the unique identifier for each customer record. Customer details are retrieved using a Java™ method that has been installed and registered as a UDR on the Informix server. The activity of creating and registering the UDR or UDT is done using Informix udtudrmgr classes.
We used RAD to create and deploy the Web service using a JavaBean. Internally the method which calls the UDR is exposed as a Web service method.
The front end application was designed in JSP/HTML. The customer ID is the input field for the index page, and on submission calls a results page which retrieves and displays the customer billing details.
In walking through this sample application, you will learn:
- How to create Java UDRs and UDTs
- How to create a Web service using Rational Application Developer
- How to use service-oriented architecture to create better Web applications
- How Informix Dynamic Server (IDS) can exploit the functionalities of service-oriented architecture
Basic concepts
Let's start with the fundamental concepts behind Web services.
What is service-oriented architecture?
Service-oriented architecture (SOA) is built on top of the three-tier client-server architecture composed of the client application, the Web services application, and the server or ERP layer, and addresses its shortcomings. SOA is composed of a set of services and applications. These services implement a function of some kind and are used by applications and other services. The services communicate among one other and with applications by exchanging XML data.
Hence, SOA facilitates software reusability in the form of services that are actually software modules that cater to more than one application's requirements.
What is a Web service?
A Web service is basically a software system that provides interoperability between machines over a network. It has two parts: language and protocol of message transfer. The language part is called WSDL (Web service definition language). The protocol used is called SOAP (Simple Object Access Protocol). WSDL basically describes the service and XML is mainly used as the language. SOAP helps the applications to communicate over the Internet.
Figure 1. Service-oriented architecture
What are Java UDRs and UDTs?
A user-defined routine (UDR) is a routine that an SQL statement or another UDR can invoke. UDRs written in Java use the server-side implementation of the Informix JDBC driver to communicate with the database server.
A user-defined datatype (UDT) is the mapping between SQL data types and Java objects to be able pass parameters and retrieve results from a UDR.
There are 2 types of UDT in Java:
- Distinct data type: CREATE DISTINCT DATATYPE
- Opaque data type: CREATE OPAQUE DATATYPE
UDTs can be created by using CREATE TYPE SQL statement or by using UDTMANAGERs createUDT methods.
Before you get started
Software requirements
To create and use UDRs written in Java:
- You need to install Informix Internet Foundation 2000
- You need to install The Java Development Kit (JDK). You may also install DataBlade Developers Kit, Version 4.0 or later, to facilitate development of UDRs in Java. If you just want to run the existing Java UDRs without compiling the source code, then installing only JRE would be sufficient instead of JDK.
Server requirements
UDRs written in Java execute on specialized virtual processors , called Java virtual processors (JVPs). A JVP embeds a Java Virtual machine in its code.
You need to specify some Java-specific configuration parameters in the INFORMIX ONCONFIG configuration file. They should look like this:
Listing 1. Snapshot of ONCONFIG file on UNIX
VPCLASS jvp,num=1 # Number of JVPs to start with
JVPJAVAHOME /usr/informix/ids_10/extend/krakatoa/jre/
JVPHOME /usr/informix/ids_10/extend/krakatoa # Krakatoa installation directory
JVPPROPFILE /usr/informix/ids_10/extend/krakatoa/.jvpprops # JVP property file
JVPLOGFILE /usr/informix/ids_10/jvp.log # JVP log file.
JDKVERSION 1.3 # JDK version supported by this server
JVMTHREAD native # Java VM thread type(green or native)
# The path to the JRE libraries relative to JVPJAVAHOME
JVPJAVALIB /lib/sparc/
# The JRE libraries to use for the Java VM
JVPJAVAVM hpi:server:verify:java:net:zip:jpeg
# use JVPARGS to change Java VM configuration
#To display jni call
#JVPARGS -verbose:jni
# Classpath to use upon Java VM start-up (use _g version for debugging)
JVPCLASSPATH /usr/informix/ids_10/extend/krakatoa/krakatoa.jar:
/usr/informix/ids_10/extend/krakatoa/jdbc. jar
|
How to create and register UDRs in Java
Follow these steps to create and register the UDRs:
- Write the body of the UDR in a Java file, similar to the following example:
Listing 2. Snapshot of UDR in Java: Circle.java
public class Circle
{
private static double PI = 3.14159;
public static double area(double c)
{
return PI * c*c
}
}
|
- Before invoking the UDR in SQL statement, register the UDR in the current database
using CREATE FUNCTION or CREATE PROCEDURE statement as follows:
CREATE FUNCTION area (float) RETURNS float EXTERNAL NAME 'circle_jar:Circle.area(double)' LANGUAGE JAVA NOT VARIANT
END FUNCTION
You can also create a Java file and compile it (as in given sample code: Create Cust UDT.java).
- Use the javac command to compile the body of the UDR and create the class file.
- Use the jar command to create jar file, which will be installed on the server.
- Install the jar file:
Install the jar files using SQLJ built-in procedure install_jar.
Listing 3
execute procedure sqlj.install_jar('file:/work/circle_jar.jar','circle_jar',1) |
UDRs can be registered using the deployment descriptor and manifest file also. If you use deployment descriptor then create a file (deploy.txt) as follows:
Listing 4
SQLACtions[] = {
"BEGIN INSTALL
CREATE FUNCTION area (float) RETURNS float
EXTERNAL NAME 'circle_jar:Circle.area(double)' LANGUAGE
JAVA NOT VARIANT
END FUNCTION
END INSTALL"
}
|
Create the manifest file manifest.txt as follows:
Name: deploy.txt
SQLJDeploymentDescriptor : TRUE
Create the jar file using manifest and deployment descriptor as follows:
Jar cvfm manifest.txt Circle_jar.jar deploy.txt Circle.class
Now the install jar step will register the UDR also.
How to use or execute UDRs
After registering the UDR, UDRs can be invoked in SQL statements, for example:
select area(3) from area_table;
Introduction to Rational Application Developer
RAD for Websphere is an integrated development environment that helps developers to quickly design, develop, analyze, test, profile, and deploy high quality Web, SOA, Java, J2EE and portal applications. It has an inbuilt Eclipse editor that helps to quickly develop Java classes and compile them, after which we can deploy them as Web services using inbuilt WebSphere Application Server. RAD also provides a testing environment so we can test the Web services on a standalone system before exposing them on the Web.
We used RAD to develop the Java classes and deploy the Web Services on WAS to test its functionality. With the help of a JDBC connection we were able to connect to the Informix server through which we retrieved data from the database and also use the Java UDRs registered on the Informix server. Hence, RAD provides the ONE platform where we can run and execute our application without further assistance.
Code used in sample application
The five programs that we used in our application are:
Listing 5: Customer.java
package customer;
import java.sql.*;
import com.informix.jdbc.IfmxUDTSQLInput;
import com.informix.jdbc.IfmxUDTSQLOutput;
public class Customer implements SQLData
{
private String type = "customer";
public int id=101;
public int tbill;
public int ebill;
public int mbill;
public int monyr;
public String getSQLTypeName() { return type; }
public void readSQL(SQLInput stream, String typeName)
throws SQLException
{
IfmxUDTSQLInput in = (IfmxUDTSQLInput) stream;
id = in.readInt();
tbill= in.readInt();
ebill= in.readInt();
mbill= in.readInt();
monyr= in.readInt();
}
public void writeSQL(SQLOutput stream) throws SQLException
{
IfmxUDTSQLOutput out = (IfmxUDTSQLOutput) stream;
out.writeInt(id);
out.writeInt(tbill);
out.writeInt(ebill);
out.writeInt(mbill);
out.writeInt(monyr);
}
public static Customer getCustomerDetail ( int cust_id) {
Customer cust_obj=new Customer();
try
{
Connection conn = null;
try
{
Class.forName("com.informix.jdbc.IfxDriver");
}
catch (Exception e)
{
System.out.println("Error: failed to load Informix JDBC driver.");
e.printStackTrace();
return null;
}
String url="jdbc:informix-sqli://XXX.XXX.XXX.com:7005/testdb:INFORMIXSERVER=ol_ids;
user=XXXXX;password=XXXXX";
try
{
conn=DriverManager.getConnection(url);
}
catch(SQLException e)
{
System.out.println("ERROR: Failed to connect!");
System.out.println("ERROR:" + e.getMessage());
e.printStackTrace();
return null;
}
PreparedStatement pstmt=conn.prepareStatement("Select * from customer where id=?");
pstmt.setInt(1,cust_id);
ResultSet rs=pstmt.executeQuery();
while(rs.next())
{
cust_obj.id =rs.getInt(1);
cust_obj.tbill =rs.getInt(2);
cust_obj.ebill =rs.getInt(3);
cust_obj.mbill =rs.getInt(4);
cust_obj.monyr =rs.getInt(5);
}
rs.close();
pstmt.close();
}
catch(SQLException e)
{
System.out.println("ERROR:" + e.getMessage());
e.printStackTrace();
}
return cust_obj;
}
}
|
Listing 6: CustSOA.java
package customer;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Iterator;
import java.util.StringTokenizer;
public class CustSOA {
public String getBillDetail(int cust_id)
{
Customer c_out=new Customer();
/*===================Connection Block==========*/
Connection conn = null;
try
{
Class.forName("com.informix.jdbc.IfxDriver");
}
catch (Exception e)
{
System.out.println("Error: failed to load Informix JDBC driver.");
e.printStackTrace();
return null;
} // End Driver Loading Block
System.out.println("Informix JDBC driver loaded successfully.");
// Connect to database
String url="jdbc:informix-sqli://XXX.XXX.XXX.com:7005/testdb:
INFORMIXSERVER=ol_ids;user=XXXXX;password=XXXXX";
//System.out.println("The url is:-"+url);
try
{
conn=DriverManager.getConnection(url);
}
catch(SQLException e)
{
System.out.println("ERROR: Failed to connect!");
System.out.println("ERROR:" + e.getMessage());
e.printStackTrace();
return null;
}
System.out.println("\nConnection established\n");
/*=========End of connection Block=============*/
/*============Call the UDR===================*/
try {
java.util.Map customtypemap = conn.getTypeMap();
System.out.println("getTypeMap...ok");
if (customtypemap == null)
{
System.out.println("***ERROR: map is null!");
return null;
}
customtypemap.put("customer", Class.forName("customer.Customer"));
String s = "select getCustomerDetail("+cust_id+") from customer";
System.out.println(s);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(s);
if (rs.next())
{
c_out=(Customer) rs.getObject(1);
System.out.println(" ID = " + c_out.id);
System.out.println(" ID = " + c_out.tbill);
}
rs.close();
stmt.close();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return c_out.id+":"+c_out.tbill+":"+c_out.mbill+":"+c_out.ebill+":"+c_out.monyr;
}
}
|
Listing 7: CreateCust UDT.java
import java.sql.*;
import java.lang.reflect.*;
public class CreateCustUdt
{
String url = null;
Connection conn = null;
public static void main ()
{
new CreateCustUdt();
}
CreateCustUdt() {
String url="jdbc:informix-sqli://XXX.XXX.XXX.com:7005/testdb:
INFORMIXSERVER=ol_ids;user=XXXXX;password=XXXXX";
// --------------
// Loading driver
// --------------
try {
Class.forName("com.informix.jdbc.IfxDriver");
}
catch (java.lang.ClassNotFoundException e) {
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}
try {
conn = DriverManager.getConnection(url);
}
catch (SQLException e) {
System.out.println("URL = '" + url + "'");
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}
Method getCustomerDetailmethod = null;
try {
Class c = Class.forName("Customer");
getCustomerDetailmethod = c.getMethod("getCustomerDetail", new Class[]
{Integer.TYPE });
}
catch (ClassNotFoundException e) {
System.out.println("Cannot get Class: " + e.toString());
return;
}
catch (NoSuchMethodException e) {
System.out.println("Cannot get Method: " + e.toString());
return;
}
UDTMetaData mdata = null;
try {
System.out.print("Setting mdata...");
mdata = new UDTMetaData();
mdata.setSQLName("Customer");
mdata.setLength(24);
mdata.setAlignment(UDTMetaData.EIGHT_BYTE);
mdata.setUDR(getCustomerDetailmethod, "getCustomerDetail");
mdata.setJarFileSQLName("Customer_jar");
System.out.println("ok");
}
catch (SQLException e) {
System.out.println("\n***ERROR: " + e.getMessage());
return;
}
UDTManager udtmgr = null;
try {
udtmgr = new UDTManager(conn);
String jarfilename = udtmgr.createJar(mdata,
new String[] {"Customer.class"}); // jarfilename = Customer.jar
udtmgr.setJarTmpPath("/tmp");
udtmgr.createUDT(mdata,
"C:\\eclipse\\CUST_TEST\\" + jarfilename, "Customer", 0);
System.out.println("UDT/UDR Created");
}
catch (SQLException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
return;
}
System.out.println();
}
private void executeUpdate(String s)
{
try
{
Statement stmt = conn.createStatement();
stmt.executeUpdate(s);
stmt.close();
}
catch (SQLException e)
{
e.printStackTrace();
return;
}
}
}
|
Listing 8: CustSOAIndex.html
<HTML>
<HEAD>
<TITLE>Customer Detail</TITLE>
</HEAD>
<BODY>
<H1>Inputs</H1>
<FORM METHOD="POST" ACTION="CustSOAResult.jsp">
<INPUT TYPE="HIDDEN" NAME="method" VALUE="18">
<TABLE>
<TR>
<TD COLSPAN="1" ALIGN="LEFT">Enter Customer ID:</TD>
<TD ALIGN="left"><INPUT TYPE="TEXT" NAME="cust_id" SIZE=20></TD>
</TR>
</TABLE>
<BR>
<INPUT TYPE="SUBMIT" VALUE="Invoke">
<INPUT TYPE="RESET" VALUE="Clear">
</FORM>
</BODY>
</HTML>
|
Listing 9: CustSOAResult.jsp
<HTML>
<HEAD> <TITLE>Result</TITLE> </HEAD>
<BODY>
<H1>Result</H1>
<jsp:useBean id="sampleCustSOAProxyid" scope="session" class="customer.CustSOAProxy" />
<% String p_id= request.getParameter("cust_id");
int p_idTemp = Integer.parseInt(p_id);
java.lang.String ret_cust = sampleCustSOAProxyid.getBillDetail(p_idTemp);
if(ret_cust == null)
{ %>
<%=ret_cust%>
<%
} else {
String tempResultreturn = webserviceutils.com.ibm.etools.webservice.util.JspUtils.markup
(String.valueOf(ret_cust));
%>
<% StringTokenizer st=new StringTokenizer(tempResultreturn,":");%>
<b> <TABLE>
<tr>
<td> Customer ID </td>
<td> <%= st.nextToken() %> </td>
</tr>
<tr>
<td> Telephone Bill </td>
<td> <%= st.nextToken() %> </td>
</tr>
<tr>
<td> Elect Bill </td>
<td> <%= st.nextToken() %> </td>
</tr>
<tr>
<td> Mobile Phone Bill </td>
<td> <%= st.nextToken() %> </td>
</tr>
<tr>
<td> Year & Month </td>
<td> <%= st.nextToken() %> </td>
</tr>
</TABLE> </b>
<% } %>
</BODY>
</HTML>
|
Procedure to create the Web service used in the sample appication
Follow these steps to create the Web service and expose the method:
- Create a dynamic project.
Select Launch File > New > Project to create a new project, then choose dynamic Web project:
Figure 2. Creating dynamic project
- Create a new package, where all the source code will be created.
Select JavaSource > New > Package:
Figure 3. Create new package
- Create a new Java class that will store the Web service code:
Figure 4. Create new Java class
- Create a Web service, using the default options. RAD provides the functionality to create Web Services using JavaBeans.
Select File > New > Web Service:
Figure 5. Create new Web service
-
In the WebService explorer select Java Bean Web Service and other option
shown in the figure.
Figure 6. Select Java Beans Web service
- When the Object Selection Page appears, click Browse Classes..., type
customer.CustSOA, and click OK.
Figure 7. Java bean identity
Figure 8. Web services explorer
- In WebService client Test Page check the methods to expose.
Click Next > Finish.
Figure 9. Web services explorer
Figure 10. Web services explorer
- Invoke the method. The exposed method can be tested on this page by clicking the hyperlink.
Figure 11. The exposed method
Figure 12. Methods in a browser
 |
The RAD directory structure
This screen shows the source structure of the dynamic Web project and the
generated client project.
Figure 13. Directory structure
Here is the main screen of the application:
Figure 14. Main page
Here is the results screen of the application:
Figure 15. Result page
Acknowledgement
We would like to thank Madhusudhan Ramidi for his support and the TWISTER team for their ideas without which we would not have thought so far.
Resources Learn
Get products and technologies
Discuss
About the authors  | 
|  | Soumita Ghosh worked within the Informix team as part of the Classics Development Team for a year. Now she works with the Visual Age team on XLC/XLC++ compilers. |
 | 
|  | Sobha Rani Cheruku works for Lab Services and handles Informix customer calls in India. |
 | 
|  | Akhilesh Kumar Tiwary is a member of the Classics Development Team, working on JDBC, C-ISAM, ESQL/COBOL, ISA and ISPY. |
Rate this page
|