HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

Darwin's Natural Selection
About two and half years ago our company was hired to write an application that would allow our client, Georgia Tech Research Institute (GTRI), to access their financials over the Web. It was our first major push into data access over the Web and we were pretty hyped. GTRI hired us because we were a PowerBuilder shop and all of their applications were written in PowerBuilder. Both Georgia Tech and our company, Sage Software, were excited about using PowerBuilder's new Web.PB. It looked very promising.

We soon realized that none of GTRI's existing code could be reused for this project. The programmers before us were guilty of the same thing that Sage Software, and most PowerBuilder programmers, were guilty of: we wrote our business logic in the user interface and not in business objects. The idea of reusing the code was thrown out and we started from scratch.

Creating Web applications was very tedious at that time. Basically, you wrote and compiled an executable that would sit on the Web server. You started that application like a normal application; however, this application did not consist of a user interface. When a request from the Web came across the wire, it was directed to the CGI-BIN directory where a special application parsed the URL string and decided what to do with it. It first deciphered a directory in the URL string and determined the name of the program. It then looked in an INI file in the Windows System directory to find the IP address and port number.

Next, it instantiated a new user object and called one function inside that user object. If the function's main purpose in life was to display a tabular report, your function connected to the database, created a DataStore object, retrieved and looped through the data. You were responsible for taking each row and each column and inserting a <TR> and <TD> tag. Finally, you disconnected from the database and sent back a massive string to the Web server.

Now let's get complicated and say that the user wanted to scroll through the data. Your function would be required to do the same thing; however, you needed to track what row the user was on and what rows should be displayed next. Since the Web is a stateless environment, you had no way of knowing who the user was, what screen he or she was on, what rows had previously been selected, and so on. If you wanted to track information between each Web hit, you had to store it in the database or in cookies. Thus you'd reconnect to the database, retrieve the data (again), determine what the user did last, skip to that row and begin your <TR> and <TD> tags.

Forget about data entry and updates. You created your own form through concatenating a large string with form elements. Once the data was submitted, you'd construct your SQL statement and submit it to the server. As Archie Bunker would say: "Those were the days."

The Strongest Shall Survive
Thank goodness for competition and the American way. Without good clean competition, I'd still be writing Web applications in this prehistoric manner. Two and a half years have brought us a long way - to the age of the Internet, e-commerce and application servers.

Like all good paradigm shifts, the industry latches onto a terminology that sticks. The new terminology is application servers. Depending on which vendors you talk to, you're likely to get different definitions of an application server. While there are several bullet points that define what an application server should be, for the moment let's forget about the essential - though less sexy - components, including load balancing and failover. That's terminology that the IT juggernauts like to use when ensuring upper management that the system is 100% reliable. I want to talk about the items that help me, as a developer, to be more productive in my work.

State and Session Management
To me, state and session management is the single most important thing about an application server. Let's say that your application has 40 separate Web pages, all accessible by a left-frame navigation. I want my application server to be able to track what my user has done on each of the 40 pages. If the user goes to the search page and searches for and retrieves 200 rows of data, I want that page to persist until the user's session times out. In other words, the user shouldn't have to hit the back button 10 times to get back to that search result. The user should only have to hit the search button once.

For shopping cart applications, I don't want to be responsible for tracking what users have selected in their carts by storing this information in a cookie or database field. I want the page to either track it or store the items in session variables.

I also don't want the overhead of connecting to the database for each transaction. I want a database connection pool that my users can share. The longest part of any application is the initial connection to the database.

Business Logic Host
In true three-tier applications, your business logic resides on the middle tier. Application servers, by default, are that middle tier. You write your code in business objects and separate this business logic from the user interface. You also want this middle tier to be open so that it can talk to other transaction servers to get your suppliers.

Intelligent HTML Forms
As a throwback from my PowerBuilder days, I want HTML elements that can be programmed. I want to be able to place an HTML field on the page and bind it to a database field. I also want the server to be able to create the necessary SQL to create, read, update and delete. I want each element to be able to be programmed such that when a user clicks on the submit button, I can reference the elements with more than a simple "value" method. I also want to be able to program these elements using Java.

Easy Distribution
The most obvious advantage of deploying on the Web is the ease of distribution. We're no longer responsible for installing our executables and OCXs on our users' machines. Even though we think this deployment has simplified the use of Web technology, it can still be complicated. One project I worked on had static HTML forms, images, Java applets and classes, and Oracle Web procedures. To migrate from a development environment to a production environment wasn't an easy task. I want my application server to be able to publish everything with the click of one button.

And On and On...
The list goes on for application servers, but these are my hot buttons. Don't forget about security, load balancing, thread pooling and access to different data sources such as Notes, PeopleSoft, ODBC and JDBC. We all have our hot buttons from the experiences we've suffered through over the years.

The Project
Enough commentary. At Sage Software many of our clients turn to us for Web-based solutions to improve all sorts of business processes. One such project, for an organization called Pathways, began in October 1998. Based on the needs of Pathways, we decided an application server was the best approach and chose SilverStream Software Inc.'s application server for the project.

Pathways, Inc., is a collaborative effort of more than 25 local social services agencies, three local governments and United Way of Metropolitan Atlanta. Pathways and the Web application's goals are to:

  1. Develop an innovative computerized system to help social services agencies work effectively together with individual consumers to help them recover from homelessness. The application will allow staff and volunteers at participating agencies to access the database simultaneously over the Internet.
  2. Generate accurate demographic data on the size and characteristics of Atlanta's homeless population and chart the effectiveness of local programs that work with the homeless. Since Pathways' agencies supply most of Atlanta's homeless and homelessness prevention services, the database they share will quickly yield meaningful qualitative and quantitative data on one of the community's most pressing social problems. The data will be used to craft innovative local and national solutions.

During the bidding process, we asked the normal question: "Java or HTML?" The natural response was a rich user interface - thus Java. After a quick study of the infrastructure of Pathways, it was determined that the bandwidth was too small to support a large-scale Java application. Most agencies would be sharing a 28K modem to access the Internet. So HTML was chosen.

The next question: "What development environment should be used?" Pathways allowed Sage Software to select the best application server. In the past we used Active Server Pages (ASP) for HTML and SilverStream for Java. Since this was going to be an HTML project, we initially intended to use ASP; however, one of Pathways' requests was that they wanted an easy migration from the HTML environment to the Java environment. They were forward thinking and knew that one day the bandwidth would catch up.

This requirement paused our efforts and we reexamined SilverStream's HTML capabilities. After a quick evaluation, we realized that SilverStream was stronger in HTML generation than anything we'd ever seen. In addition, we could write all of our business objects in Java. This meant that when we decided to build our forms using Java, we could reuse all our business objects. Not a new concept, but SilverStream is practicing what the industry was preaching.

The SilverStream Solution
We were awarded the project in mid-November 1998; development began on December 1. The project had massive amounts of data that we were to track and the project timeline was short. We were faced with approximately 20 pages that worked against 25 main tables and 30 code tables.

The application required each user to have job-specific security roles. These roles were needed to allow the user to see different pages and have different read/write access on each page.

This was easily accomplished in the database by creating three tables - a user table, a role table and an objects table. The user table, of course, tracked all of the users. The role table created different groups, much like roles in Windows NT security or Oracle security. Finally, objects were created that mirrored the page names of the application. Read/write attributes were assigned to each role for each object and each user was assigned one or more roles.

In addition to the normal security defined above, some pages allowed the user to read and write data only to the agency to which they were assigned. In other words, if one user went into the case management page and entered notes for Agency A, another user assigned to Agency B could not see those case notes.

The Beginning...
How was this application created in two months with a minimum amount of resources? Please keep in mind that this application dealt only with pages. Pages, by SilverStream definition, are HTML pages with a little JavaScript. For this application we didn't dabble with the Java Forms or Views. Even though there's a lot of power in the Forms and Views, we stuck with the Pages for this project. See Figure 1 for a basic understanding of the interface.

Figure 1
Figure 1:

A simple login screen was required to allow the user to have access to the application. Using the Page designer, I simply created an HTML page with tables and a form. The form contained two single-line edits and a Login Button. Each object is no simple form element; rather, it is a Java object that has many properties and functions.

The Login Button has an event called pageActionPerformed. Listing 1 shows the Java code for this event. You'll notice that this is Java code, not JavaScript. This is a common misunderstanding.

Let's start with line 14. Here I access a field (HTML single-line edit) with a method called getValue. This simply gets the value of the text field object. I then check to ensure that the user has entered at least one value. On line 17 I call the agScriptHelper.alert() method. This produced JavaScript that is called on the body load event in HTML.

If the page passes both validations, I then populate a string with a query that I want to pass to my business object. (For security and privacy reasons I've altered the query statement, and I can't show you the business object.)

On lines 35 and 36 I populate a hashtable with two parameters; then, on line 41, I invoke a business object that performs the SQL against the database. The page gets passed back a result set if the query was successful. On line 55 I go to the first row of the result set (there should only be one row), and on lines 66 through 68 I retrieve the values of the first row. On lines 71 through 75 I set the session objects that will be used throughout the application. These session objects are the only ones required to run the application. Finally, I issue the showPage method, which will open up the frame set for the main interface.

If the user were to view the source, they would see Listing 2. As you can see, this looks nothing like Listing 1. The Java code runs on the server, and the user never sees anything except the simple HTML elements.

Create, Read, Update and Delete: these are the primary things you want to do when accessing your database. Clearly, SilverStream was designed from the ground up to be concerned about database access. All of the primary screens in the application require CRUD in one way or another.

Creating a CRUD page in HTML is very simple.

  1. Select New Page from the page designer.
  2. Select a data-aware page format.
  3. Select the primary table.
  4. Select the fields of the primary table.
  5. Select the Style for the Page. The Style sets the default colors of the page and the text on the page. It also gives you the basic CRUD navigation buttons - First, Last, New, Save, Delete, etc.
  6. Give the page a name.
SilverStream then takes over. It creates your HTML page and your data access object, then binds the fields to the form elements and provides the navigation bars.

If you're only trying to update the entire table, then you're finished. However, most of us want to update a subselect of the table. In our case we have a client record and we want to update all of the case management files for that client. Thus we only want to retrieve the client records in the case management table. There are several ways to do this. This was our approach:

We have a search screen that allows the user to search the database based on one or more fields. When the user locates the record that he or she wishes to modify, we set a session value. On the left frame various images were created for navigating to different sections of the client. The images are programmable, so we grabbed the session value and constructed the where criteria for the page. The where criteria consisted of "CLIENT_KEY={session value}". Then, using the above predefined method, we passed the page name, frame name, the where criteria and the sort criteria as the parameters. When the page loads, it reads in the values that were passed and constructs the query for the database. The sample code appears in Listing 3.

For each of the pages, Pathways wanted to see common information about the client. Thus we created a page that contained these elements - name, address and age. We created our own methods for retrieving the client information and saved the page. In certain pages, such as the Case Management page, we dragged and dropped the Header page, making it a subpage of the Case Management page. From the Case Management page we can treat the subpage as an object and call its methods and access its properties. How about that? Object-oriented HTML development.

Now let's add security to this screen. The security method is a common element for each page. It has a rather complicated SQL statement that needs the user ID and the page name as the parameters. For security reasons I won't display the code for this. I will tell you, however, that it was easy to accomplish this for all the pages. We added the security methods to the Header page. On the pageRequestBegin event we called the method and passed in the session object's user ID and the screen name. The security object would pass back a 0, 1 or 2. If it was a 0, the user didn't have access to the page and had to be directed to an error page. If the return was a 1, the user had read access only, and we simply set the property for the Save, Delete and New buttons such that the HTML would not be generated for the objects.

Data Views
Data views are powerful objects within SilverStream. On each of the pages we allowed the users to update one record at a time. They could scroll through the records, save and delete, and then scroll to other records. To give the user an idea of how many records were in their select, we added a Data View just below the navigation bars. The Data View was linked to the page's cursor so that we could see all of the records for that select. The records in a Data View are displayed in a table with neat scroll bars that allow the user to scroll up and down on the records.

Stored Procedures
I'm adding this section for the SilverStream enthusiasts who haven't coded their first stored procedure call. Putting your business logic in stored procedures is still a good idea for heavy transaction-based functions that hit many tables. Listing 4 contains a very simple call to a stored procedure in SilverStream. You'll notice, however, that this is a purely JDBC call, which is why it took me some time. I was looking for SilverStream classes, but there's no need to extend the JDBC calls.

Line 3 shows the connection string to the database. If you're unsure of the connection string, look in the SilverStream management console under the database that you're using. On Line 16 is the stored procedure that you'll be calling. You'll use the "?" for the parameters in this string. Don't attempt to concatenate a string that includes the actual values. The "{" is required too. On Line 19 you're connecting to the database. You will, of course, use your own user ID and password. On Line 21 you're creating your Callable Statement and on Lines 23 and 24 you're putting in your two parameter values. Finally, on line 25, you're calling the procedure. This stored procedure doesn't return a result set, which is why it took me a few hours to figure out. There are a ton of examples on how to get a result set back. As you can see, this is pure Java and JDBC, so it can be applied outside of SilverStream.

Final Analysis
SilverStream is an excellent tool for creating fully functional enterprise Web applications. At the time of this writing, the development of the project is complete two weeks ahead of what we considered a tight schedule. We are now beginning the alpha test phase; however, Pathways has been able to see the work as it progressed. They provided valuable feedback along the way, saving us time in the long run.

The SilverStream newsgroup has been an excellent source for how-to's and problem solving. We only needed to call SilverStream once for assistance.

The entire project went quite smoothly, which is generally hard to say about any application server. It was a large project that we completed in just two months. The resources involved were two SilverStream developers, an Oracle DBA and a Visual Basic programmer. Your next question is: "Why a Visual Basic programmer?" We found that a majority of the work was creating the presentation of the screens and the layouts. Our Visual Basic programmer picked up SilverStream and created all of the forms without one day of training. The SilverStream coders came through and added the code once the forms had been created.

SilverStream gets an A- by my grading system. I don't give A+'s, and it must be flawless to get an A. I'll use it for all future HTML development projects.

About the Author
President/CEO Chad Ruff founded Sage Software, Atlanta, Georgia, in 1995, and has concentrated his company's efforts on delivering state-of-the-art custom applications using PowerBuilder, MapInfo, Java and other Internet-related technologies. He can be reached at [email protected]


Listing 1.
1. Hashtable queryInfo = new Hashtable(); 
3. String sUser = ""; 
4. String sPassword = ""; 
5. String ls_agency = ""; 
6. String sQuery = ""; 
7. String sAgencyName = ""; 
8. String sUserID = ""; 
9. BigDecimal bdAgencyKey = new BigDecimal(0); 
10. BigDecimal bdUserKey = new BigDecimal(0); 
12. // Retrieve the value of the login field and check to  
13. // ensure that user has entered at least one character 
14. sUser = FieldLogin.getValue(); 
15. if ( sUser.equals("")) 
16. { 
17. agScriptHelper.alert("You must enter a user id."); 
18. return ; 
19. } 
21. // Retrieve the value of the password field and check to  
22. // ensure that user has entered at least one character 
23. sPassword = FieldPassword.getValue(); 
24. if (sPassword.equals("")) 
25. { 
26.  agScriptHelper.alert("You must enter a password."); 
27.  return ; 
28. } 
30. //Build the query String for the Data Object 
31. sQuery = "USER_ID = '" + sUser + "'" + 
32.  " AND PASSWORD = '" + sPassword + "'" ; 
34. // Put information into a hashtable 
35. queryInfo.put("Query", sQuery); 
36. qureyInfo.put("Database",getDatabase()); 
38. try 
39. { 
40.  // Invoke the business object 
41.  String queryResult = (String) agpDataLogin.invokeQuery(queryInfo);  
43.  // Check to ensure that the object ran successfully 
44.  if (queryResult == null)  
45.   { 
46.   agScriptHelper.alert("Invalid Login, Please try again. (Null Query)"); 
47.   return ; 
48.   } 
50.  // Check to ensure that the data object returned a result set 
51.  if (queryResult.equals("1")) 
52.   { 
54.  // goto the first row in the result set 
55.  agpDataLogin.gotoFirst(); 
57.  // Get the User has been assigned to an Agency  
58.  bdAgencyKey = (BigDecimal) agpDataLogin.getProperty(0); 
59.  if (bdAgencyKey == null) 
60.  { 
61.   agScriptHelper.alert("Invalid Login, Please try again."); 
62.   return ; 
63.  } 
65.  // Retrieve the required fields from the data object 
66.  bdUserKey = (BigDecimal) agpDataLogin.getProperty(1); 
67.  sUserID = (String) agpDataLogin.getProperty(2); 
68.  sAgencyName = (String) agpDataLogin.getProperty(3); 
70.  // Set the session values for the application 
71.  setSessionValue("AgencyKey", bdAgencyKey.toString()); 
72.  setSessionValue("UserKey", bdUserKey.toString()); 
73.  setSessionValue("AgencyName", sAgencyName); 
74.  setSessionValue("UserID", sUserID); 
75.  setSessionValue("ClientKey", ""); 
77.  // Goto the applications main interface. 
78.  showPage("FrameSet.html"); 
80.  } 
81. else 
82.  { 
83.  agScriptHelper.alert("Error"); 
84.  System.out.println ("Error: Unable to access the Clients");  
85.  } 
86. } 
87. catch (Exception e) 
88. { 
89. agScriptHelper.alert("Invalid Login: " + e.toString()); 
90. } 

Listing 2.
function com_sssw_AgpPage() 
var Page=new com_sssw_AgpPage(); 
function com_sssw_submit(name){document.forms[0].elements['AgEvtSrc'].value=name;
function com_sssw_onBodyLoad(){ 

<TITLE>Pathways, Inc.</TITLE> 
<BODY onload="com_sssw_onBodyLoad();" BGCOLOR="#FFFFFF">
<P><IMG SRC="../Objectstore/Images/PathwayLogo.gif" WIDTH=332 HEIGHT=53 BORDER=0> 
<SPAN STYLE="font-size:12;">Login 
<P><FONT SIZE=2 COLOR="#FFFFFF" FACE="Helvetica"><SPAN STYLE="font-size:12;">Password 
<P><INPUT NAME="S7_" TYPE="Password" SIZE="20"> 

Listing 3.
1. String sClient = "" ; 
2. String sParm = "" ; 
4. sClient = (String) getSessionValue("ClientKey");  
5. sParm = "CLIENT_KEY=" + sClient; 
6. agScriptHelper.setFrameLocation("CaseManagement.html", "content", sParm, null); 

Listing 4.
1. try  
2. { 
3.  String url = "jdbc:sssw:oracle:sid"; 
4. String sSPCommand = ""; 
5.  String sReturn = ""; 
6. boolean bReturn = false; 
7. Integer iClient = new Integer(sClientKey); 
8. Integer iUser = new Integer(sUserKey); 
10. int intClient = 0; 
11. int intUser = 0; 
13. intClient = iClient.intValue(); 
14. intUser = iUser.intValue(); 
16. sSPCommand = "{call pc_income_set_caltotal_sp(?,?)}" ; 
17. System.out.println(sSPCommand); 
19. Connection con = DriverManager.getConnection( url, "userid", "password"); 
21. java.sql.CallableStatement stmt = con.prepareCall(sSPCommand); 
23. stmt.setLong(1, intClient); 
24. stmt.setInt(2, intUser); 
25. stmt.executeUpdate(); 
27. con.close(); 
29. } 
30. catch (Exception ex)  
31. { 
32. System.out.println(ex.toString()); 
33. ex.printStackTrace(); 
34. return; 
35. }



All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.