- South Bay Cluster Association

advertisement
APEX: LESSONS FROM THE TRENCHES
Bill Holtzman, National Air Traffic Controllers Association
I. Introduction
Large organizations can afford custom internet applications to streamline and accelerate business processes. Smaller
organizations often can’t. My organization, the National Air Traffic Controllers Association (NATCA), solicited estimates
from several vendors for both custom and off-the-shelf products to track labor grievances, but the organization ultimately
squawked at the price. We turned to Application Express.
ApEx has very low barriers to entry but the ability to move to high levels of sophistication. With just a modest education in
SQL, PLSQL, and HTML we found we could use it to build applications ourselves. We can modify, improve, and streamline
the system with feedback from the entire user base without calling a vendor nor, more importantly, getting a bill for the work.
We have constructed and deployed many other smaller applications, some in just hours, and can build any other application
we need at no cost. The value Application Express brings to our smaller organization is tremendous, and more so with the
power of Oracle behind it.
II. Outline
The grievance
The National Air Traffic Controllers Association represents 15,000 members in 400 locations ranging from Pago Pago to
Anchorage to San Juan. Members work for the Federal Aviation Administration (FAA), an agency of the US Government.
NATCA’s bread-and-butter is the filing of labor grievances, written complaints concerning working conditions and violations
of regulations. A typical grievance may describe an incident in which an employee’s rights were ignored, or it may involve a
situation where a management decision had an adverse affect on an employee. The processing of grievances follows a strict
procedural path governed by a contract negotiated between the FAA and NATCA. This process is subject to change.
The NATCA grievance application
The NATCA Grievance Automated Tracking System, or “GATS”, has been deployed nationally since September 2006, the
current grievance count is about 200,000. GATS has been evolving for over three years, enduring sea changes in the business
environment and emerging with ever-increasing capabilities and performance.
A team of six gathers feedback continuously from users and determines development priorities. By doing this in-house, we
avoid the costly use of contractor time, acquire important organizational knowledge about administering IT systems, and
provide a highly tailored and responsive application for our over-worked local representatives.
Summary of techniques
This paper will cover the following topics:

Report regions – ride the learning curve
o
o
o
Wizards

Application wizard

Simple report wizard
SQL report region

Concatenated fields with plain text, links and images

Embedded conditional links and images
SQL report region generated by PLSQL
www.odtug.com

Custom sorting through PLSQL

Enhanced performance
ODTUG 2007
ApEx Lessons from the Trenches




Holtzman
2
Techniques with Javascript
o
Adding an OnSelect function to a drop-down
o
Generating database-driven Javascript with PLSQL
File storage using custom tables
o
Constructing the tables and procedures
o
Upload and download pages
Security
o
Session state protection - use of checksums in SQL Report Regions
o
Use of branching to enforce security
o
Application level items
Other techniques
III. Technical discussion
Report Regions – Ride the Learning Curve
Wizards
The beginning user can get going with ApEx using MS Access-like wizards that require virtually no knowledge of
programming languages. The ApEx Quick Tour demonstrates this, creating a spreadsheet-based web application in just one
minute! The Quick Tour can be found on Oracle’s web site at:
http://www.oracle.com/technology/products/database/application_express/html/getting_started.html
By watching this short viewlet a complete novice – say, Developer A –
can build and deploy a basic web application. The “Create Application
from Spreadsheet” wizard (image at right) that is demonstrated will
create a report region within the app in which the spreadsheet data is
presented to the web user. This is the easiest, most basic use of ApEx –
Developer A is not necessarily even aware that a report region has been
created.
Developer B may have already created an app and want to add a report region. Developer B can use the report region wizard
to build a more customized report containing selected columns from a single table.
Developer C may be more ambitious and want to create a report region using data from more than one table. Developer C
uses the SQL Report wizard and the Query Builder (see Figure 1) to select columns from several tables. The Query Builder
requires the developer to simply click on the tables and then check the desired columns, and then generates the appropriate
SQL including column references and joins. As a result, even Developer C needs absolutely no knowledge of SQL.
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
3
Figure 1: Graphical Query Builder enables non-programmers to build SQL
Even Developer D, who is building a report region that shows only those columns selected by the user, does not need any
programming knowledge. In order to give the user control, Developer D creates check boxes on the page using a static list of
values and then drills down into the Report Attributes area of the region and put conditions on the display of the subject
column using the “Item not null” selection in the Condition Type. Developer D can also drill down into the Column
Attributes page of a particular column and change the display of that column. This might include re-formatting, replacing the
column value with a selection from a List of Values, or making the column a link to another page.
This process could continue for quite a while, with a completely unskilled programmer learning to build more and more
capable web applications without knowing how to write a single line of SQL or PLSQL. The capability of ApEx to
accommodate the inexperienced lowers the barriers to entry for this technology and brings the world of web application
development to an enormous audience in much the same way that MS Access did with desktop computing.
Many users of MS Access found they needed the flexibility of adding their own code. They were able to do so piecemeal, and
in so doing were able to gradually work their way up to actual programming. In exactly the same way, the novice ApEx
developer will realize the limitations of relying on wizards. They will learn SQL and PLSQL, incorporate them into
applications and become real programmers!
SQL Report Region
With knowledge of SQL, the ApEx developer can use the wizard to create SQL Report Regions. In
these regions the developer specifies the query and appropriate joins and conditions. The developer
at this level has more options and flexibility in terms of presentation because the formatting, value
substitution, links, etc. can be coded directly and concatenated. The following code is an example.
The resulting display is shown at the right.
select
'<a href="f?p=&APP_ID.:8:' || :APP_SESSION ||
':::8:P8_DUP_GRID,P8_RETURN_PAGE,P8_ARTICLE:' || g.grid || ',32,' ||g.article ||
'">' || g.natca || '</a><br><span style="font-size:8pt">' || g.faanum ||
'</span>' "NATCA/FAA<br>(Copy)"
from grievance g
The automated column link feature could not generate this display because it involves two concatenated strings where one is
a link and one is not. In addition, the link includes five parameters and the automated column link can only accommodate
three. This is just one example of the flexibility gained by manual coding.
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
4
Another is the inclusion of a link such as the following to provide the user with a pop-up
window including database-driven reports or text, where parameter values must be passed into
the target page. The appearance of the column is shown at right.
'<a href="javascript:myPopUp(''f?p=&APP_ID.:9:' || :APP_SESSION ||
'::::P9_GRID:' || g.GRID || ''')" &F168_PRINT.>' || g.topic || '</a>' "Topic"
The SQL Query creates a link and the resultant HTML - as generated by ApEx at runtime and
sent to the user’s browser - looks like this:
<a href="javascript:myPopUp('f?p=104:9:11001668615862681378::::P9_GRID:5581')" onMouseOver="return
window.status='View this grievance for printing'" onMouseOut="return window.status=''">Article 34
Working Hours</a>
Note that the application variable &F168_PRINT. is set to the following:
onMouseOver="return window.status=''View this grievance for printing''" onMouseOut="return
window.status=''''"
causing the text “View this grievance for printing” to appear in the status area of the browser instead of the actual link.
Yet another technique involves the use of decode or case statements within your SQL to produce a
display involving different fields of data. At the left is the display that results from the following multiconditional code:
select
decode(g.status_id, 1, decode(g.date_sub_2, null, trunc(g.u_action_2) - trunc(sysdate)
|| '&nbsp' ||
case
when (g.u_action_2 - sysdate) > 7 then '<img src="#FLOW_IMAGES#greenN.gif" alt="NATCA
must submit this by ' || to_char(g.u_action_2, 'MM/DD/YY') || '">'
when (g.u_action_2 - sysdate) > 3 then '<img src="#FLOW_IMAGES#yellowN.gif" alt="NATCA
must submit this by ' || to_char(g.u_action_2, 'MM/DD/YY') || '">'
when (g.u_action_2 - sysdate) > 0 then '<img src="#FLOW_IMAGES#redN.gif" alt="NATCA must
submit this by ' || to_char(g.u_action_2, 'MM/DD/YY') || '">'
when g.u_action_2 is null and date_rec_1 is null then '<img
src="#FLOW_IMAGES#greenN.gif" alt="FAA has not replied at the E1 level">'
else '<img src="#FLOW_IMAGES#past.gif" border="0" alt="NATCA failed to submit this by '
|| to_char(g.u_action_2, 'MM/DD/YY') || '">'
end,
to_char(g.date_sub_2, 'MM/DD/YY')), 'Closed') "DATE_SUB"
from grievance g
The use of conditions within the SQL allows the developer complete flexibility in the resulting display within the column,
including data type, images, and concatenation. By making full use of this capability, the developer can provide users with
highly customized displays that present information in the most readily graspable form.
A complication of using this approach is that you cannot allow the user to sort on columns such as these since the sorting is
complex. The only way to provide the user with sorting options on columns such as this is to take the next step in the ApEx
learning curve.
SQL Report Region generated by PLSQL
Converting your Report Region up from a straight SQL Query to a
query generated by PLSQL starts with changing the type of the
Report Region as shown at right. The rest of it isn’t quite as easy!
In this region, your PLSQL code generates a SQL query. Here is a
simple version of this:
declare
p_sql varchar2(32767);
begin
p_sql := q'! select grid from grievance !';
return p_sql;
end;
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
5
This uses 10G quoting syntax to enclose the query text. A more advanced example of this including some of the query
columns previously mentioned is shown here. Note that the use of the colon to reference page and application items and also
as a delimiter in the URL must be handled via substitution after the SQL string is created.
declare
p_sql varchar2(32767);
begin
p_sql := q'! select g.GRID, !';
p_sql := p_sql || q'! '<a href="javascript$myPopUp(''f?p=&APP_ID.$9$' || $APP_SESSION ||
'$$$$P9_GRID$' || g.GRID || ''')" &F168_PRINT.>' || g.topic || '</a>' || gr_groupid(g.grid) "Topic",
!';
p_sql := p_sql || q'! '<a href="f?p=&APP_ID.$8$' || $APP_SESSION ||
'$$$8$P8_DUP_GRID,P8_RETURN_PAGE,P8_ARTICLE$' || g.grid || ',35,' ||g.article || '" ' ||
gr_status_area('Duplicate this grievance') || '>' || g.natca || '</a><br><span style="fontsize$8pt">' || g.faanum || '</span>' "NATCA2", !';
p_sql := p_sql || q'! from GRIEVANCE g, gr_status_lookup p, gr_bu b where g.gr_status = 3 and
g.status_id = p.id and g.bu_id = b.id (+) !';
if :P35_FAANUM is not null then
p_sql := p_sql || q'! and lower(g.faanum) like '%'||lower($P35_FAANUM)||'%' !';
end if;
case
when :P35_SORT = 1 then p_sql := p_sql || q'! order by trunc(g.reply_by_3), trunc(g.date_sub_3) nulls
last, trunc(g.u_action_3) nulls last, substr(g.natca,4,3), g.natcasub !';
when :P35_SORT = 2 then p_sql := p_sql || q'! order by trunc(g.date_sub_3), trunc(g.u_action_3) nulls
last, trunc(g.reply_by_3), substr(g.natca,4,3), g.natcasub !';
when :P35_SORT = 3 then p_sql := p_sql || q'! order by substr(g.natca,1,2), substr(g.natca,4,3),
natcasub !';
else null;
end case;
return replace(p_sql,'$',':');
end;
A simpler SQL Report Region would be unable to sort by complex concatenated fields but by using PLSQL to generate the
SQL, custom sorting is now provided to the user via a drop-down item called P35_SORT.
The use of PLSQL also reduces the length of the resulting SQL. In the example above, if the user has left :P35_FAANUM
empty, the generated SQL does not include any WHERE clause for that field, and this improves performance. This granular
control over the SQL is essential to performance when the tables grow to production levels.
Techniques with Javascript
Adding an OnSelect function to a drop-down
Let’s say you’d like some Javascript to execute when the user makes a selection from a drop-down. For instance, in the
image to the right, the Grievant field is a text field into which the user can type anything, but you’d like to give the user the
option of selecting from the drop down and then have that selection automatically entered into the Grievant field.
The Javascript for this is very simple:
function pickGrievant(p_grievant)
{
document.getElementById("P8_GRIEVANT").value =
p_grievant;
}
This code goes in the HTML Header you access via the “Edit
Attributes” button on the Page Definition.
To call this function, insert your code as shown in Figure 2, the Element section of your Page Item.
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
6
Figure 2: Calling Javascript from a Select List.
Generating database-driven Javascript with PLSQL
A more challenging use of Javascript involves the generation of the Javascript function using PLSQL code. This is similar to
the generation of an SQL Report Region with PLSQL. We are seeking a way to dynamically generate Javascript to
incorporate stored data into Javascript functions.
Users of the NATCA Grievance Program needed a way to insert “boilerplate” text into their grievance at the click of a
button. The contents of this text varied however, depending on the selected bargaining unit (work group). In addition,
officials wanted the ability to change those text options themselves periodically through the application. One way to
accomplish this was to use PLSQL to write the Javascript every time a session is initiated.
The table containing the work text has two fields, one to identify the bargaining unit (BU_ID) and one containing the
boilerplate text (BPLATE). The following PLSQL is contained in a process on the login page that executes after authentication
of the user is complete.
declare
p_java varchar2(4000);
cursor c1 is select bu_id, bplate from gr_bu;
begin
p_java := 'function insertBP(p_region_id)
{
var p_bu_id = document.getElementById("P8_BU_ID").value;';
for a1 in c1 loop
p_java := p_java || chr(10) || 'if (p_bu_id == ' || a1.bu_id || ')' || chr(10) ||
'document.getElementById("P8_BPLATE").value = "' || a1.bplate || '";';
end loop;
p_java := p_java || chr(10) || '}';
:F168_BPLATE_JAVA := p_java;
end;
This PLSQL creates a string of text containing the Javascript function and sets the application item F168_BPLATE_JAVA to this
value. That string is then inserted into the page by a simple entry in the HTML Header of the page as shown in Figure 3
below.
Figure 3: Inserting PLSQL-generated Javascript into the HTML Header of a page.
When the page is generated, the result looks something like this:
function insertBP(p_region_id)
{
var p_bu_id = document.getElementById("P8_BU_ID").value;
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
7
if (p_bu_id == 12)
document.getElementById("P8_BPLATE").value = "This grievance is filed pursuant to the Interim
agreements and 5 USC 7103 (a) (9). The Agency's actions constitute a violation of the Interim
agreements between NATCA and the FAA, 5 USC Chapter 71, and all applicable laws, rules, regulations,
and past practice. NOTE: Under protest, and as ordered by FAA management, this grievance is filed in
accordance with the Imposed Working Rules (IWR).";
if (p_bu_id == 13)
document.getElementById("P8_BPLATE").value = "This grievance is filed pursuant to the Interim
agreements and 5 USC 7103 (a) (9). The Agency's actions constitute a violation of the Interim
agreements between NATCA and the FAA, 5 USC Chapter 71, and all applicable laws, rules, regulations,
and past practice. ";
}
The user interface is shown in Figure 4. The Select List page item on the right is P8_BU_ID. The user selects a BU (bargaining
unit) and then clicks the Insert button to insert the appropriate boilerplate for that BU. The user then has the option of
modifying the boilerplate to suit their needs. The Javascript could be triggered by a change in the drop-down, but in the
actual application there are other parameters as well.
Figure 4: Execution of PLSQL-generated Javascript by the user.
File storage using custom tables
Constructing the tables and procedures
Page items of type “Browse” can be used to easily and automatically upload user files to the database. This item will provide
the user with the ability to browse their local drives for a file. When the page is submitted, the file will automatically be
uploaded to a default table that you can access through the view wwv_flow_files. This generic storage is not ideal; to better
organize and streamline your database, you’ll want to store uploads in a custom table. For reference, see “How to Upload and
Download Files in an Application” on OTN.
Figure 6 shows one of the custom tables used in the NATCA Grievance Program.
Figure 5: Custom table for storing file properties table (on the left) and the uploaded files (on the right)
Having separate tables for the properties and the actual files simplifies some of the SQL and may enhance performance. In
the How-To, the primary key generated by the default table is used in the custom table, but this is a very long number and it’s
much easier to create and work with your own primary key.
As specified in the How-To, it’s necessary to create a procedure to download from your custom tables. Once you’ve done
that, it’s important to remember to grant the privilege of using that procedure to your users.
SQL> grant execute on download_my_file to public
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
8
Upload/Download from Custom Tables
Once you’ve created the tables and procedure, you can construct a page such as that shown in Figure 6 to perform both
uploads and downloads.
Figure 6: Upload/download page
When a file is specified on the right and the upload button pressed, ApEx automatically uploads the file to the
wwv_flow_files view. A process on the page then retrieves it from that location, copies it into the custom storage table,
makes an entry into the properties table with the associated data, and then deletes it from the generic table. The code looks
something like this:
insert into blob_store (blob_content, mime_type)
select blob_content, mime_type
from htmldb_application_files where name = :P2_FILE_NAME returning blid into p_blid;
insert into gr_blob_intersect (blid, blob_name, blob_descr, blob_category, userid, load_date)
select p_blid, the_name, the_descr, :P53_CATEGORY, the_user, sysdate from wwv_flow_files where name =
:P2_FILE_NAME and dbms_lob.getlength(blob_content)!=0;
delete from wwv_flow_files where name = :P2_FILE_NAME;
On the left side of Figure 6, the user can download files from your custom table. This capability is created by an automated
column link in an SQL Report Region as shown in Figure 7.
Figure 7: Creating a link for users to download files from a custom table (the image is modified)
Parameters within the download procedure allow you to specify whether you want the file to open in-line with the application
or in a separate window.
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
9
Security
Session state protection - use of checksums in SQL Report Regions
Without efficient and strong security ApEx would be worthless. Since parameter values are often passed via the URL, it is
essential to prevent users from tampering with the URL and thus accessing data that would otherwise be inaccessible.
The built-in session state protection feature adds a checksum to every URL generated based on the URL itself, much like a
“check digit” within a credit card number. If you accidentally provide or enter an incorrect credit card number, nine times out
of ten the number itself will not be valid because the check digit is the product of a formula based on the other digits.
The checksum in ApEx is obviously much stronger protection, containing 30 or so characters, as shown.
http://www.abc.net/pls/htmldb/f?p=168:34:470931357178041727::NO:::&cs=3A70EA7DD614FA61411D4DCACB75E481C
Enabling session state protection is as easy as a few clicks.
Figure 8: Enabling session state protection.
With session state protection enabled, ApEx will append a checksum to any auto-generated URL such as a column link. But
if you’ve used some of the techniques mentioned earlier in this article, such as creating manual links within an SQL Report
Region, you will need to invoke the checksum procedure manually. One of the manual links shown earlier looked like this:
'<a href="javascript:myPopUp(''f?p=&APP_ID.:9:' || :APP_SESSION || '::::P9_GRID:' || g.GRID || ''')"
&F168_PRINT.>' || g.topic || '</a>' "Topic"
The checksum procedure is HTMLDB_UTIL.PREPARE_URL. This procedure accepts the text URL as a single IN parameter,
calculates a checksum based on the string, and returns the input URL with the checksum appended. The following shows
how it would be incorporated here:
'<a href="javascript:myPopUp(''' || htmldb_util.prepare_URL('f?p=&APP_ID.:9:' || :APP_SESSION ||
'::::P9_GRID:' || g.GRID) || ''')" &F168_PRINT.>' || g.topic || '</a>' "Topic"
All that has changed is that the entire URL is now a variable, and the checksum procedure operates on that variable. The
same method can be used in a PLSQL (anonymous block) Region to manually create a secure link within your app:
htp.p('<center>Want to know more?<br><a href="javascript:trainingPopUp(''' ||
htmldb_util.prepare_url('f?p=&APP_ID.:2:&APP_SESSION.::::P2_OPTION:8') || ''')">Click
here</a></center>');
Use of branching to enforce security
An issue with the above is that the HTMLDB_UTIL.PREPARE_URL procedure can be a real drag on performance when the number
of rows gets into five digits and more. There’s more than one way to skin the cat, of course, and the use of conditional
branching will also provide protection against URL tampering.
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
10
Figure 9: Using conditional branching to enforce data security.
This method is fairly simple in that you create a branch on the target page that fires before loading. Then you simply make
the condition one that evaluates your user’s access rights reference the requested information. If the conditions indicate the
user is not entitled to see that information, then the user is sent to an “access denied” page advising that. In Figure 9, if the
user and primary key fails the security function GR_ACCESS, then the user will be sent to page 20. A notice will appear on that
page that references the activity that caused the denial of access (based on the hidden variable P20_FLIP). Page level security
could accomplish the same thing but provides the user with only a very generic error page and not as much control over the
process.
Application level items
The session value of an application level item is stored in session state and the item itself is never associated directly with an
input item on a page. Since they cannot be assigned a value through the URL, application level items are less subject to
tampering than page items. While the name of a page item will appear in the raw HTML for that page, the user most likely
has no way of even knowing the name of your application level items.
Using application level items is easy. You can create them in the Application Builder. The default format for page level item
names is PXX_ITEM, where XX is the page number, but for application level items it is FXXX_ITEM where XXX is the APP_ID.
In the NATCA grievance program, the header of each page looks like this:
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
11
The text “RVP Level” and “Washington Center: ATC” are both rendered from an application level item whose value is
assigned in the following process on the login page that fires after the login is completed.
declare
p_sec_lev number(3);
p_region_id number(3);
p_facility varchar2(70);
p_facid varchar2(10);
begin
select sec_lev into p_sec_lev from gr_emp where upper(username) = :APP_USER;
select r.facility into p_facility from gr_facility_lookup r, gr_emp g where upper(g.username) =
:APP_USER and r.id = g.facility_id;
select r.region_id into p_region_id from gr_facility_lookup r, gr_emp g where upper(g.username) =
:APP_USER and r.id = g.facility_id;
:F134_USER_FAC_NAME := p_facility;
select f.facid into p_facid from gr_facility_lookup f, gr_emp g
where g.username = lower(:APP_USER) and f.id = g.facility_id;
:F134_USER_FACID := p_facid;
:F134_HEADER := 'Grievance Tracking: ';
case
when p_sec_lev = 0 then
:F134_HEADER := :F134_HEADER || 'Area Rep Level';
when p_sec_lev = 1 then
:F134_HEADER := :F134_HEADER || 'FacRep Level';
when p_sec_lev = 2 then
:F134_HEADER := :F134_HEADER || 'RVP Level';
when p_sec_lev = 3 then
:F134_HEADER := :F134_HEADER || 'National Level';
else
null;
end case;
end;
Then it’s just a simple matter of referencing those application level items in the page template to display their values on the
top of every page.
Figure 10: Referencing application level items in the page template.
Other techniques
The built-in tools for monitoring developer and user activity are great, especially the
“Recent Page Views” option. This provides you with a detailed listing of every
single page view generated. I often found I wanted to filter these results in ways that
were not directly available, such as screening out my own page views. Fortunately,
you get direct access to this data via the HTMLDB_ACTIVITY_LOG view, and this
provides even more detail.
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
12
In the SQL Command Processor, the following SQL will give the result shown in Figure 11.
select * from htmldb_activity_log
Figure 11: Result set when querying the HTMLDB_ACTIVITY_LOG view.
From here you can modify your select statement to provide any specific information you need.
Another technique I found very useful was to build in e-mail processes to alert the developer to system anomalies and events.
I built a process on the login page to e-mail me whenever a login attempt failed. When I got a string of a dozen or so of these
for the same username, I knew someone was going to be unhappy and contacting me soon. I usually beat them to the punch
and defused what might have become an issue. I considered having the process e-mail the user directly with their password
but decided that might be too aggressive and insecure.
A final technique I took full advantage of was to build a message board directly into the application. When the system
deployed nationally I was constantly bombarded with questions, since I was not only the sole architect and developer but also
the marketing, training, and support departments. Keeping the user manuals was a huge chore because of all of the
development I was doing, and of course even if I kept them updated there is no guarantee they would be used.
Having to answer the same question over and over was clearly a
ridiculous inefficiency, and so I sought to store the Q&A in a
searchable knowledge base. Fortunately, I had already built a message
board application for another project. I found it was fairly painless to
import another instance of this application and then integrate its
authentication with the grievance program.
The trick to this is to use the same authentication scheme in each app,
and edit each scheme to contain the same text string in the “Cookie
Name” field. This enables ApEx to pass the cookie between the apps
and save the user from having to login to each, making the use of
separate applications almost invisible to the user.
By having a built-in message board, users could ask questions from directly inside the application, and this appeased their
need to “vent” promptly and also insured that their experience was fresh in their mind when they described it. When I
responded, everyone could share in that. The information I provided was then kept in the database and easily searchable. The
message board is shown in Figure 12.
Figure 12: Internal message board / searchable knowledge base
www.odtug.com
ODTUG 2007
ApEx Lessons from the Trenches
Holtzman
13
IV. Conclusion
In this paper, we looked at the various techniques for working in ApEx. We reviewed the use of concatenated
text/link/images in SQL Report Regions, and the use of PLSQL-generated SQL Report Regions to add more conditional
display control, enhanced performance, and complex sorting ability. The use of custom tables for storing file uploads was
presented along with the reasons why this is superior to the default storage. Methods were presented to enable developers to
add Javascript functions to their page items as well as insert database-driven Javascript into select pages. Three different
methods for adding security into applications were presented, including the use of session state protection with both
automated and non-automated tools, the use of conditional branching, and the use of application level items.
One purpose of this paper was to demonstrate the versatility of Application Express in the following context:





broad skill range
low entry barriers
comfortable avenues for moving up in sophistication
built for rapid application development
highly secure and totally web-based
ApEx is a powerful, versatile and convenient tool, and developers with just modest experience in SQL and PLSQL can really
get going in a hurry. Skills in Javascript and HTML are a big plus and will help the developer create a very comfortable
interface for the user. This paper is intended to give developers the benefit of practical experience with ApEx and give them a
leg up in the learning process.
Thank you very much. You can contact me at skyworker@comcast.net or 703-403-0139.
www.odtug.com
ODTUG 2007
Download