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 information to the JavaBean:

 

  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 information from the JavaBean while it is running, code WHEN-CUSTOM-ITEM-EVENT triggers in your form.

 

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

Ileana Balcu is a Senior Developer for Dulcian, Inc. Ileana was the first Oracle Certified Professional in Romania. She develops generic Oracle Developer Forms and Reports systems for a variety of organization types including banking, manufacturing and government agencies. She has presented at several ODTUG conferences and at other local Oracle user group meetings.