Sie sind auf Seite 1von 18

The opinions expressed by the author of this document are entirely his own and do not

reflect the position of Oracle Corporation.

For technical information about J2EE Development on Oracle, visit the Java Developer
Center (http://www.oracle.com/technology/java) on Oracle Technology Network.
A DATABASE-CENTRIC APPROACH TO J2EE
APPLICATION DEVELOPMENT
—Toon Koppelaars
Centraal Boekhuis

Introduction
Building a J2EE/Java application may seem a daunting task at first. Java, object-oriented programming itself, is truly
different, and cannot be compared with PL/SQL (which can be classified as an easy to learn programming language).
There are many new technologies one has to explore and learn: for example, various frameworks to enable the Model-
View-Controller (MVC) design pattern; HTTP, the stateless-protocol; HTML in the browser, including JavaScript;
JDeveloper, Oracle’s strategic Integrated Development Environment (IDE). Will you ever be able to grasp all this new
technology? There are ways to ease this daunting task, in particular for traditional Oracle client/server shops. The most
successful way is to adopt a database-centric approach. The Oracle server has come a long way and various features such
as Virtual Private Database (VPD), instead-of triggers (IOT), (updateable) views, ref cursors, pipelined table functions,
and packaged procedures today enable you to implement the majority of all involved application logic into the well-
known database server. Strongly preferring stored PL/SQL to Java when deciding on where code should go, will enable a
very thin J2EE/Java layer. By never writing a line of Java code that could have been a line of PL/SQL code, you will
considerably reduce the risk in your J2EE project.
In order to deal in a structured way with the question in the title above, we will first present a model of the J2EE
technology stack from the viewpoint of “code execution environments.” This will enable us to talk about the where of
code execution. Next we will develop a generic classification scheme for code (irrespective of where the code ends up
running). This will enable us to talk about what code. We can then map code onto the technology stack. This article will
discuss how traditional Oracle client/server shops can approach the J2EE world using a database-centric mapping. We
explain in more detail how we successfully apply this strategy in all of our J2EE application development efforts.

Recap Of The J2EE Architecture


It is not our intention here to give an in-depth description of the complete J2EE specification. Rather we will explain
some main architecture components that enable you, the Oracle client/server guru, to start understanding the J2EE arena
in general, and specifically its execution environments.
J2EE defines a multitier, distributed object architecture. The multitier environment breaks down into a client tier, a
middle tier (the application server), and a data tier (the database server). Inside this multitier environment, J2EE supports
the execution of five different software component types.
1. Java inside client OS (fat clients)
2. Applets
3. Servlets
4. JavaServer Pages (JSP)
5. Enterprise JavaBeans (EJB)
Java Inside Client OS
This is J2EE’s way of creating a traditional fat client. Using Java in conjunction with libraries such as Swing or Abstract
Windowing Toolkit (AWT), you write a front-end application that presents a rich user interface to the user. This Java
application communicates with the middle tier to invoke business services and/or the data tier to retrieve/manipulate
persistent data. The application runs inside the Java Virtual Machine (JVM) of the client operating system (typically
Windows).
Applets
These are Java programs that execute inside an Applet Container in your web browser.1 Usually this container will be the
JVM of your browser. Applet execution is initiated by your browser whenever it detects the applet tag in the HTML

1
Applets should not be confused with JavaScript. JavaScript is Java-like code that is embedded in HTML source. JavaScript is used to
perform simple checks in the client tier (e.g., domain checks) or to enhance the look/feel of HTMLin the browser.
source. Part of the applet tag is the applet'
s Java class file that needs to be fetched from the Web server. Once the browser
has downloaded this file from the Web server, it invokes a start-method which starts applet execution. Applets too can
use the popular Swing and AWT libraries to provide a rich (i.e., not HTML- or XML- based) user interface to the user.
As such they too can be seen as “fat” client programs, only these run inside your browser.
Servlets
These are Java programs that execute inside a Servlet Container on your Web server. This container is provided by your
vendor: Oracle provides OC4J (Oracle Containers for J2EE) as the J2EE Servlet Container. Note that a Servlet Container
is itself a Java program, so it in turn runs inside the JVM provided by the operating system of your Web server.
Execution of servlets is typically started by an incoming HTTP request (post or get). When handed the request, OC4J
instantiates the servlet object by loading the Java class file that holds the servlet'
s byte code from the file system and then
invokes the doPost or doGet method on the servlet object. Servlets handle the HTTP request and eventually create the
next (HTML or XML) page to be sent back to the browser that initiated the request. By doing so, servlets can be viewed
as Java' s answer to existing solutions such as Common Gateway Interface (CGI), PHP Hypertext Preprocessor (PHP),
and Active Server pages (ASP).
JavaServer Pages (JSP)
These are HTML pages mixed with special tags that hold embedded Java. This Java will be executed prior to sending the
HTML to the browser and is able to generate dynamic content. JSPs eventually execute in the same container as servlets
do. Whenever OC4J detects that a JSP needs to be executed, it reads the JSP file from the file system and converts the
JSP into a servlet by generating a class file for it. It then instantiates this servlet class and invokes a method to start
execution of this “servletised” JSP. It's often said that “a JSP is a Servlet inside out” (HTML that executes embedded
Java), and vice-versa “a Servlet is a JSP inside out” (Java that outputs HTML).
Enterprise JavaBeans (EJB)
These are Java programs that execute inside an EJB Container on your application server (not necessarily the same as
your Web server). With Oracle, OC4J also acts as the EJB Container. EJBs are used to implement reusable business
functions. As such, EJBs typically act as “back-end” application services for the other component types. They are
considered to be fat, meaning that they hold the business and data logic code for the application. EJBs sit between
servlets/JSPs and the data tier (servlets/JSPs can call EJBs). EJBs can also call other EJBs, potentially on other
application servers. EJBs will communicate with the persistent data store (database) on the data tier.
Servlets, JSPs, and EJBs are enabled to access the relational database running at the data tier by means of Java DataBase
Connectivity (JDBC) . JDBC is J2EE' s standard database access application-programming language (API), that replaces
the well-known SQL*Net layer in client/server applications. Figure 1 summarizes the multitier, distributed object
architecture.

EJB
EJB
EJB

Java
r m i /i i o p

Se r v l e t J
A p p let Se r v l e t D
h t t p (s)
JSP B
H t m l /X m l
JSP C RD BM S

Figure 1. The Three Tiers and Five J2EE Component Types

J2EE Says Nothing About Data Tier (Code) Objects


There are no software component types in the J2EE architecture that run on the data tier. J2EE does not regard the data
tier as a tier that could (or even should) run code. On the contrary the data tier is supposed to only house persistent data,
and surely no code. The J2EE standard prides itself of being portable across platforms. This is enabled by Java’s “Write
Once Run Anywhere” promise. As such J2EE will never introduce data tier Relational Database Management System
(RDBMS) specific specifications (nor any other vendor-specific service). The API between the middle tier and the data

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
tier typically does not have procedure calls in it, but is fully based on SQL statements (select, insert, update, delete) in
conjunction with transactional and session control commands (commit, rollback, connect, disconnect). Many of us Oracle
adepts must find this very sad. The Oracle database server is capable of doing so much more than just service (the
simplest2) SQL statements.

J2EE Architecture Or Architectures?


As may have become clear from the sections above, there is actually no such thing as one J2EE architecture. You will
have to pick your own architecture to fit your J2EE application. Not all J2EE applications will use/require all software
component types mentioned above. Looking at the middle tier, the majority of the applications out there do not use EJBs
(considered a most difficult-to-use component type). Instead they employ some framework to implement direct access to
tables/views in the database. Typically a framework will offer an execution environment within which code can be added
around the retrieval and manipulation of data. Oracle’s BC4J framework is a prime example of such a framework. In a
very similar way as Oracle*Forms does, BC4J too allows you to add block/row/item level triggers that implement
additional business logic. Looking at the client tier, most J2EE applications make use of the thin HTML front end to
implement the user interface. Fewer employ applets or fat Java clients to implement the user interface.
A common denominator in all alternative architectures is the use of the MVC design pattern. The next section will
introduce this design pattern; thereafter we will present a few alternative architectural approaches.
MVC
The Model-View-Controller design pattern sounds new, but in fact is something Oracle client/server developers (perhaps
not knowingly) do every day when building Forms applications. This design pattern dictates that application code should
be separated out into three parts: the business logic part, the user interface part and the controller part.
Handling Business Logic: Model
This is the application code that is responsible for the “Business Logic,” including the data retrieval and manipulation.
Client/server developers that have adopted the fat database server model separate this code by creating database-stored
PL/SQL modules that are called by client-side code, and by creating database triggers that are fired by data manipulation
language (DML) statements for validation of the transaction. J2EE developers will use a specific model framework like
BC4J to develop this code. The use of Toplink or EJBs can also be positioned within the M of MVC.
Creating User Interface: View
This is the code that is responsible for creating the “Look” of the application. It creates the very front end of the
application: screens/pages that the user is presented with to interact with the application. Client/server developers use the
Forms*Builder screen painter to define screens (Canvases, Blocks, LOVs, menus, etc.) and then delegate creating the
Look to the runform component of Forms. J2EE developers will use a specific view framework like UIX to develop this
code. Homegrown tag libraries for JSPs can also be positioned within the V of MVC.
Dealing with User Interface events (triggered by user): Control
This is the code that is responsible for creating the “Feel” of the application. Every event that the user can trigger by
using the view layer of the application is dealt with by this code. Client/server developers, again, delegate the majority of
this task to the state machine called runform. Runform presents us with default behavior that deals with every possible
user interface event. It even offers us the ability to adapt this behavior by writing triggers (in the client side) that
override/enhance the default behavior. J2EE developers will use a specific control framework like Struts to develop this
code. Oracle’s own Application Development Framework (ADF) controller can also be positioned within the C of MVC.
Alternative MVC Approaches In J2EE
We will study alternative MVC approaches by looking at the amount of application code that is deployed in each tier.
This is a suitable way to explore these alternatives, given the context of this article. A tier is considered fat if it houses
lots of code, and thin if it houses little code. In this way we can generate the eight alternatives shown in Table 1.
Alternative Client Tier Middle Tier Data Tier
1 Thin Fat Thin
2 Fat Fat Thin
3 Fat Thin Thin
4 Fat Thin Fat

2
As we will see later on, a pure J2EE application will never produce complex SQL statements. Only single table selects, primary key-
based (i.e., single row) updates and deletes, and single row inserts are produced by such an application.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
5 Thin Fat Fat
6 Thin Thin Fat
7 Fat Fat Fat
8 Thin Thin Thin

Table 1. Alternative MVC Approaches

1. Thin/Fat/Thin (see Figure 2)


This is the typical J2EE way of creating an
HTML-based application. Control is
implemented, for instance, with Struts.
Model is implemented with EJB or some
model framework (e.g., BC4J). View is
implemented with JSP or some view
framework (e.g., UIX). All the browser does
is display a (poor) HTML GUI3 (thin), and
send HTTP requests to the Struts controller.
The controller then coordinates the
execution of EJB code or model framework
code. Inside these all business logic and data
logic processing has been implemented (fat).
Eventually simple queries (single table), or simple DML statements (single row, primary key-based) are
executed towards the database (thin). Struts then determines the next page to be sent back and initiates the view
framework to do so. Both control and view will not offer the possibility to house business or data logic, since
that would violate the MVC design pattern.
2. Fat/Fat/Thin (see Figure 3)
This is the typical J2EE way of creating a
rich GUI-based application (either applet-
based, or Java in OS-based). Control and
view are implemented within the fat client-
side GUI application (compare to
client/server- Oracle*Runform). Model is
implemented with EJB or some model
framework. The client tier is in charge in this
alternative (fat): it deals with creating the
rich GUI and handling all UI events (control)
on behalf of the user. In this alternative the
client delegates the execution of all business
logic and data logic processing to EJB code
or model framework code, which are located centrally in the middle tier (fat). The database again only needs to
serve simple queries and simple DML
statements (thin) initiated by the fat model
layer. In short, processing for V and C takes
place in the client tier and for M takes place
in the middle tier.
3. Fat2/Thin/Thin (see Figure 4)
This is basically a client/server architecture
molded into the J2EE architecture. The
application is again either applet-based or
Java in OS-based. The difference with the
previous alternative is that all business and

3
By a poor UI we mean a UI that does not respond directly to user-initiated events. A block-mode device, which is what a browser
displaying HTML can be considered, is an example of a device offering a poor UI. No processing takes place within the browser (to
respond directly). Only when the user submits the HTML form to the server will processing start (at the server). This browser
behaviour can be enhanced by using JavaScript enabling a somewhat more responsive UI. JavaScript is code that runs within the
browser and is triggered by UI events initiated by the user.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
data logic is now also implemented within the rich GUI application running on the client tier (fat). So not only is
this tier fat due to the rich GUI it offers, but also due to all the logic code it hosts: hence the “fat-square” above.4
The fat client application will either communicate directly with the back tier via JDBC, or go through the middle
tier via a thinly configured model framework, i.e., it only offers database connectivity and does no additional
logic processing in this case (thin). The database again needs to serve simple queries and simple DML
statements (thin) initiated by the fat client tier. In short all dimensions M, V, and C are located in the client tier.
4. Fat/Thin/Fat (see Figure 5)
This is alternative 2 where the M has moved
from the middle tier to the data tier.
The GUI is rich (applet or Java in OS). This
can be considered a client/server
architecture where all business and data
logic is now taking place in the data tier: the
middle tier (thin) only supports database
connectivity from the client to the data tier.
The database is now fully employed (fat)
through the use of stored PL/SQL
(functions, procedures, packages), triggers,
and complex views (updateable, possibly
with instead-of triggers). Also the
complexity of data retrieval and
manipulation is now dealt with by programming complex SQL queries and DML statements. In short, view and
control sit in the client tier, and model in the data tier.
5. Thin/Fat/Fat (see Figure 6)
This is again an HTML-based application
(thin client tier). All dimensions of MVC are
available in the middle tier (fat). Business
and data logic processing takes place not
only within the model framework, but also
within the data tier (fat). The big challenge
in this alternative is: how do we divide this
logic processing? What part do we
implement within the model framework, and
what part within the rich PL/SQL
environment of the database? For this
alternative to be manageable, we first need
to establish a clear separation of concerns in
this area.
6. Thin/Thin/Fat (see Figure 7)
This is alternative 1 where the M has moved
from the middle tier to the data tier. All
business and data logic processing takes
place inside the database (fat). The model
framework is deployed only for database
connectivity; no additional logic code runs
within this framework (thin). Compared to
the previous alternative (5), the division of
the business and data logic processing has
been made 100 percent in favor of the data
tier. The database is now fully employed
(fat) through the use of stored PL/SQL
(functions, procedures, packages), triggers,
and complex views (updateable, possibly with instead-of triggers). Also, the complexity of data retrieval and
manipulation is now dealt with by programming complex SQL queries and DML statements. In short, view and

4
This alternative is actually comparable with the way we did client/server applications in the early days, when the database tier was
not yet capable of running business or data logic code (pre-Oracle7 era).

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
control sit in the middle tier, and model in the data tier. This alternative is actually the proposition of this paper
(we will come back to this later).
7. Fat/Fat/Fat (see Figure 8)
Business and data logic is distributed among all tiers:
within the fat client, within the model framework
and/or EJB layer, and also within the database. The
big challenge introduced in alternative 5 is even
bigger here. Managing application development
within this architecture must be a complete
nightmare.5
8. Thin/Thin/Thin
This alternative is mentioned for completeness,
but we do not consider this an architecture that
is appropriate for application development, since
there is no tier to hold any business and data
logic code.

Code Execution Environments


As mentioned in the introduction we will establish code execution environments enabling us to talk about the where of
code execution in a structured way. Within the context of the J2EE architecture alternatives introduced above, and
looking from a viewpoint of code execution environments we can now distinguish the following:
1. SQL and PL/SQL execution within the Oracle RDBMS (data tier)
2. Java code execution (middle tier, in the Web container or the application container)
3. JavaScript code execution (client tier, inside browser)
4. Java code execution (client tier, inside browser)
5. Java code execution (client tier, inside OS)
The execution environments that are available to you depend of course on the J2EE alternative that you have chosen for
your application. Since the most often chosen J2EE architectures involve a browser client displaying HTML, we will not
consider the latter two environments (for creating a fat GUI) in the remainder of this article. From now on we assume a
browser client displaying HTML.

Classifying Application Code


Before we can talk about where (what) code should go, in terms of the execution environments, we must also establish
some classification of application code. Up until now we have used somewhat intuitive terms such as:
• Data retrieval and manipulation code
• User interface code
• Business logic code
• Data logic code
In this section we will more precisely define the meaning of the above terminology.
Data Retrieval And Manipulation Code
This is code that queries (retrieves) the persistent data store, or changes (manipulates) the persistent data store. All, and
only, SQL Select and DML statements fall in this class.
User Interface Code (UI Code)
This is code that creates the user interface (look), including code that responds to user interface events and then modifies
the user interface (feel). Part of the creation and/or modification of such user interface will require calls to business logic
code (defined hereafter). Dependent upon the results of these calls, the user interface will be modified differently.
Examples:

5
I often refer to this alternative as the Run-Run-Run (as fast as you can) alternative. You will end up with this architecture if you
decide to put a PL/SQL wizard, an EJB believer, and a Swing hacker together in your development team.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
- In a Forms application, user presses Enter-query, enters query criteria, then presses Execute-query. UI code (that
is part of the Runform executable) will submit the query towards the RDBMS and display the rows returned
inside the Forms block. Note the query itself is not part of the UI code.
- In a browser HTML application, user presses a tab-bar that is not yet current. UI code will determine how the
user interface should be changed and executes code that generates the new HTML to be displayed by the
browser.
Business Logic Code (BL Code)
This code is subdivided into two classes: code that composes/executes transactions and code that composes/executes
queries.
• Query composing/executing code
This is procedural code surrounding data retrieval code. This code is responsible for composing the actual Select
statements, or conditionally determining which Select statements should be executed. This code also initiates the
execution of these statements and handles the rows returned by the RDBMS. We will refer to this class as read-
BL code (rBL code).
Examples:
- In a Forms application, user enters a customer id in an item, post-validate-item trigger fires and executes a
query to retrieve the customer name, customer address, and debit amount.
- In a browser HTML application, user enters query criteria and presses Search button. The rBL code
communicates the criteria to the RDBMS and submits a query. Using the criteria the RDBMS dynamically adds
an appropriate where-clause to the query (Virtual Private Database feature) and then executes it.
- The definition of a database view can also be considered part of this code class.
• Transaction composing/executing code
This is procedural code surrounding data manipulation code. This code is responsible for composing a (series
of) DML statement(s), or conditionally determining which DML statements should be executed. This code also
initiates the execution of these statements. Depending upon the return code(s) given by the RDBMS, this code
will also execute the commit or rollback processing for the transaction. Note that data retrieval will often be part
of the transaction composition. We will refer to this class as write-BL code (wBL code).
Examples:
- In a Forms application, user presses Commit after having changed various queried records. The wBL code will
generate and execute the required DML statements to change the corresponding records in the database (this is
performed by the Runform executable).
Or, the user presses some button inside a Form, which then fires a stored procedure inside the database that
starts execution of a large (batch) transaction.
- In a browser HTML application, user has entered a new record, and presses a Save button. The wBL code will
create and execute the required DML statement to insert the new record into a database table. In this case this
will be performed by the model framework (or EJB).
All code that is considered data logic code (see below) is not considered part of BL code.
Data Logic Code (DL Code)
This is code that deals with the checking of data integrity constraints (i.e., business rules). It is responsible for the
upholding of all assertions (rules) that are applicable to the database table contents. We consider this code to be in a
distinct class by itself and not part of the above mentioned BL code class. Whenever wBL code executes transactions, the
data manipulation code that gets executed as part of such transaction can potentially violate data integrity rules. If this is
the case, DL code will ensure that such a transaction fails and be forced to rollback. For the majority of the integrity
rules, the DL code will need to execute data retrieval code to determine if a given data manipulation is allowed or not.
[Kopp-2003] describes in much detail various issues and how-tos regarding the implementation of DL code. It also
introduces the following sub-classification of rules that can be applied one-on-one to the DL code that checks the rules:
1. Rules that are checked by inspecting a single column value (attribute rules).
2. Rules that are checked by inspecting more than one column value in a single record (tuple rules).
3. Rules that are checked by inspecting more than one record in a single table (table rules).
4. Rules that are checked by inspecting more than one table (database rules).
5. Rules that are checked by inspecting values prior to TX-start and values prior to TX-end (transaction rules).
Examples:
- In a Forms application, user changes status of a record and presses commit. Pre-update block trigger fires and
executes DL code to check a Business Rule that involves this record status.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
- In a browser HTML application, user enters a record and presses Save. Insert statement is executed by wBL
code, RDBMS fires pre-insert table trigger that executes DL code to check an involved Business Rule.
Of the four code classes introduced above only the last three are fully distinct from each other and together cover the full
spectrum of application code. Data retrieval and manipulation code is embedded in (and thereby part of) either BL code
or DL code.

Figure 9. Positioning the Different Code Classes


Figure 9 illustrates the way the different code classes interact with each other. Note that actual code of an application is
never fully separated as visualized in this figure. For instance the UI code will hold embedded BL code6 or DL code.7
And wBL code will typically hold embedded DL code.8 These embedded code modules of a certain class inside code of a
different class, can be considered the API objects of that class. As we will see later on it is sensible to make a clear
distinction of all these API code modules in a class versus the non-API code modules in that class.

Mapping Code Classes Into The Execution Environments


Now that we have established a classification for application code and execution environments that are available to us,
we will proceed with the mapping of code into these environments. Given the context of this article we will only
investigate database-centric mappings (or slight deviations from this). Also, since we assumed a context of a browser
client displaying HTML, we will not focus on UI code mappings: these are given within that context. UI code will be
executed within the Java execution environment of the Web container using a view framework (JSP or UIX) and
controller framework. For DL code and BL code we do still have options available in terms of mappings. We will
investigate these alternatives first for each class separately and then merge them.
Mapping DL Code
There are basically three options for mapping DL code into the execution environments (see Table 2): all goes into the
middle tier, all goes into the data tier (i.e., the database-centric approach), or using certain criteria, all DL code is spread
across both tiers.
JavaScript Java in Container RDBMS
1 All
2 All
3 All/Part All/Part

Table 2. Alternative DL code Mappings


Model frameworks such as BC4J offer a rich set of possibilities to implement DL code for all business rules. As
mentioned earlier the way you do this looks a lot like this was done in Forms using pre- and post-DML triggers on base-
table blocks. There is one big difference though: it’s all Java code now, instead of PL/SQL. If you are familiar with
PL/SQL why not opt to implement all DL code inside the RDBMS? You have probably been doing this for quite some

6
UI code will typically call query composing/executing code to embed data in the user interface. UI code will typically call transaction
composing code in response to user interface events.
7
DL code for checking simple rules such as “status-code must be in (A, B, C),” or “finish date must be after start date” is often
embedded in UI code.
8
The only way to fully separate DL code from BL code is to adopt an architecture where all DL code sits in database triggers.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
time. Nowadays there are solid frameworks, such as Oracle’s RuleFrame or our homegrown RuleGen,9 that aid in
implementing DL code for all business rules inside the RDBMS. Either way, using a Java framework or a PL/SQL
framework to implement DL code, you will end up with DL code that is clearly separated from any other code (BL and
UI). During the lifecycle of the application this will turn out to be a big advantage in the area of cost for application code
management and maintenance.
One could also opt to spread DL code across two frameworks. Again, if you choose to do so make sure you first set clear
guidelines that tell your developers when to implement DL code in the Java framework, and when to do so in the
PL/SQL framework. Examples of these guidelines could be: all DL code that can be dealt with in a declarative way using
the RDBMS, is done in the RDBMS (e.g., primary/unique keys, foreign keys, check-clauses), and all DL code that
requires procedural logic and needs to be hand-coded is implemented in the Java framework. Another strategy could be
to implement all DL code that requires data retrieval (i.e., must submit Select statements to check the rule) with the
PL/SQL framework, and to implement all other DL code (that does not require data retrieval, i.e., attribute and tuple
rules) with the Java framework.
Like many subjects concerning J2EE, the subject of where to implement DL code tends to divert into a “religious”
discussion. The Object-Oriented/Java tribe won’t consider the RDBMS as an option. The Relational/PL/SQL tribe can’t
see the benefits of taking DL code out of the RDBMS (author’s strong opinion too). The RDBMS is the “final frontier”
when it comes to data integrity. Once DL code has been implemented in the RDBMS the integrity of the data inside the
tables has been secured no matter what future applications are developed against those tables.
Mapping BL Code
This one is even more religious, since the methodology used for systems development plays a big role here. When it
comes to BL code, there is a whole new wave of belief out there: “Thou shall model thou business (logic) in an OO-way
and UML is thou vehicle to do this.” And by the way, don’t bother about your data, we (UML) will derive top-down
what needs to be stored persistently. It’s beyond the goal of this article to fully explore this new belief. The author has
had encounters with a few of these new fundamentalists and much has become clear: they refuse to spend time
investigating any other approach. In short, you are either on their side of the hill or you are not. Their side seems to have
momentum in the industry and therefore is appealing. However, think twice before you decide to depart to that other
“greener” side of the hill. If you have been happy designing your applications using traditional ER diagrams, process
flow diagrams, business functions, and then down to tables and modules, by all means keep on doing so. Why change?
From the looks of it, if you are going down a (full-fledged) UML lane, two things seem to be certain: 1) your BL code is
the center of the universe instead of your persistent data, and 2) your BL code will not end up in PL/SQL. Your choice
should be really simple now— if your application is a “window-on-data” type of application (and frankly, which one is
not?), a bottom-up traditional relational design approach is the way to go.
JavaScript Java in Container RDBMS
1 All
2 All
3 All/Part All/Part

Table 3. Alternative BL Code Mappings


Under the assumption that we are still on this side of the hill, we have the same three options for BL code mappings as
we did have for DL code (see Table 3). Model frameworks such as BC4J will aid in transaction and query composition as
far as it concerns the composition of the data retrieval and manipulation code. All other procedural (hand-coded) BL
code will end up in Java classes outside (in front of) such framework. Triggered by events in the UI initiated by users, UI
code will invoke these classes. No BL code sits in the RDBMS; only straightforward SQL is submitted in this case.
Again here, if your background is Oracle why not stick to implementing BL code in PL/SQL? Two key technologies
inside Oracle will greatly aid in moving all BL code into the RDBMS: for rBL code complex views and the VPD feature
are the magic bullet, and for wBL code complex views and instead-of triggers are.

Our Database Centric Approach


Our J2EE software factory has adopted the BC4J and UIX frameworks. Currently we deploy all J2EE applications with a
custom-built controller framework. In the future however it is likely that we will adopt the Struts or ADF controller
framework. All of our J2EE applications are deployed as HTML applications running in the browser. This section
presents the database-centric approach in our J2EE software factory.

9
See: http://www.rulegen.com

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
DL Code
All business rules (data integrity rules) are implemented inside the RDBMS. Currently the DL code that checks them sits
in stored procedures, functions, and packages that are part of wBL code. However we are in the process of adopting our
RuleGen framework, which will move all DL code into/behind database triggers. Only two types of rules are allowed to
(also) be checked outside the RDBMS: attribute and tuple rules. Since these can be checked without having to execute
additional data retrieval code (i.e., without communicating with the database), they are allowed to be checked by
JavaScript in the browser too. Note that no DL code whatsoever is executed in the middle tier. Apart from the “final
frontier” argument mentioned earlier, the rationale behind this is that for DL code to validate a business rule (given a data
manipulation statement), it either has to execute additional retrieval code, or it does not. In the former case the most
efficient way to do this is from within the RDBMS. In the latter case the most user-friendly (responsive) way to do this is
in the front end (JavaScript). Ergo nothing is left for the middle tier to execute when it comes to DL code.
BL Code
All BL code is implemented inside the RDBMS. In the application code classification section we have discussed that BL
code is called by the UI code layer. There are two high level strategies to accomplish this.
• API from UI code to BL code are PL/SQL procedure calls.
In this case all BL code can sit inside the procedures that are being called by the UI code. The PL/SQL code
inside these procedures then composes the transaction or query.
• API from UI code to BL code are SQL statements.
In this case we must create a layer of views to enable us to push down as much BL code as possible into the
RDBMS. Data retrieval and manipulation takes place through these views only. The wBL code can then sit
inside instead-of insert/update/delete triggers attached to the views and rBL code is implemented by the view
definitions themselves.
We chose SQL statements to be the standard API from UI code to BL code. The main reason for this is that model
frameworks (such as BC4J) use SQL statements as the de facto way to communicate with the data tier. Procedure calls
are supported too, but they are not the standard way to communicate with the data tier.
The BL code calls that are embedded in the UI code is the only Business Logic that is left outside the RDBMS. In our
case these are the actual SQL statement texts, which represent the API call to the BL code. It is prudent to also think
about what type of SQL statements are actually allowed to be embedded in the UI code. For instance, do we allow
queries that join two objects (table or view)? Do we allow function calls inside the SELECT list of the query? Or should
all this stuff be pushed down into view definitions? In our J2EE software factory we have set the following standards for
this API:
• Queries
- Are always based on a single view (FROM-clause). All additional logic, join, sub-query, etc., sits in the view
definition.
- Only hold bare view columns in the SELECT-clause. All additional logic, built-in or custom stored function
calls to format values, sit in the view definition.
- Never have a WHERE-clause. VPD adds this dynamically.
This gives us the following template for a query that is embedded in UI code:
SELECT <bare column>, <bare column>, …
FROM <view>;

• DML statements
- Are always based on a view
- Always manipulate one-row
This gives us the templates in Listing 1 for DMLstatements that are embedded in UI code:
UPDATE <view> SET <column>=<value>, <column>=<value>, …
WHERE <primary key>=<value>;
DELETE FROM <view>
WHERE <primary key>=<value>;
INSERT INTO <view> VALUES(<value>,<value>,…);
Listing 1. Templates for DML Statements
• Instead-of triggers defined on these views are then able to interpret the single view-row DML statement and
translate this into (potentially complex) DML statements against underlying database tables.
Other than the calls to these API BL code objects, we do not allow BL code in the Java container or inside the Browser
(Javascript).

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
UI Code
As mentioned earlier, UI code will be executed within the Java execution environment of the Web container using a view
framework (for UI generation) and controller framework (for UI event handling). All this code does is generate HTML
for the browser (embedded with data retrieved from the API views). This code is kept as thin as possible: we even do not
allow field level formatting within this UI code. This should be done within the API view that services the particular
HTML page. In short, since no DL code or BL code runs in the Java container, all that is left for the Java container to
execute is this (thin) UI code.

Our Approach In More Detail


Generating where-clauses at runtime has become possible in the database server with the introduction of the VPD
feature.10 Instead of coding the Where+Order-by clauses in the BL code API statements embedded in the UI code, the
database can generate these at runtime using the VPD-accompanying feature called Application Context. This context
tells VPD in what context the application is and enables VPD to generate the necessary where-clause. Both features are
further discussed in the next section. UI code would have to transfer the application context to the database (using a
stored procedure call that is part of the BL code API too), before performing the simple “select * from <view>” (without
any Where + Order-by clauses). For those HTML pages where users are allowed to change queried data (typically the
smaller part of a Web application), we must ensure that the API view can accept single-row updates: these are update
statements with where-clauses generated by BC4J when posting changes of cached rows to the database. They are always
of the form “Where <pkcol(s)> = <pkval(s)>.” This poses a problem when using database views that, due to their
complexity, are not “updateable.” Updates to complex views cannot be computed by the Oracle server and will generate
a "ORA-01732: data manipulation operation not legal on this view". The solution for this problem is to create
instead-of-update (database) triggers on these views: they fire instead of the update-statement. These triggers should
perform all necessary Business Rules checking (DL code) and, when successful, execute the applicable DML on the
views'underlying tables (wBL code). Figure 10 shows a page network. Application context is transferred from page to
page as the user navigates through the application. Each page is based on an API view with a VPD policy attached to it
and an optional instead-of trigger.

V 4(p1)
In st e a d - o f
V PD t rig g er
Co n t e x t
Pa g e
Co n t e x t
Pa g e Co n t e x t

Co n t e x t Co n t e x t
Co n t e x t Co n t e x t Pa g e

Pa g e

Pa g e Co n t e x t
Co n t e x t V 5 (p 1 ,p 2 ,p 3
)
V PD
Pa g e

V 1 (p 1 ) V 3 ( p 1 ,p 2 )
V 2 ( p 1 ,p 2 )
V PD V PD
V PD In st e a d - o f
t r ig g er

Figure 10. Application Page Network With API Views


Virtual Private Database (VPD) / Application Context
The VPD feature, available since Oracle8i, enables us to have the server dynamically add a where-clause “predicate” to
an SQL statement. It is often referred to as the preferred mechanism to be used for implementing “row level security.”
Row level security policies may dictate that certain users may only see certain rows in a table (or view). Instead of
programming these where-clauses everywhere in application code, it is now possible to define such policy once centrally
on the database table/view. The way this is done is by a) writing a Stored PL/SQL Function whose job it is to produce a
(piece of) where-clause predicate, and b) telling Oracle that this (policy) function is to be attached to a specific
table/view. Oracle will then automatically execute the function every time it is about to execute an SQL statement that
accesses the table/view. It will first add the return value of the function to the where-clause of the SQL statement, and
then execute it. For instance, consider a row level security policy that dictates employees may only access employee
records within the same department, except for managers who are allowed to access all employee records. This would
require the policy function shown in Listing 2:
function Emp_Policy(p_schema in varchar2, p_object in varchar2) return varchar2 as
l_deptno number;

10
VPD can even be tweaked such that it will return rows in a specified order too (see next section).

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
l_job varchar2(10);
begin select e.deptno, e.job into l_deptno, l_job
from emp e
where e.login_name = USER; -- Login_name-column holds database username
if job <> 'MANAGER'
then return 'DEPTNO = '||to_char(l_deptno);
else return '';
end if;
end;
Listing 2. Management/Employee Record Access
Once this policy function is created in the DEMO schema, it can be attached (added) to the DEMO.EMP-table using the
dbms_rls (row-level-security) supplied package, as follows (see Listing 3):
exec dbms_rls.add_policy('DEMO','EMP', -- Object to add policy too
'EMP_POL', -- Name for this policy
'DEMO','EMP_POLICY', -- Policy function to add
'SELECT'); -- When to be enforced

Listing 3. Adding Policy Function


The dbms_rls package is also used to remove a policy:
exec dbms_rls.drop_policy('DEMO','EMP','EMP_POL');

Policy functions can access system variables such as USER, SYSDATE, etc, or functions like USERENV(), to
dynamically determine what the predicate to be returned should be. To further enable a policy function to dynamically
determine this return value, one can use another feature called “application context.” Application context offers a generic
way to register knowledge on what the context within the (client side) application currently is within the database
session. This is done by setting <attribute,value> pairs within a named context of the current database session. The
<attribute,value> pairs are stored inside v$context, of which each database session has its own copy. Policy functions can
read these attribute values and use them to compute the correct predicate. A (named) context must first be created using
the “create context” command. Oracle offers secure contexts by making sure <attribute,value> pairs can only be set
within a context by a given stored package (which is supplied at create context time). Note that contexts exist at the
database level and not within a specific schema. To create a context the create context system privilege is required.
Listing 4 shows the code that creates a context (specifies the package that can write the context), and the package source
itself.
create context EMP_APPLICATION using EMP_SEC;
package EMP_SEC is
procedure set_empno(p_empno in number);
end;
package body EMP_SEC is
procedure set_empno(p_empno in number) is
begin dbms_session.set_context('EMP_APPLICATION','CURRENT_EMPNO',to_char(p_empno));
end;
end;
Listing 4. Create Context
A client application can now register a current employee in the context by calling the EMP_SEC.set_empno packaged
procedure. Policy functions can read context contents in two ways: by directly selecting from v$context, or by calling the
sys_context PL/SQL built-in function.
select value into l_current_empno
from v$context
where namespace = 'EMP_APPLICATION’ and attribute = 'CURRENT_EMPNO';
Or,
l_current_empno := sys_context('EMP_APPLICATION','CURRENT_EMPNO');
VPD and application context made it very simple for our Java programmers to retrieve the data that had to be shown on a
certain UIX page. First they call a “set-context” procedure telling the database what the current application context is,
then they perform a full access of a BC4J view object (which would translate into a “select * from <view>” statement).
The policy function then makes sure only the necessary rows are returned. Figure 11 depicts these steps taking place.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
Ja v a (v i a BC4 J):
1 ) Ca l l Se t _Ct x (… );
2 ) Se l e ct * f r o m < vi e w > ;
1
7 3

O r acl e 8i
<view >
Se t _Ct x

W h e r e -cl a u se
2
4
6

v $ co n t e x t V PD
A1 v1 Po l i cy-Fu n ct i o n
A2 v2 5
A3 v3

Figure 11. VPD and Application Context at Work


A separate (PL/SQL) team would develop the (page) API views, context procedures, and policy functions, required by
our “Java-boys.” Some of the coding standards we issued were:
1. Page views should return no rows when the policy function detects that either the context is not available
(empty), or holds incorrect values. In these cases a policy function should always return a false predicate (e.g.,
WHERE 0=1).
2. All columns of page views should be of type varchar2, and every value should already be formatted in the way it
should be displayed: no additional formatting was allowed on the middle tier. UIX page bind variables would
always be of type String.
3. When pages would feature bubble-text on certain view column values (e.g., explaining a coded value), then
these too were to be supplied by additional columns in the view.
4. Page views only return columns that are to be displayed, with two exceptions: the case of a multirow page
where a row can be selected by the user and a (hidden) primary key must be communicated to the context of the
next page. And the case of a page view that is to support updates and/or deletes; these views need an explicit
primary key defined within the BC4J layer and available at runtime. In both cases such primary key columns are
then part of the page view, but possibly not shown on the UIX page (similar to hidden items in Oracle*Forms).
5. Every where-clause returned should be checked for optimal query execution.
Page views can be classified into two types: those returning a single row, and those returning multiple rows. The UIX
templates we used for multirow pages featured “clickable” column headers. A user could click on a column header to
indicate that the result set should be ordered on that column. Using VPD, the optimizer can be tricked such that the rows
are returned in a certain (requested) order (see Listing 5). Consider the Emp_Policy function again: it now retrieves a
column-name from the EMP_APPLICATION context (attribute ‘ORDERCOL’) which has been set by client-code
before issuing the query on EMP, indicating the column on which the rows should be sorted. The function now returns a
sub-query predicate that already orders the empno-values (we need a double sub-query for this).
function Emp_Policy(p_schema in varchar2, p_object in varchar2)
return varchar2 as
l_ordercol varchar2(10) := sys_context('EMP_APPLICATION','ORDERCOL');
l_empno number := to_number(sys_context('EMP_APPLICATION','CURRENT_EMPNO'));
l_deptno number;
l_job varchar2(10);
begin select e.deptno, e.job into l_deptno, l_job
from emp e
where e.empno = l_empno;
if job <> 'MANAGER'
then return
'empno in (select te.empno'||
' from (select empno'||
' from emp'||
' where deptno = '||to_char(l_deptno)||
' order by '||l_ordercol||') te'||
' )';
else return '';
end if;
end;
Listing 5. Request Sorted Results

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
A “select * from emp” including the above-generated where-clause will be optimized as follows in Listing 6 (the “in
<subquery>” translates to a nested-loop join):
>.SELECT STATEMENT
>...NESTED LOOPS -- does not disturb row order
>.....VIEW
>.......SORT order by -- will sort on requested column
>.........TABLE ACCESS by rowid emp -– retrieves order-by column value
>...........INDEX range scan emp_fk –- Uses l_deptno
>.....TABLE ACCESS by rowid emp
>.......INDEX unique scan emp_pk
Listing 6.Nested-Loop Join
The resulting rows from a nested-loop join will always be ordered by the row-order of its first row-source. In the case
above this is the order generated by the sub-sub-query. All the second row-source does is execute the IN-operator: it
sequentially retrieves single EMP-rows, given the ordered empno “stream” it receives from the sub-query.
Instead-Of Triggers On Views
With the introduction of Oracle8i, it has become possible to also create “instead-of” insert/update/delete triggers in the
database, next to the already available before/after, statement/row triggers. Instead-of triggers will fire instead of the
DML statement issued against the table. They will fire for each row affected. Contrary to the already available trigger
types, instead-of triggers can also be created on views. This greatly enhances the possibilities to use views as the
interface of choice for client-side application code communicating with the database server. These type of views, views
that retrieve data ready-for-display in the front end, typically join data from various tables, maybe also aggregate some
data, return virtual columns, etc., and very likely will have become non-updateable (i.e., generate ORA-01732 error
when updating) due to their query-complexity. Instead-of triggers solve this problem, and now make it possible to also
use these views for transacting with the database (we already used them in client/server applications for retrieving data
ready-for-display in Forms). When the view is DML-led the instead-of trigger fires and should first perform all necessary
Business Rules (Data Logic) checking and only when successful, execute the applicable DML on the view’s underlying
tables. As mentioned earlier, BC4J will generate update statements of the form:
Update <view> set <col>=<value>, …
Where <pkcol> = <pkval>

It is therefore essential that when a page view is developed for a UIX page that supports updates by the user, this view is
explicitly checked to optimally execute its query given the where-clause BC4J adds (and not only given the where-
clauses added by the VPD policy, as mentioned earlier). To prevent mixing of these (BC4J) where-clauses with our own
policy where-clauses, we standardized that VPD only adds a where-clause when SELECTing from page views. It was up
to the instead-of trigger code (before even starting with the execution of DL code or wBL code), to always first check the
row level security: is, given the application context, updating this row at all allowed or not? Figure 12 depicts the steps
taking place when BC4J updates a view with an instead-of trigger:
1) BC4J generates update statement.
2) View will retrieve affected rows (perform a select, but not update).
3) Update responsibility is handed over to instead-of-trigger. Trigger is supplied with retrieved
record(-variables).
4) Trigger will check row-level-security and/or other application-context dependant issues.
5) Trigger determines which tables to update, and does so.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
Ja va (vi a BC4 J):
1 ) U p d at e V se t c1= v1
w h e r e Pk co l = p k va l ;

O r acl e8i
2 V
T
T 3
T
v$ co n t ext
A1 v 1 5
A2 v 2 In st e ad -o f
A3 v 3
U p d at e -t r i g g e r
4

Figure 12. Instead-of Trigger at Work


There is one issue that you need to be aware of when adopting instead-of triggers to update complex views. This
concerns the row-locking strategy. Model frameworks will try to acquire a row-lock before performing the (PK-based)
DML statement. Acquiring the row-lock is done via a “select … for update” query. API views are usually so complex
that without an instead-of trigger they would not be updateable. This implies however that they cannot accept a “select …
for update” query either. Oracle will generate a “ORA-02014: cannot select FOR UPDATE from view with DISTINCT,
GROUP BY, etc.” error when attempting to do so. The solution to this issue is to configure the model framework such
that it won’t try to acquire the row-lock. BC4J supports three locking strategies: pessimistic (lock when row is touched
in the cache, just like Oracle*Forms does), optimistic (lock just before posting the DML), or none (do not acquire row-
locks). In our situation we use the “none” strategy. This implies that the instead-of trigger now has the responsibility to
acquire the row-locks to prevent waiter/blocker situations.
A nice enhancement request here would be for Oracle to implement a instead-of Select-for-Update trigger in the
RDBMS too.

Lessons Learned
Here are some of the lessons we have learned during the first few J2EE projects that we have done, using the database-
centric approach that we have described.
Do Not Trust Java Geeks
In our database-centric approach we explicitly create API views in conjunction with set-context stored procedures that
are to be used by the UI code for executing the data retrieval and manipulation (including BL+DL Code as described
earlier). Once you have set these guidelines in terms of what BL code API objects are to be used from within the UI code
(Java view+control frameworks), make sure that the Java programmers cannot access any other database objects than
these. For if you supply them with a database connection that gives them access to all other BL code objects, or all
underlying tables of the API views, you can be sure of one thing: they will start using those too. Part of our approach
now is that we create a separate database schema that holds the BL code API objects only. The Java model framework
connects to this schema, and cannot see or access any other application objects inside the database (they sit in a different
schema). We create separate development teams too: one team that develops the view+control (UI code) for the
application, and one team that develops the model (BL+DL code) for the application. The first team uses JDeveloper.
The second team still uses the Designer product. For each page of the application these two teams are forced to sit
together first and discuss the application context dimensions for that page, and the semantics of the database view that
services the data retrieval and/or manipulation for that page. Once this has been agreed upon both teams can start
development for that page independent from each other.
VPD: Hard Parses Versus Soft Parses
Consider a “display-book-details” page of an Order-Book application. The application context of this page consists of
only one attribute, say Book_Id. The API database view selects all columns of the Books table. The VPD policy function
is supposed to add a where-clause such as “WHERE Book_Id = <current book_id of the application context>.” The
policy function in Listing 7 would do this (assuming a BOOK_DETAILS context with a BOOK_ID attribute that has
been set by the UI code):
function Book_Details_Policy(p_schema in varchar2, p_object in varchar2)
return varchar2 as
l_book_id number;
begin
l_book_id = sys_context(‘BOOK_DETAILS’,’BOOK_ID’);

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
return 'Book_Id = '||to_char(l_book_id);
end;
Listing 7. Hard Parse Result
This would however cause a hard parse for every different book_id submitted, since the book_id is embedded as a literal
inside the where-clause that is generated. To prevent this the policy function should be rewritten as shown in Listing 8:
function Book_Details_Policy(p_schema in varchar2, p_object in varchar2)
return varchar2 as
begin
return 'Book_Id = sys_context(‘‘BOOK_DETAILS’’,’’BOOK_ID’’)’; -- Double quotes.
end;
Listing 8. Soft Parse Result
In this case the where-clause will be treated as if it were of the form “where book_id = :b1.” The sys_context call will
behave as if it were a bind-variable and is bound at execute time of the query. This will now cause soft parses for
different subsequent book_ids that are submitted and therefore consume significantly less CPU resources.
VPD: Policy Function Fires Twice
Some of our policy functions are quite complex, due to the nature of the API view and the required where-clause
semantics. To give you an idea here is a pattern we often use inside a policy function:
• Read all attribute values of the current application context namespace
• Truncate a global temporary table
• Execute lots of procedural PL/SQL code using above values to compute a set of primary key values
• Store these primary key values inside the global temporary table
• Return the following where-clause:
where <pk-columns of API-view> in
(select <columns>
from <temporary table>)

Filling the temporary table is CPU-intensive in this case. Once it is done, fetching the rows from the view (by UI code)
requires little CPU. This worked fine for us in Oracle8i. However the introduction of Oracle9i has changed the execution
model of VPD policy functions. A policy function now fires twice for every query that is submitted: once during the
parse phase (irrespective of whether this is a hard or a soft parse), and once during the execute phase. Given the CPU-
intensive policy function this has meant that the migration to Oracle9i has caused a near doubling of the CPU usage for
these pages. We have opened a TAR for this on Metalink but to no avail: this is documented behavior (in fact Oracle
states that the once-only firing of the policy function in Oracle8i was a bug). We are in the process of rewriting these
CPU-intensive policy functions so that they detect whether the contents of the temporary table are already OK, and if so
do not execute the procedural PL/SQL code a second time.
Sorting Via VPD: A Bridge Too Far
The double sub-query trick we explained earlier to mandate a certain order in the rows retrieved by the API view works
fine as long as the view involved is simple. Getting this trick to work for more complex views turned out to be rather
difficult. Currently we do not use this trick anymore. Using BC4J, the order-by clause is added to the “select * from
<API view>” query. This can easily be coded as part of the embedded BL code call inside the UI code as follows in
Listing 9:
ViewObject vo = am.findViewObject("VBOOKHITS");
Vo.setorderbyclause(‘author’);
RowSet rowSet = vo.getRowSet();
Row r = null;
while (rowSet.hasNext()) {
r = rowSet.next();
// processing here…}
Listing 9.Order by Author Query
Instead of sending a “select * from <view>” statement to the RDBMS, this code will send a “select * from <view> order
by author” query to the RDBMS. VPD will still insert the necessary where-clause.

Conclusion
This article assumes you are an Oracle PL/SQL shop. If you are, then coding all Data Logic and Business Logic Code in
PL/SQL will enable you to considerably reduce the risk in your (first) J2EE project. We are not saying that it will be easy
though. On the contrary, there is still a whole new world for you to discover and adopt. Approaching this in a database-
centric way however, will enable you to not make it more complex than it needs to be.
For us this approach has meant that only few developers needed to learn the new IDE including all the technology
aspects surrounding it. Since the new Java IDE is only used to build UI code, we were able to specify a finite number of

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.
UI patterns (page types) that enable us to build almost any browser (HTML) application. Each pattern is supported by a
super class that already implements the bulk of the job necessary for that pattern. In this way we even further simplified
the work that had to be done in the new Java IDE. Right now the majority11 of time spent on a J2EE project within our
company involves the good old PL/SQL and SQL languages. This has benefits in many areas. For instance scalability
and tuning issues do not play at the OC4J level, but at the well-known RDBMS level: we do not know how to perform
tuning of memory, CPU usage, and contention in an OC4J instance. In our database centric approach the container has
hardly any work to do.
The biggest benefit of the database-centric approach can be found in the Total Cost of Ownership (TCO) of the J2EE
application. History has taught us that 20 percent or less of the TCO of any software application lies in the initial creation
of the application. The bulk, 80 percent or more, of the TCO lies in the run and maintenance phase of the application.
Being an Oracle PL/SQL shop, you will experience big benefits in maintaining a J2EE application that was built in a
database-centric way versus maintaining one that was not.
The database-centric approach will also work for application development that does not involve J2EE. Given the
architecture of the DL+BL code including the API layer that we have defined, we can fairly easily change to other client
tools (ask yourself, “Is J2EE here to stay?”). All such client development tools have to support is being able to call a
stored procedure (to set context) prior to doing a select (from the API view). And for the data manipulation part, all the
tool has to support is generating single row (PK-based) DML statements.
Ask yourself, “Is PL/SQL here to stay?”

Bibliography –L1
[Kopp-2003] Business Rules: Theory and Implementation (What and How). Proceedings of the Business Rules
Symposium ODTUG-2003, Miami (also available at http://web.inter.nl.net/users/T.Koppelaars).

! "
# $%& ' ( ') *
' + # , , or
, .

11
On average two-thirds of the build effort is done in the familiar PL/SQL and SQL environments and one-third in JDeveloper/Java.
After go-live, the run and maintenance effort shows a distribution that shifts even more in favor of a PL/SQL and SQL programming
effort.

Reprinted by permission of Oracle Development Tools Users Group (ODTUG)


Copyright 2004 ODTUG. All Rights Reserved.

Das könnte Ihnen auch gefallen