Cut out the Middle-Man: Use Informix Dynamic Server with J/Foundation to host a Java application service

How to create and deploy a Java application service such as an RSS or Web server directly from your data server using Informix Dynamic Server with J/Foundation

IBM® Informix® Dynamic Server (IDS) user-defined routines (UDRs) can be written in C, Java™, and Stored Procedure Language (SPL). A recently documented extension to Java UDR support - codenamed Solano - is the ability to host a Java application service, such as an HTTP server, directly from within the data server.

Share:

Guy F. Bowerman (guyb@us.ibm.com), Senior Software Engineer, IBM

Guy Bowerman photoGuy Bowerman is a senior software engineer in IBM's Resolution, Engineering, and Development (RED) team, providing advanced technical support, product development, training, and bug fixing for Informix products. Guy has worked for Informix Software since 1994 in the U.K. and U.S.



26 October 2006

Introduction

Why Solano? A new spin on the two-tier database model

A typical browser-based three-tier database application architecture places much of the business and application logic in the middle tier in the form of an application server providing dynamic HTML or XML generated by a programming language or framework such as JSP or PHP. The data server is used to simply serve data to the application server over the network through Open Database Connectivity (ODBC) or Java Database Connectivity (JDBC) requests, or to additionally perform some of the business logic in the form of stored procedures and UDRs.

Figure 1. Three-tier browser-based database application architecture
Three-tier browser-based database application architecture

The three-tier model is flexible and a wide range of ready made application servers and programming systems are available. While this model provides benefits to large enterprise users, for smaller SMB users, some of the costs involved in maintaining the middle tier, such as deployment, administration, upgrades, security, and network bandwidth might not be as advantageous.

An alternative model incorporates the three tiers into two tiers with the application server running in the same address space as the data server. The Solano feature of IDS with J/Foundation allows UDRs to be mapped to Java methods that start and stop an application. The application runs within an Informix Virtual Processor, known as a Java Virtual Processor (JVP). It can listen on its own network ports and respond directly to client requests while maintaining high-performance server-side JDBC connections to the data server.

Figure 2. Two-tier database architecture with Solano
Two-tier database architecture with Solano

This revised form of the two-tier model offers several potential advantages:

  • Deployment can be simplified; a self-contained application can be installed by running an SQL script, removing the requirement to install, and maintain a third-party application server.
  • Security is improved. Possible attack vectors can be reduced by disabling external connections into the data server and having all non-local database access go through the Solano application, which makes its own internal database connections.
  • Network overhead between the application server and data server is eliminated.
  • Performance is improved. Applications services running in the same address space as the database server can use the server-side JDBC driver for high-performance access to the database. This, in turn, allows the application to make more frequent calls to the data server to maintain its data cache, improving data integrity.
  • Session tracking; an application server can maintain a set of transient information about the clients sessions that can in turn be accessed and processed by the data server if they share the same address space.

Some applications will always be better suited to the three-tier model. Tried and tested load balancing solutions have been developed for the three-tier system to manage scalability. Not all Java application servers will be suitable to run inside a data server without customization. And writing an application server from scratch can imply a significant investment of resources.

The example described in this article makes use of the Apache Jakarta HttpCore Components to show how a simple Java application server can be written and embedded into IDS with very little effort.


The embedded RSS server

This example queries the IDS demo database stores_demo to serve an RSS feed showing the last 20 orders. An RSS feed can be added to a Mozilla Firefox browser toolbar or an RSS compatible newsreader to provide a regularly updated data feed in a summary format. The same example was previously implemented with both JSP and PHP in a developerWorks blog post.

The example code was tested on Linux and Windows. Because it is written in Java, the example should work on any platform IDS is available for.

Figure 3. An RSS feed
An RSS feed

Ingredients

The following components are required:

  • Java 2 SDK 1.4.2
  • Apache Jakarta HttpCore Components 4.0-Alpha 2
  • Informix JDBC 3.0.JC3
  • IDS 10.0

Step 1. Write a standalone RSS server

Writing a standalone RSS server may sound like a complex task, but the HttpCore components allow a standalone Java server to be written with just a few lines of code.

To keep coding to a minimum, the Jakarta Simple HTTP server example written by Oleg Kalnichevksi is used as a starting point. A small modification changes it from serving HTML files to serving an XML RSS feed. The main change is in the doService() method, which reads in a URL request from a client, converts it into a file entity, and serves the file. To become an RSS server it connects to the database, runs a query, and builds an XML formatted string entity with the result set to serve to the client.

Listing 1. Standalone RSS server doService() method
        protected void doService(final HttpRequest request, final HttpResponse response) 
                throws HttpException, IOException {
            String method = request.getRequestLine().getMethod();
            if (!method.equalsIgnoreCase("GET") && !method.equalsIgnoreCase("HEAD")) {
                throw new MethodNotSupportedException(method + " method not supported"); 
            }
            String target = request.getRequestLine().getUri();
            response.setStatusCode(HttpStatus.SC_OK);


            // build a string entity to return to the client
            String s = getRSSFeed(target);
            StringEntity body = new StringEntity(s);

            // set the content type to text/xml
            body.setContentType("text/xml");

            response.setEntity(body);
        }

The RSS string is constructed in a new method called getRSSFeed(). In this example the target argument to getRSSFeed(), which represents the URL string requested by the browser or newsreader, is not used. A more complex example might interpret the URL when building a database query in order to return customized RSS feeds.

Listing 2. Standalone RSS server getRSSFeed() method
        // getRSSFeed - connect to data server, execute a query, convert data to RSS feed
        protected String getRSSFeed(String target)
        {
          // begin generating the RSS feed string (use a dummy link)
          String rssFeed = "<rss version=\"2.0\">\n<channel>\n<title>IDS Feed " + 
            "<title>\n" + "<link>http://localhost:8080<link>\n" +
            "<description>IDS Feed<description>\n";


            // get database connection
            try {
              Class.forName("com.informix.jdbc.IfxDriver");
              Connection conn =
              DriverManager.getConnection(
              "jdbc:informix-sqli://mymachine.beaverton.ibm.com:1526/stores_demo:" +
              "INFORMIXSERVER=myinstance", "myuser" ,"mypasswd");

              // execute a query and dynamically build the RSS feed string
              Statement stmt = conn.createStatement();
              String sqlStr = "select first 20 i.order_num, quantity, " +
               "trim(description) desc, order_date, total_price, trim(company) co " +
               "from items i, orders o, customer c, stock s " +
               "where i.order_num = o.order_num and o.customer_num = c.customer_num " +
               "and i.stock_num = s.stock_num order by order_date desc";
              ResultSet rs = stmt.executeQuery(sqlStr);

              // add a new item to the RSS feed for every row returned
              while(rs.next())
              {
               String rssTitle = rs.getString("quantity") + " " + rs.getString("desc") +
                  " $" + rs.getString("total_price") + " " +  rs.getString("co") + " " +
               rs.getString("order_date");

               // replace chars which might be interpreted as XML control characters

               rssTitle = rssTitle.replaceAll("&", "&");

               rssFeed += "<item>\n<title>" + rssTitle + "<title>\n";
               rssFeed += "<link>http://localhost:8080/<link>\n<item>\n";
              }
              // close ResultSet and Connection
              rs.close();
              conn.close();
            } catch (Exception e)
            {
              return e.getMessage();
            }
            // write the end of the feed

            rssFeed += "<channel>\n<rss>";

            return rssFeed;
        }

To build and launch the standalone RSS server, include the Informix JDBC drivers, the HttpCore package, and the current directory in your CLASSPATH.

Listing 3. Building and launching the standalone RSS server
export CLASSPATH=.:/work/jakarta-httpcore-4.0-alpha2/lib/jakarta-httpcore-4.0-alpha2.jar:
/usr/jdbc_30JC3/lib/ifxjdbc.jar:/usr/jdbc_30JC3/lib/ifxjdbcx.jar:$CLASSPATH

javac rssServer.java
java rssServer

Make sure the data server specified in the connection string is online, and point your browser to http://localhost:8080/ to confirm the RSS server is working. You should see the RSS XML data displayed on the screen.

Step 2. Modify the RSS server to run inside IDS

In order to run the RSS server in IDS, the main() method from the standalone RSS server is replaced with a new method rss_start() that will be mapped to a UDR.

Listing 4. New method rss_start() to replace main()
    public static void rss_start() throws Exception {
        Thread t = new RequestListenerThread(8080);
        t.setDaemon(false);
        t.start();
    }

The JDBC connection string is also modified to request an internal, Solano style connection. Note that it is the addition of the database name and user credentials to the standard server-side JDBC direct connection string that tells IDS this is a Solano application that can run unattended.

Listing 5. Solano style internal connection
          Connection conn = DriverManager.getConnection(
              "jdbc:informix-direct:/stores_demo:user=myuser;password=mypasswd;");

The IDS RSS server can now be built with javac using the same CLASSPATH used to build the standalone server. It cannot be launched directly without a main method, so the next step is to set up IDS to launch it.

Step 3. Set up J/Foundation and modify the JVPCLASSPATH

To enable J/Foundation, the VPCLASS ONCONFIG parameter, to create a JVP, needs to be uncommented. With this option enabled, a JVP will be launched when the first Java UDR is executed. For a detailed guide to setting up J/Foundation, refer to the Resources section.

Modify the JVPCLASSPATH ONCONFIG parameter to include the IDS RSS server class files and the HTTPCore JAR file. Putting the directory of the IDS RSS server class files in the CLASSPATH means that the full path of the RSS server start method does not need to be specified when registering the UDR. An example might look like this if the Java file is built in a directory where /work/ids_rss and the HttpCore components were installed in /work:

Listing 6. Onconfig parameter modifications
VPCLASS        jvp,num=1 
...
JVPCLASSPATH
/usr/informix/extend/krakatoa/krakatoa.jar:/usr/informix/extend/krakatoa/jdbc.jar:
/work/ids_rss/.:/work/jakarta-httpcore-4.0-alpha2/lib/jakarta-httpcore-4.0-alpha2.jar:$CLASSPATH

Once these ONCONFIG parameters are changed, IDS needs to be re-started for them to take effect.

Step 4. Register and execute the UDR to start the RSS server

The following SQL script maps the RSS server rss_start routine to a UDR and starts the RSS server:

Listing 7. SQL script to register and start the IDS RSS server
database stores_demo;

{ create the start routine and map it to the Java method }
create procedure start_rss()
external name 'ids_rss.rss_start()' language java;

{ execute the start routine }
execute procedure start_rss();

Note that in this example, the path of the ids_rss.rss_start() method does not need to be specified because the JVPCLASSPATH ONCONFIG parameter was updated to include the directory where the classes were built.

Once the start_rss UDR is executed, the RSS server is running and ready to receive incoming connections.

When a Java UDR calls the System.out.println() method, the output is written to the JVP log file specified by the JVPLOGFILE ONCONFIG parameter. This enables status messages from the RSS server to be monitored by tailing the log file. When the RSS server is launched and receiving incoming connections, a typical output might look like this:

2006/07/22 00:07:31.639 JVP#3: Registering service Tracer
Listening on port 8080
Incoming connection from /9.76.209.230
New connection thread
Request received
2006/07/22 00:07:37.029 JVP#3: Cannot get UDRManager environment
Response sent
Connection kept alive
IO error: Read timed out
Incoming connection from /9.76.209.230
New connection thread
Request received
2006/07/22 00:13:05.540 JVP#3: Cannot get UDRManager environment
Response sent
Connection kept alive
IO error: Read timed out

The above log shows that two incoming connections were received from the same IP address and a response was sent. The RSS server has sent the RSS feed showing the 20 most recent orders to the requesting browsers or newsreaders, and is ready to receive new requests.

The Cannot get UDRManager environment log entry is not an error but an expected message from the JVP when a UDR is not using the UDREnv interface, documented in the J/Foundation Developer's Guide. IO Error: Read timed out is an expected status message from the RSS server printed when the configurable keepalive value times out after a client requests a page. Messages like this from the application can be removed or added to with simple modifications to the code.

Conclusion

What's next?

This example shows how a small modification to the Jakarta Simple HTTP server can produce a working Java application server running inside an IDS instance. The same example can be expanded to create a custom HTTP server that serves a mixture of HTML files and data from a database retrieved through the server-side connection depending on the URL supplied, or a Web server that serves all its files from the database. A more complex RSS server based on this framework might serve customized data feeds based on the incoming URL. Imagine a news server that used the incoming URL to configure and serve customized news feeds based on date and subject matter.

Web services

A yet-untapped use for this technology is as a backend providing Web services from the database to an AJAX-style application. Javascript running in the client's browser could trigger Solano Web services running directly in the database to dynamically serve content. This would allow the Web services to be componentized within the server rather than written as part of a middleware application.

Secure connections

Another application for Solano would be to host an HTTPS server, enabling end-to-end security directly from browser to database.


Download

DescriptionNameSize
Sample code for this articlesolano.zip7KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Information management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management, Java technology
ArticleID=170258
ArticleTitle=Cut out the Middle-Man: Use Informix Dynamic Server with J/Foundation to host a Java application service
publish-date=10262006