The Trials and Tribulations
of Making a Nontrivial JavaBean Work with Forms
Introduction
When building production systems, is not unusual to want to provide
functionality in Oracle Forms Developer that goes beyond what is built into the
tool. In order to support these extensions, Oracle provided various solutions:
·
VBX support was buggy and reliable only
for superficial extensions to the product. Significant extensions ran into severe
difficulties and eventually this functionality was abandoned
·
OCX
support promised to fix all of the VBX issues, but it had the same kind of
rough implementation problems as VBX.
·
Calling C
programs through the FFI package was reliable but difficult to use.
·
JavaBean support
was eventually provided but developers were wary of this functionality until some
successful usages had been documented.
Because of some specific project requirements, it was necessary
to make a JavaBean work to support local printing on a label printer in Forms
6i deployed over the Web. We needed to provide the capability for the form to
write a file on the client machine.
The difficulty encountered involved getting around security
issues that would enable a web-based form to access a local client machine. This
problem was compounded by the client running software that made it difficult to
upgrade. The development environment being worked in consisted of the following:
·
Database and Application server: Solaris
·
Forms 6i
·
JDK 1.3.1
·
JInitiator 1.1
·
Apps server 11.5.7
Ultimately, we were able to convince the client to upgrade the
JInitiator to 1.3.1, which made the task somewhat easier.
This paper will discuss some of the difficulties encountered in
providing the desired functionality for our client and the solutions used.
Embedding Java Beans into Oracle Forms Developer
Oracle Forms Developer supports the embedding of a JavaBean
either in an item specifically built for this purpose or as part of a text
item.
The steps to insert a JavaBean in a form are as follows:
1.
Create a new item in a control block, set its Item Type to “BeanArea.”
2.
Add your JavaBean name to the Implementation Class property. Be sure to use a fully qualified
name (such as oracle.forms.ClientWrite), but do not add any file extension.
3.
The property Visible
should be set to “Yes.” (You can set the size of the JavaBean area to 1 pixel,
so that it will be less obvious)
4.
The Canvas should be the one that is active when the
JavaBean is called.
5.
On a WHEN-BUTTON-PRESSED or any other trigger code, add
the following command to send
set_custom_property(
'CONTROL.CLIENTREQUESTBEANITEM', --Forms name of the JBean Item
1, --record number
'writefile', --parameter as defined in
the JBean (case sensitive)
:CONTROL.FILENAME ||'|'||:CONTROL.JOBIDTAG);
--text that has to be passed to the JBean
6.
If you need to receive
Building the JavaBean
A JavaBean was created to write the desired text (:CONTROL.JOBIDTAG)
into the specified file (:CONTROL.FILENAME). Next, a container/wrapper for the
JavaBean was added. Each of the successive steps is described in this section
and the relevant code is listed after each step.
1.
Add the WebForms specific and other required java libraries
to your JavaBean wrapper:
import oracle.forms.ui.*;
import oracle.forms.handler.IHandler;
import oracle.forms.properties.ID;
import java.awt.*;
import java.io.*;
import java.lang.*;
2.
Have your container class extend VBean. A VBean class
file is provided as part of the WebForms product package.
public class ClientWrite
extends VBean {
3.
Implement your event listeners. Register your
user-defined properties. Those properties are then accessible in the form,
using those same names.
private String filename= new String ("");
private static final ID WRITEFILE =
ID.registerProperty("writefile");
private IHandler myIHandler;
public String fileContents = new String(""); //This is
a plug for the Form TextArea
public ClientWrite()
{
super();
System.out.println("in ClientWrite ");
}
4.
Set the properties on the handler that is passed into
the init() method.
public boolean
setProperty(int pid, Object value)
{
return true;
}
public boolean
setProperty(ID pid, Object value)
{
5.
Implement handlers to handle any events that will be
received from the form.
if(pid ==WRITEFILE)
{
try
{
//Split string into
two parts
int v =
((String)value).indexOf("|");
filename =
((String)value).substring(0,v);
fileContents =
((String)value).substring(v+1);
//Set values
File inputFile =
new File((String)filename);
FileWriter in = new
FileWriter(inputFile);
String text1 = new
String((String)fileContents);
int length1 =
text1.length();
char c[] = new
char[(int)length1];
char c1[]= new
char[(int)length1*2];
text1.getChars(0,length1,c,0);
int j=0;
String s1=
System.getProperty("line.separator");
for(int i=0;i<length1;i++)
{
if ((int)c[i]==10)
{
s1.getChars(0,s1.length(),c1,j);
j=j+s1.length();
}
else
c1[j++]=c[i];
}
in.write(c1,0,j);
in.flush();
in.close();
}
catch(Exception e)
{
System.out.println("Error in PJC " );
e.printStackTrace();
return false;
}
}
return true;
}
public void destroy() {}
public Object getProperty(ID propertyId)
{
return null;
}
public void init(IHandler
myIHandler)
{
super.init(myIHandler);
}
}
Compiling the JavaBean
Use the following steps to compile the JavaBean.
1.
Select a working directory for compiling and jarring
the JavaBean. Copy the .java file in the directory and change to this directory.
2.
Check that the Java version is correct in this
directory:
Java –version (should return java 1.3.1)
3.
Compile the JavaBean.
Javac
ClientWrite.java (should create ClientWrite.class)
4.
Pack the JavaBean in a jar file.
Jar –cvf ClientWrite.jar ClientWrite.class (should create
ClientWrite.jar)
Security Considerations
In a client/server environment, it was possible to write files on
the server by using the package UTL_FILE in database procedures, and also write
files on the client machine by using the TEXT_IO Forms built-in. When the forms
were deployed on the web, a new layer was added. The UTL_FILE still writes
files to the database server, but the TEXT_IO writes files to the application
server. There was no built-in way of handling files on the client machine. In
2003, Oracle released the WebUtil package to handle all of these issues in
Oracle9iAS Forms Applications. However, there are still a number of Oracle
installations built using Forms 6i and deployed to the web that must use a
custom-built solution.
There are many Oracle clients who acquired Oracle Developer 6i
along with Oracle Applications. They ported the applications to the web and have
been successfully using them for years. For these organizations, it is not
worthwhile to contemplate costly migrations to a new version of Forms or to
develop new applications. However, sometimes it is necessary to add new
functionality. In the case described in this paper, the new functionality was a
label printer attached to the client computers. The label printer needed a file
sent through the serial port. This could work if the file was written on the
client machine.
The security problems arose from the fact that the browser needs to
control the files on the client computer. This situation would not work over the
Internet. Any browser requires some sort of identification before allowing this
operation. The identification comes from a security certificate. This
certificate needs to be created, and then embedded into the jar file (known as
signing the jar file). The client machine needs to know at runtime that the
certificate comes from a valid source.
The Versions Game
The first problem encountered was that the default JInitiator for
Forms 6i uses version 1.1. The corresponding JDK is for Java1. The
documentation and utilities on the Sun website for Java1 were archived a long
time ago. The client was reticent to upgrade the JInitiator to 1.3 because the
old version was already working and the initial versions of JInitiator 1.3 were
not very stable.
When using JInitiator 1.1,
it is necessary to compile PJC with Java 1.1 and sign it in the version 1.1
way. However, it was not possible to make this work for our client. It worked with the public certificate created
by Oracle, but not with our certificate.
With JInitiator 1.1 a certificate must be installed on each
client machine. This was large hurdle to overcome. In JInitiator 1.3, when the
Java runtime encounters a JAR file that is signed with an unknown certificate,
it will pop up a dialog asking the user if they want to install and run that
code as shown in Figure 1.
Figure 1 – Screen that appears on the applet install for
JInitiator 1.3
The client finally agreed to upgrade the JInitiator to 1.3. With JInitiator 1.3, you can build the class with
Java 1.3 and sign the JAR file in the 1.3 way, as described in the next
section.
The Forms 6i patch version was important for this process as
well. For the first patches of Forms 6i, there was a bug that did not allow
multiple signing identities. JInitiator itself requires a signing identity. If
a new jar is added with a custom identity, it was not recognized. In order to
override this restriction, it was necessary to unjar f60all_jinit.jar, rejar it
with the extra classes, sign the new jar, and reference that in formsweb.cfg
instead of f60all_jinit.jar. This would allow the certificate to work, but it the
operation must be repeated any time a new Forms patch is added.
The Security Certificate
The best solution to the problem described above is to acquire
a security certificate from a certificate authority. This will allow your code
to run smoothly and the clients will not even be required to accept the code.
If you creating a pure Internet application that is open to anyone, it is highly
recommend that you acquire this type of certificate. If this application is
only accessible to a limited number of users through an Intranet system, you
can create your own security certificate using the following steps:
1.
Select a secure directory to store the security keys;
check that JDK1.3.1 is available (a “certificates” directory should be created
in the Java default directory)
Java –version (should return java 1.3.1)
2.
Select the appropriate values for the certificate
description as shown here:
Name |
Example |
CN= |
CompanyName |
OU= |
ORGUnitName |
O= |
IT Development |
L= |
CityName |
S= |
StateName |
C= |
CountryName |
Validity (in days) |
7000 |
3.
In the “certificates” directory, add the following command
to generate a keystore:
keytool -genkey -dname "cn= CompanyName, ou= ORGUnitName,
o=IT Development, l= CityName, s= StateName, c= CountryName " -alias
pjc_identity -keypass pjc_identity_pwd -keystore keystore –storepass
keystore_pwd -validity 7000
4.
Verify that the certificate is in place
keytool -list -keystore keystore –storepass keystore_pwd
Signing Jar files
1.
Sign the JavaBean jar file with the certificate created
before:
jarsigner -keystore <add certificates directory
here>/certificates/keystore –storepass keystore_pwd -keypass
pjc_identity_pwd ClientWrite.jar pjc_identity
2.
Verify the jar:
jarsigner -verify ClientWrite.jar
3.
Copy the jar in the directory
/appl/oracle/dev/d01/oracle/devcomn/java/oracle/apps/fnd/jar
4.
Add the jar name to the appsweb.cfg
file.
Testing the Results
The easiest way to test this application was to install the Forms
6iDS and add an entry for the test form to the formsweb.cfg file using the
following code:
[PrintJob]
IE50=JInitiator
form=chrisprintjob
userid=test/test@obi16.dulcian.com
archive_jini=f60all_resigned.jar,ClientWriter.jar
width=650
height=550
separateFrame=false
splashScreen=no
lookAndFeel=Oracle
colorScheme=Khaki
It was helpful to display the Java Console to see that the jar
file was loaded correctly and that the JavaBean had no errors. In order to
display the Java Console, you need to set the Plug-in components as shown in
Figure 2.
Figure 2 – Properties for displaying the Java Console
for testing purposes
At runtime, the Java Console should load the f60all and your
custom jar without any errors, as shown in Figure 3.
Figure 3 – Correct loading of the signed jar file
Additional Documentation
· Oracle Forms Online Help
· Oracle 9i Forms: JAR File Signing for JInitiator 1.3 Technical White Paper – September 2002
· “Building Internet Applications with Oracle Forms 6i and Oracle 8i” – An Oracle Technical White Paper- March 2000
About the Author