J2EE Web Application - Master Detail and Lookup Using HTML DataWindows

To do this exercise we will work with EAServer, PowerJ and PowerBuilder. This exercise will show you the basics for creating a J2EE Web application using JSP and a Java Bean to call EAServer. We will create a couple simple DataWindows to implement a Master Detail on a single window and also create a pop-up search window. This example uses the EASDemo database and the connection cache in Jaguar. Make sure you can access the cache by name and that the cache name is EASDemo.


PowerBuilder Component

The PowerBuilder component is very simple. In my example, I will create several dataobjects and a component called n_power in a package called power. See objects below.

Customer Lookup

The first dataobject is d_customer_lookup. Create a computed field in the dataobject to display customer's name: lname + " " + fname. Notice the dataobject must also contain the columns lname, fname and id. These columns must exist so we can reference them from client side JavaScript. We don't want any columns visible except the computed field so set the visible property of lname, fname and id to "visible =0". This can be done via the Visible property checkbox or by clicking the property icon for Visible and setting the visible expression value to 0 (zero). Click OK.

Select all records from the customer table.

Visible Expression

DDDW Products

The drop down DataWindow for product is a select of all products. Make sure to select the product ID, name, description and price. We can then make a computed column to display products. The drop down is used in the d_order_item dataobject.

Select columns as displayed below.

Employee

The d_employee dataobject is used to select a sales rep in the d_order_item dataobject. Simply create a dataobject that selects all employees. Make sure you select employee ID, fname and lname.

Select as below.

FIN Code

The dataobject d_fin_code is a drop down DataWindow used in the d_order_item dataobject.

Select fin code and description.

Order and Order Item

The two main dataobjects are d_order and d_order_item. These two dataobjects have special tricks so read closely.

Order

d_order is used to create and add orders. I need to trick the HTML DW in this dataobject. I want to display the customer's name so I added a dummy column to my SQL. Simply add a string ' '. Name the column full_name. For client-side scripting to work, the column must be on the dataobject and it must have a tab order. So we trick it. We simply set the expression for visible to 0 (zero) for full_name. We then create a computed column that equals full_name. Now we can reference it with client-side JavaScript and stop the user from editing the value. It's display only.

You will use a retrieval argument for Order.

Add a drop down DataWindow to fin_code_id.

Make sure you have the drop down List for Region.

The last column, sales_rep, needs a drop down DataWindow.

DataWindow buttons must be set. Set the Update button to Update action.

Set the Lookup button to User Defined and name blookup_cust_id

The most important part is to add two link arguments to the dataobject so we can pass the context of the detail with the master. We will do the same process to the detail. The link arguments are added to the DataWindow not to a column.

The expression must be correct or the argument will not be passed. See example below with added spaces.

obj_d_action= ' " " ' |obj_d_context= ' " " ' |id= ' string ( arg_id ) '
obj_d_action=single double double single |obj_d_context=single double double single|id=single string( arg_id ) single

Order Item

The d_order_item dataobject has a retrieval argument of order id.

Select as follows:

Make sure you add a drop down DataWindow for product.

Command Button Add and Delete must be set to a User Defined action. This will allow us to pass action and context from the master and detail dataobject. They must also be named badd and bdelete so we can reference them in the client-side javascript.

Again, add two link arguments to the dataobject. The link arguments are added to the DataWindow not to a column.

The expression must be correct or the argument will not be passed. See below with added spaces.

obj_action= ' " " ' |obj_context= ' " " ' |id= ' string ( arg_id ) '
obj_action=single double double single |obj_context=single double double single|id=single string( arg_id ) single

The self link argument allows you to move the values from master to detail or detail to master. We now have all our dataobjects and can tie them together in our code to create a simple master detail JSP page.

The PowerBuilder Jaguar Component

Create a new PowerBuilder Jaguar component called n_power and add two methods as follows:

HTML Method

of_html will be used to retrieve a lookup DataWindow and of_master_detail will be used to create orders.

transaction t
datastore ds
string sz_html
errorlogging el

this.GetContextService( "errorlogging", el )

t = Create transaction
t.DBMS = "ODBC"
t.DBParm = "UseContextObject='Yes',CacheName='EASDemo'"

connect using t ;

ds = create datastore
ds.dataobject = arg_dataobject
ds.SetTransObject( t )
ds.Retrieve()

ds.object.datawindow.htmlgen.browser = arg_browser

If len( arg_action ) > 0 Then
ds.SetHTMLAction( arg_action, arg_context )
End If

sz_html = ds.object.datawindow.data.html

disconnect using t ;

Return sz_html

Master Detail Method

of_master_detail will be used to create an order and order items.

transaction t
datastore ds_m, ds_d
string sz_html
errorlogging el

this.GetContextService( "errorlogging", el )

el.Log( "Action M " + arg_action_m )
el.Log( "Context M " + arg_context_m )
el.Log( "Action D " + arg_action_d )
el.Log( "Context D " + arg_context_d )

t = Create transaction
t.DBMS = "ODBC"
t.DBParm = "UseContextObject='Yes',CacheName='EASDemo'"

connect using t ;

If arg_id = 0 Then
SELECT max( id ) + 1
INTO :arg_id
FROM "sales_order"
USING t;
End If

ds_m = create datastore
ds_m.dataobject = "d_order"
ds_m.SetTransObject( t )
ds_m.Retrieve( arg_id )

ds_m.object.datawindow.htmlgen.browser = arg_browser

If len( arg_action_m ) > 0 Then
ds_m.SetHTMLAction( arg_action_m, arg_context_m )
Else
ds_m.SetHTMLAction( "IGNORE", arg_context_m )
End If

If ds_m.RowCount() < 1 Then
ds_m.InsertRow(0)
ds_m.object.id[1] = arg_id
End if

ds_d = create datastore
ds_d.dataobject = "d_order_item"
ds_d.SetTransObject( t )
ds_d.Retrieve( arg_id )

ds_d.object.datawindow.htmlgen.browser = arg_browser

If len( arg_action_d ) > 0 Then
ds_d.SetHTMLAction( arg_action_d, arg_context_d )
Else
ds_d.SetHTMLAction( "IGNORE", arg_context_d )
End If

sz_html = sz_html + ds_m.object.datawindow.data.html
sz_html = sz_html + "<br>"
sz_html = sz_html + ds_d.object.datawindow.data.html

disconnect using t ;

Return sz_html

Deploy Component

We need to create a project to deploy our new component. Simply create a deploy project and select n_power as your component. Make sure you specify the component is autodemarcation. Because our component does not use datastores as an instance variable you can disable bind thread.

Set the component properties as follows:

Make sure you specify your server, password and port.

Now that our component is published we can code our Bean and JSP pages to our new component.

Building a J2EE WAR

The first step is to create a new workspace. I called mine power. We will create a bean target and JSP target and a java class target. When we create the JSP target we will also create a WAR. The WAR will hold the JSP and Java Bean.

JSP Target

We are creating the JSP target first so PowerJ will create the WAR needed to bundle all the files up into a J2EE WAR. Later in this exercise we will create some JSP pages.

Select the JSP 1.1 and follow the wizard.

Do not create a deploy target. We will simply compile the WAR and import into Jaguar.

Targets have now been added to the power workspace. Notice below that the wizard did not use the name I specified for the first page. I can rename or delete and create a new JSP page. You do not use the wizard to create a new page. Simply select the Page tab and select JSP page.

Java Classes Target

From the menu select new and select the Java Classes icon then click OK.

You need to create a dependency for the JSP target.

Specify the location of the stub target.

Notice the Stubs target is created and a dependency is added to the JSP target.

To get stubs we need to go into Jaguar Manager and export stubs/skeletons for power package (the PowerBuilder component we published).

Specify %jaguar%\html\classes

The classes will be generated and we can now import and compile. Note if you left the classes in this location and compiled, the Web application would find the classes. It is normal practice to compile the stubs in your WAR so you can move the WAR to a different server and have all needed classes moved as well.

Back in PowerJ we can now import the generated classes and compile in PowerJ.

When the list box pops up go to %jaguar%\html\classes\power and select all the Java files in this directory.

All the files will be added to our Java Classes target.

It's very important we tell PowerJ where to put the classes and Bean in our WAR. By specifying the Build Options of the target, we can have the classes placed in the correct location of our Web application.

Now we can code our Java Bean to access the Jaguar PowerBuilder component.

Note below the new Java Bean was placed in our Stubs target. We can now add methods to the bean so we can call it from our JSP.

Coding the Bean

We first need to import our stubs into our class. Notice the import of the power package and the declaration of n_power as the jagComponent.

To create a new method, right-click on the bean and select Insert Method.

Add a new method called of_create() return String. See below.

To added the code to connect to Jaguar we need to use an ORB. Add an import statement to access the ORB:

import org.omg.CORBA.*;

Add the following code to the of_create method:

java.util.Properties props = new java.util.Properties();

props.put("org.omg.CORBA.ORBClass","com.sybase.CORBA.ORB");

ORB orb = ORB.init((String[]) null, props);

SessionManager.Manager lManager = SessionManager.ManagerHelper.narrow( orb.string_to_object("iiop://{put in your server}:9000") );
SessionManager.Session lSession = lManager.createSession("jagadmin", "{put in your password");
SessionManager.Factory lFactory = SessionManager.FactoryHelper.narrow(lSession.lookup("power/n_power"));

this.jagComponent = n_powerHelper.narrow( lFactory.create() );

return "good" ;

See image below.

Next we need to create a method called of_html. It needs several arguments.of_html(String aAction, String aContext, String aDataobject, String aBrowser )

Add the following code to the method.

String sz = new String("");

try {

this.of_create( );

sz = this.jagComponent.of_html( aAction, aContext, aDataobject, aBrowser );

}

catch (CTS.PBUserException aException) {}

return sz ;

The last method to add is of_master_detail. Again we need to add several arguments:

of_master_detail(int aID, String aActionM, String aContextM, String aActionD, String aContextD, String aBrowser)

Add the following code:

String sz = new String("");

try {

this.of_create( );

sz = this.jagComponent.of_master_detail( aID, aActionM, aContextM, aActionD, aContextD, aBrowser );

}

catch (CTS.PBUserException aException) {}

return sz ;

Our bean should now compile and we are ready to code our JSP.

JSP Pages

To create new JSP pages right click on the JSP Target and select new.

Switch tabs to the Code Files and select JSP file and click OK.

PowerJ will prompt you for a name.

lookup.jsp

The first page we will create will be called lookup.jsp Add the following code to the page.

<jsp:useBean id="jspBean" class="com.powerteam.jspBean" scope="session" />
<%
int l_key ;
String sz_key = new String("0");
String sz_html = new String("");
String sz_action = new String("") ;
String sz_context = new String("") ;
String sz_browser = new String("");

sz_browser = (String)request.getHeader( "User-Agent" );
if ( sz_browser == null ) {
sz_browser = "" ;
}

sz_action = (String)request.getParameter( "obj_action" ) ;
if ( sz_action == null ) {
sz_action = "" ;
}

sz_context = (String)request.getParameter( "obj_context" ) ;
if ( sz_context == null ) {
sz_context = "" ;
}

sz_html = jspBean.of_html( sz_action, sz_context, "d_customer_lookup", sz_browser );

%>
<html>

<head>
<title>Lookup</title>
</head>
<script language="javascript">
function obj_ButtonClicked(row, objectName ){

if (objectName == "bselect" ) {

sz_name = obj.GetItem( row, "lname" ) + ", " + obj.GetItem( row, "fname" ) ;
sz_id = obj.GetItem( row, "id" );

opener.obj.SetItem( opener.obj.GetClickedRow(), "cust_id", sz_id ) ;
opener.obj.SetItem( opener.obj.GetClickedRow(), "full_name", sz_name ) ;

window.close();

}
}
</script>
<body>
<p><%= sz_html %></p>
</body>
</html>

order.jsp

The order.jsp page is our main page. If you look at the code here you will be able to see how we collect the action and context and add it to the self link arguments we defined in the PowerBuilder DataWindow. Add the code below to your order.jsp.

<jsp:useBean id="jspBean" class="com.powerteam.jspBean" scope="session" />
<%
int l_id ;
String sz_id = new String("0");
String sz_html = new String("");
String sz_action_m = new String("") ;
String sz_context_m = new String("") ;
String sz_action_d = new String("") ;
String sz_context_d = new String("") ;
String sz_browser = new String("");

sz_id = (String)request.getParameter( "id" ) ;
if (( sz_id == null) || (sz_id.equals( "" ) )) {
sz_id = "0" ;
}
l_id = Integer.parseInt(sz_id);

sz_action_m = (String)request.getParameter( "obj_action" ) ;
if ( sz_action_m == null ) {
sz_action_m = "" ;
}
sz_context_m = (String)request.getParameter( "obj_context" ) ;
if ( sz_context_m == null ) {
sz_context_m = "" ;
}

sz_action_d = (String)request.getParameter( "obj_d_action" ) ;
if ( sz_action_d == null ) {
sz_action_d = "" ;
}
sz_context_d = (String)request.getParameter( "obj_d_context" ) ;
if ( sz_context_d == null ) {
sz_context_d = "" ;
}

sz_browser = (String)request.getHeader( "User-Agent" );
if ( sz_browser == null ) {
sz_browser = "" ;
}

sz_html = jspBean.of_master_detail( l_id, sz_action_m, sz_context_m, sz_action_d, sz_context_d, sz_browser );

%>
<html>
<head><title>Web DW Demo</title>
</head>
<SCRIPT Language=JavaScript>
function obj_ButtonClicked( row, objectName ){

if (objectName == "blookup_cust_id" ) {
popupwindow = window.open("","Lookup","width=350,height=400,directories=no,toolbar=no, resizable=no,menubar=no,scrollbars=yes,dependent, titlebar='Lookup',alwaysRaised=yes,left=245,top=290");
popupwindow.creator = window ;
popupwindow.location="lookup.jsp";
}

if (objectName == "bvalidate" ) {

// set action and context
obj_m.submitForm.obj_d_action.value = "";
obj_m.submitForm.obj_d_context.value = obj_d.GetFullContext() ;

obj_m.actionField.value = "Validate" ;
obj_m.contextField.value = obj_m.GetFullContext();

obj_m.submitForm.submit();

}

}

function obj_d_ButtonClicked( row, objectName ){

if (objectName == "badd" ) {

// set action and context
obj_d.submitForm.obj_action.value = "";
obj_d.submitForm.obj_context.value = obj.GetFullContext() ;

obj_d.actionField.value = "AppendRow" ;
obj_d.contextField.value = obj_d.GetFullContext();

obj_d.submitForm.submit();
}

}
</SCRIPT>
<h1><b><font color="#FF0000">Order Enter</font></b></h1>

<p><%= sz_html %></p>

</html>

Build and Deploy J2EE WAR

As stated earlier you must specify the location to place the java classes in our Web application. You can specify the Build Options for the classes target. It's very important we tell PowerJ where to put the classes and Bean in our WAR. By specifying the Build Options of the target we can have the classes placed in the correct location of our Web application.

To build our WAR we simply do a right mouse on the WAR target and select build. After building the WAR we have a WAR file on our computer under the workspace powerWar: workspace\powerWar\Debug

The WAR name is powerWar.war
Open Jaguar Manager and import the WAR. You can import the WAR as shown below.

Select the WAR file.

After Deploying the WAR you need to install the Web application. Install an Existing Web Application.

Before restarting the Jaguar server you need to make sure your new Web application knows about all classes. If you are using EAS3.5 or EAS4.0 you do not need this step. If you are using EAS3.6 you must manually add the power package to the Web application. Right mouse on the Web application and select Web application properties.

Select the All tab and modify the com.sybase.jaguar.webapplication.java.classes. You need to add: *,power.*,com.powerteam.*

You are now ready to restart Jaguar and test your application.

Test your J2EE Application

You must first restart Jaguar so it will know about the new classes and JSP files that were added. To test we need to open a browser and type in the URL to our JSP application. On my machine Jaguar's HTTP server is running on PORT 8000 and my Web application is named powerWar so the URL is as follows: http://jones-dean:8000/powerWar/order.jsp

The first thing I should be able to do is lookup a customer.

The select value is returned to the window that opened the search.

Notice all drop down DataWindow's are populated.

Notice you can insert rows and keep the context of both DataWindows.

This example is very simple. We did not code the Update button to take the context of the detail. You would need to do this to allow saving the data. Also the Add button does not take the order ID from the master and place in the detail. These steps are very easy to do after completing this exercise. Try passing the detail action and context with the master DataWindows. For a more realistic version of master detail look at smlPortal's Customer demo. This demo shows how advanced master detail can be. It allows you to drill into a customer>order>order item. This master detail is done without writing any JSP or Java. You simply create your DataWindows, write your validation in an NVO and deploy using our admin tool. Take a minute and go through the PowerPoint. Then get a user ID and password and give it a try!

Contact Us


PowerObjects Logo

718 Washington Ave. N.
Suite 202
Minneapolis, MN 55401
612.339.3355
1.866.770.3355
info@powerobjects.com

Passion

"Leverage technology to solve business problems."


Core Values

  • Always Add Value
  • Think Team
  • Love What You Do
  • Live the Technology
  • Do the Right Thing

Exchange Hosting

PowerObjects is now offering full service MS Exchange hosting at $9.95 per 500 MB mailbox!

Contact sales@powerobjects.com

» learn more