Developing Applications With Complex Graphics in JDeveloper 9i

 

Background

JDeveloper 9i is a sophisticated development tool. For building client/server applications, it is slightly less efficient and more difficult to build using JDeveloper than in a standard 4GL such as Developer. It also takes significantly longer although JDeveloper is improving with every version and the Oracle team is working to decrease the lag between the products.

There are things that JDeveloper can do that Developer and other 4GLs cannot. In particular, JDeveloper is very well suited for creating highly complex, graphics-intensive applications. These types of applications could never be built in Developer regardless of the time and skill of the resources devoted to the project.

At Dulcian, we used JDeveloper 3.2 to build an application using sophisticated graphics over the last 18-months. This was a long and difficult process, requiring two complete rewrites of the application before adequate functionality and performance were achieved. In the end, a number of creative workarounds were also required to reach the desired result.

This paper will do the following:

·         Describe the application we built

·         Outline the difficulties encountered

·         Provide advice for building similar applications

·         Show some of the basic ideas and code examples associated with building a JDeveloper graphics application

 

Description of the Application

Dulcian has evolved our own business-rule based systems development methodology over the last few years. All system requirements are placed into a unified repository from which the system is generated. This grand vision requires a single application to maintain a complex repository containing different kinds of business rules:

·         Structural business rules are entered using UML class diagrams

·         Process-related business rules are entered using modified UML activity diagrams

 

Using this approach, in addition to supporting the traditional complex application requirements, it was also necessary to include the ability to draw diagrams on the screen similar to the functionality of Oracle Designer’s ER Diagrammer or JDeveloper’s Class Modeler. We were ultimately trying to create a single, integrated application to maintain the entire rules repository.

To achieve this goal, we had to overcome the “piecemeal” feel of products such as Designer where the Repository Object Navigator (RON) is separate from the ER Diagrammer. Changes made in one part of the tool are not immediately reflected in the other. After many months of work, we were able to create a unified environment where we can design, generate, test and maintain configuration management of a system. Figure 1 shows the resulting integrated Repository Manager Process Flow tool.

 

Figure 1: Repository Manager Process Flow Tool

It is beyond the scope of this paper to fully discuss the architecture of the business rule engine. Contact the author for further information.

Difficulties Encountered in Creating a Graphics Application in JDeveloper

In order to build applications using the business-rule based methodology described above, you must recognized that the coding required goes far beyond what the JDeveloper 9i wizards can support. A lot of hand coding was necessary in order to create these types of applications. If you have not had a great deal of experience with Java, you will need to learn it when building these systems. Also, many of the standard Java references do not have adequate material about drawing graphics in Java. We did find a few texts specifically targeted for creating graphics in Java. In particular Java 2D API Graphics by Vincent J. Hardy (Prentice Hall PTR; ISBN: 01301426621999) and Graphic Java 1.2, Mastering the JFC: AWT, Volume 1
by David M. Geary (Prentice Hall , ISBN: 0130796662 1998 )
were very useful.

One of the toughest challenges faced in working with the JDeveloper 3.2 release was in getting the graphical objects to interact meaningfully with the Oracle database. For example, in a UML class diagram, if each row in the database table CLASS represents a class and a diagram showing classes, it is necessary to represent the classes from the table on the screen as well as being able to add classes on the screen and have them inserted into the database.

In traditional applications development, the user interface (UI) components are intelligently linked to the database. This is a more complex with graphics objects since they must be created on the fly. Immediate access was used in our system to extract the information from the JDeveloper Business Components for Java (BC4J). This used the old ROWSET/Infobus architecture, which produced terrible performance. It took 1/100th of a second to perform immediate access retrieval from a BC4J cached object. This may not sound like a long time, but when displaying a diagram, there may be several thousand information elements to consider. Every object has at least four: height, width, x and y positions). Using this interval rate (10 seconds/1000 elements), some diagrams took up to 30 seconds to load.

The next section will demonstrate how to create some of this functionality in JDeveloper 9i without the use of immediate access while achieving much better performance.

 

Building a Graphics Application

This section will include two separate project examples. The first will serve as a introduction to the basic concepts associated with graphics in JDeveloper 9i. This application will draw a simple box and line on the screen. There is no database interaction.

The second section will explain the steps used to create a simplified version of our Repository Manager. This project requires the use of a database table to store UML classes.

NOTE: This is not a novice step-by-step tutorial. It is assumed that you already know hot to create workspaces, projects and simple applications in JDeveloper.

 

Application to Draw a Box and Line (no database access)

The following steps can be used to create a simple drawing application:

1.        In a new workspace and project, create a JFrame object. Inside the frame, create a JDesktopPane and JInternalFrame. These are required to support MDI graphics development. An excerpt of the code used is shown here (Snippet 1)

 

public class FrameBc4jPackageModule extends JFrame

{

  private JUApplication app = null;

  private GridLayout gridlayout = new GridLayout();

  JDesktopPane myDesktop = new JDesktopPane();

  BorderLayout borderLayout1 = new BorderLayout();

  JInternalFrame class1Frame = new JInternalFrame();//Must use JInternalFrame for MDI

 

Snippet 1: Code to support MDI graphics development

Class1Frame is the name of the object to be displayed and sized on the screen. Note that the frame is set up using GridLayout as the Layout property. This can be done either by using the JDeveloper wizards to generate the frame or hand coded.

2.        In the Jbinit method for the frame, add myDesktop (JDesktopPane) to the overall application frame’s content using the code shown here (Snippet 2):

 

this.getContentPane().add(myDesktop, BorderLayout.CENTER);

 

Snippet 2: Code to add a pane to the desktop

 

3.        Define the location and size of the window by invoking the appropriate set methods using the following code (Snippet 3):

 

class1Frame.setLocation(50,50);

 class1Frame.setSize(100,50);

 

 

Snippet 3: Code to define location and size of window

 

4.        Add and display the frame using the code shown here (Snippet 4):

 

insert 4

myDesktop.add(class1Frame);

  class1Frame.setVisible(true);

 

Snippet 4: Code to display the frame

 

The four steps above are all that is necessary to handle frames. You can take advantage of the native MDI environment to support the drawing of frames. For most drawing objects, you will need to use the Java paint( ) method. The paint( ) method is included with all graphical objects in the Java source code from Sun Microsystems which can be called as required.

5.        To draw lines or other objects on the screen, it is necessary to make standard graphics calls as shown in the code below (Snippet 5):

public void myDraw(Graphics g)

  {

    //This paints lines

    g.setColor(Color.black);

    g.drawLine(0,0,200,200);

  }

 

Snippet 5: Code for graphics call

This code creates a graphics object and draws a black line. MyDraw is invoked in the library paint( ) method as shown in the following code (Snippet 6):

public void paint(Graphics g)

{ 

    myDraw(g);

 

  }

Snippet 6: Code to invoke MyDraw

If you run the routine at this point, the line will be drawn on top of the frame since the frame is drawn before the paint( ) method is invoked. If the goal is to create a modeling application, then the lines must be drawn so as not to cover the frames. The simple solution is to paint the frame after the lines are created. This can be accomplished by added a repaint command to the paint( ) method as shown here (Code Snippet 7):

public void paint(Graphics g){

      myDraw(g);

      class1Frame.repaint();    //This paints Frames over lines 

  }

Snippet 7: Code to repaint the frame

 

Moving graphics on the screen

You may want to click and drag frames and not allow the line to disappear. Using only the steps above, at this point, the frame will act as an eraser and the line will not be redrawn. To solve this problem, add a command to redraw the line.

There are significant resources required in moving frames around on a screen that may not be justified. Some programs use degraded graphics where the user sees an outline of the object being moved. The object is then repainted after movement is complete. This is a simple issue for frames. You simply need to set the myDesktop JDesktop DRAG mode in the Jbinit method as shown here (Snippet 8).

myDesktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); 

 

Snippet 8: Code to move frame on screen

The line must now be repainted after the frame is moved. This is accomplished by adding a mouseReleased event to the frame to re-invoke myDraw as shown in the following code (Snippet 9):

void class1Frame_mouseReleased(MouseEvent e)

  {

    myDraw(this.getGraphics());

    }

Snippet 9: Code to repaint line after moving frame

 

Create a Simple Repository Manager (database access)

The application works by loading the classes into BC4J, looping through the BC4J view and displaying the classes on the screen. The application also includes a button with the functionality of loading and displaying the classes.

1.        Create a table called “CLASS” and populate it with data using the code shown below (Snippet 10):

CREATE TABLE class

 (

  classid                    NUMBER(10) NOT NULL,

  name                       VARCHAR2(200),

  locx                       NUMBER(10),

  locy                       NUMBER(10),

  width                      NUMBER(10),

  height                     NUMBER(10),

  color                      VARCHAR2(20)

 )

 

Snippet 10: Code to create CLASS table

2.        In a new workspace, create a standard BC4J project using the wizards to generate an entity and view for the CLASS table.

3.        Again using the JDeveloper wizards, create a frame and panel for the BC4J object.

4.        Create a default application to support the CLASS table.

 

At this point, there are two different ways to interact with a BC4J view:

·         Directly by manipulating the view

·         Indirectly by bolting a BC4J view to a UI construct and interacting with the UI object for retrieval and updating of data

 

These two approaches result in virtually identical performance statistics. Each has its own pros and cons. Using UI components, you also have the advantage of reusing these components. For this application, you can have the graphical classes appearing on the screen and the UI components appearing in a separate window such as a property sheet.

Using the UI components approach takes advantage of the power of the JDeveloper 9i wizards by decreasing the amount of manual coding required.

Not using the UI components is a conceptually cleaner approach. For some, it may be more technically satisfying to interact directly with the BC4J components rather than placing them in an intermediate area.

In JDeveloper v. 3.2, it was necessary to use UI components because directly accessing BC4J rowsets was significantly slower. In the 9i release, this performance difference does not exist.

 

5.        In a BC4J Panel, using a BorderLayout, place a button on the screen. Label the Button “Load.”

6.        Create an InternalFrame and JDesktopPane and add the internal frame to the desktop pane as in the previous example.

7.        As you spin through the BC4J objects, they must be loaded into a vector. To declare the vector, use the following code: (Snippet 11):

 

Vector classVector = new Vector();  //Holds pointers to Frames representing classes

 

Snippet 11: Code to declare vector

8.        Clear the vector using the code shown here (Snippet 12):

 

classVector.removeAllElements();

Snippet 12: Code to clear vector

 

9.        Generate a pointer to the BC4J class view by creating the appropriate objects in the declaration section of the class as shown here (Snippet 13):

ViewObject vo; //access to BC4J 'Class' view

int voRows; //used to store the number of rows returned in the View

 

Snippet 13: Code to generate pointer

10.     Instantiate the pointer using the following code (Snippet 14):

vo = app.getApplicationModule().findViewObject("Class1View");

voRows = vo.getRowCount();

vo.reset();//resets the iterator to 'before' the first row

 

  

Snippet 14: Code to instantiate pointer

11.     Create an action event on the Load button either suing the wizards or by adding the following method to the class (Snippet 15):

 

void loadjButton1_actionPerformed(ActionEvent e) {}

 

Snippet 15: Code to enable Load button

12.     Spin through the BC4J rowset using the code below (Snippet 16) to retrieve the information for the frames and add it to the vector:

for(int r=0; r<voRows; r++){

      if(vo.hasNext()){

        Row row = vo.next();//returns first row, then next row, etc...

   //Creats a new JInternalFrame for each row in the ClassView

   JInternalFrame currentFrame = new JInternalFrame("",true,false,true,false);

   myDesktop.add(currentFrame);

  currentFrame.setTitle(new String(row.getAttribute("Name").toString()));

  currentFrame.setLocation(

        Integer.parseInt(row.getAttribute("Locx").toString()),

        Integer.parseInt(row.getAttribute("Locy").toString()));

currentFrame.setSize(

       Integer.parseInt(row.getAttribute("Width").toString()),

       Integer.parseInt(row.getAttribute("Height").toString()));

currentFrame.setVisible(true);

classVector.addElement(currentFrame);//add instance of JInternalFrame to the vector

}

Snippet 16: Code to retrieve frame information

 

Since SET commands take integers, the only way to get information from the BC4J layer is by using the toString( ) method. You must then cast the value back to be an integer using the parseInt( ) method.

Because the frames are stored in a vector, they can be re-displayed very quickly with a simple myClassDraw method as shown here (Snippet 17):

public void myClassDraw(Graphics g)

{

       g.setColor(Color.black);

      if  (!classVector.isEmpty())

    {

           for(int i=0; i<classVector.size();i++)

          {

              ((JInternalFrame)classVector.elementAt(i)).repaint();

           }//End Loop

    }//End If        

  }      

Snippet 17: myClassDraw method

 

The only difference between working directly with BC4J and using the UI components is that another command must be used to retrieve the information to set the title and location as shown here (Snippet 18):

currentFrame.setTitle(new String(name_jTextField1.getText()));

currentFrame.setLocation(

       Integer.parseInt(locXJtextField.getText()),

       Integer.parseInt(locYjTextField.getText()));

 

Snippet 18: Code to set title and location

Note that the getText( ) method must be explicitly cast to an “int” for the setLocation method.

Conclusions

Working with graphics in Java is neither simple nor intuitive. As is usually the case, there are easier and harder ways of accomplishing the same tasks. After 18 months of experience with this new tool, we found that Murphy’s Law seemed to be in full force. The first three ways we attempted for many tasks seemed to be the least effective.

We also gained a new appreciation for why some capability was never built into other products by their development teams. Even functionality that may appear quite simple, is in reality, quite complex. For example, detecting whether or not a user has clicked near a line appears to be a simple task. This task can be approached in two ways. The hard way is to globally detect a mouse click event, determine the cursor location and mathematically calculate the distance to each line on the screen to see if it is close. The easy way is to place an invisible long, thin box around each line with a listener to detect a mouse click event. Unfortunately, we tried the harder way first.

In another case, to draw boxes on the screen , you can either draw rectangles and code intelligent behavior on them or use native frames to get all of the drag and drop, resizing and degraded graphics functionality for free. (Guess which approach we tried first?)

The point is that graphics programming in Java, and particularly when connecting to an Oracle database is a unique, specialized area of knowledge. Before embarking on such a “trek,” you would be wise to find a “code Sherpa” to help you avoid the myriad crevasses where you can get stuck.

 

About the Author

Dr. Paul Dorsey (paul_dorsey@dulcian.com) is the founder and President of Dulcian, Inc. (www.dulcian.com), an Oracle consulting firm that specializes in business rules-based Oracle Client-Server and Web custom application development. Paul is co-author of five Oracle Press books that have been translated into six languages: Oracle JDeveloper 3 Handbook, Oracle Designer Handbook (2 editions), Oracle Developer: Advanced Forms and Reports, Oracle8 Design Using UML Object Modeling. Paul won the Chris Woolridge Outstanding Volunteer Award at IOUG-A-Live! 2001 and was one of six initial recipients of an Honorary Oracle Certified Master award from Oracle Corporation at OOW 2001. Paul is the Executive Editor of the IOUG’s SELECT Journal, President of the New York Oracle Users’ Group and the founder and chairperson of the ODTUG Business Rules Symposium, now in its third year.