JDeveloper Web Development: Tips & Techniques

 

JDeveloper was created to help you design, develop, debug, and deploy Java code of different types and build an object layer that accesses the database. It offers a rich set of features for designing, developing, debugging, and deploying Java and other related files that are part of the Java 2 Platform, Enterprise Edition (J2EE). JDeveloper 10g contains many wizards and code generators that make it easier to implement complex functionality in Java, enabling you to concentrate on solving business problems when building web applications. It also offers strong code organization and configuration management. However, if you are just getting started with this tool, there is a lot to learn. This paper will offer some helpful tips and techniques that the author has gleaned from building real systems with this product that will hopefully be helpful to others.

I. Beginner Level Tips

The following tips can help you get started with your first few JDeveloper experiences.

A. Use the Internet

There are many helpful sources of information available over the Internet:

·         Use Google a lot!

·         Use OTN:  (i.e. how to get a check box to work in a JSP see link)
http://www.oracle.com/technology/products/jdev/tips/mills/adf_data_bound_checkbox.html

 

B. Use Naming Conventions

Consistently applied naming conventions are critical for the success of any system. Given the enormous number of elements available in the Java and JDeveloper environments, it is even more important to have a clearly defined set of conventions to follow. Creating naming conventions for your Java applications has several benefits:

1.        When you review your own or other people’s code, you can quickly grasp the meaning of a particular element simply by seeing its name.

2.        By knowing how elements are named, you can locate specific elements more efficiently, making your applications easier to maintain.

3.        Another benefit of using a naming convention is that it frees you from having to re-create ways to name elements. By having a naming framework, you will not have to stop and think about how to name each new element.

4.        Consistently named elements applied throughout an organization also make it easier for developers to work on each other’s code.

The following are some naming conventions that the author has found useful in JDeveloper. Note that the type of object is often pre-pended on the instance name.  This can help you locate things like buttons on a page, when you do not remember their exact names.  (i.e. jButton_Save).

·         jPanel_main

·         borderlayout_contentPane

·         jTextField_firstName

·         jTextArea_description

 

New Java classes are always named with an initial capital letter and initial capitals on merged word transitions as shown in this example:

MyClass(String firstParameter_In, Date secondParameter_In)

 

Methods within a class are handled with an initial lower case letter, and the uppercase letter is used to indicate additional words as shown here:

·         myMethod()

When naming Associations and Links in ADF Business Components, start with the parent-object, then add the word “To”, followed by the child object as shown here:

·         (ParentToChild)

·         DeptToEmpAssoc  (this association would validate that Emp.dept_Id is a valid value in the Departments table)

·         EmpToAddressLink (this link would provide a set address for current employee)

 

C. Generate “create” Methods for Entities

There are several ways to handle the creation of new rows in the database.  However, unless you obtain an appropriate primary key at the time of creation in the middle tier, a number of subtle bugs may show up in your application. Therefore, it is recommended that you always check the box next to “Create Method” in the Entity Object Editor shown in Figure 2.

 

Figure 2. Entity Object Editor - Create Method checkbox

 

Find the “create” method in the “yourEntityImpl.java” class in the Structure pane and add the following code to get a sequence counter from the database to populate the primary key.

 

  protected void create(AttributeList attributeList)

  {

    super.create(attributeList);

    oracle.jbo.server.SequenceImpl s = new oracle.jbo.server.SequenceImpl("myTable_seq",
                                                                           getDBTransaction());
    this.setMyTableId(s.getSequenceNumber());
}

 

D. Coding Shortcuts

There are many handy coding shortcuts that can speed up your code writing in JDeveloper. For a complete listing see:
 Tools | Preferences | Code Editor | Code Templates | Shortcut (column)

1. Type “sop” and then press “Ctrl-Enter” to give you:    

System.out.println();

 

2. To create a basic FOR LOOP, type “fori” and press “Ctrl-Enter to get:      

for(int i=0; i<  ;  i++)
{
}

 

3. Use “Surround with” to add commonly used code snippets to any block of highlighted text.  Right-click the highlighted block and then click “Surround with” to add snippets such as: try-catch, if, while, for, if-else, etc. around the selected block. Figure 1 shows some of the options for the Surround With menu choice.


Figure 1.  Surround With

Making the selection shown in Figure 1 inserts the following code: 

try

            {

               String x ="";

            }

             catch (Exception e)

          {

           }

 

4. Indent/shift blocks of code by highlighting the code and then pressing “Tab” or “Shift-Tab” to move the entire block.

E. Backup your entire workspace

Backup your workspace, or be prepared to suffer the loss. Use any zipping tool to make regular backups of your entire workspace.  Even with the best source control system you may implement, it is still necessary to do this often.  Typical applications can run into hundreds of pages of generated and hand-written code, which have large interdependencies.  The ability to step forward or back in time can be a life saver when things go wrong.

II. Intermediate Level Tips

After you have had some practice building simple applications with JDeveloper, these tips and techniques may come in handy.

A. Use Views with INSTEAD OF Triggers

Although you may be tempted to build a middle-tier similar to the database with entities for each table of interest, this approach may not be very scaleable. Many BC4J projects have had to be rebuilt because they performed very poorly when there was significant data in the middle tier.  An alternative approach uses ADF BC to build one or two objects per page against database views that handle the complex table joins for a given user application page.  Inserts, updates and deletes can then be handled with INSTEAD OF Triggers on the database view object.  Better code maintenance and middle tier performance are quickly achieved, and the database and client code can be developed and debugged independently by maintaining a single common point of interaction in database views representing the pages in the user application. Limit the use of entities to data that needs to be written back to the database.  Entities require additional overhead and data caching, so it is wasteful to use them for static content.

Use a view object that directly points to the database for read-only data.  You can implement almost any complex query in an ADF view object, but let the database store and execute your complex queries.  Keep the ADF view objects simple.  Focus on using one or two views per page, in the same way as described previously for entities. For example, using the emp_details_view to update manager_id for an employee from the HR Schema: (emp_details_view  - joins five tables), you could create the following INSTEAD OF trigger:

CREATE OR REPLACE TRIGGER t_iu_emp_details_view

 INSTEAD OF

  UPDATE

 ON emp_details_view

Referencing new as new and old as old

Begin

  if updating ('manager_id') then 

      update employees set manager_id = :new.manager_id

       where employee_id = :old.employee_id;

  end if;

end;

 

B. Clearing the ADF BC Cache

It is important to keep the view and entity caches synchronized with the database.  Before deleting a parent row, it is necessary to clear the ADF BC cache for child rows using the Remove method in the parent class. To access the remove method, check the box next to “Remove Method” in the Entity Object Editor. Then add custom code to spin through and remove any child rows, in the yourEntityImpl.java class.

 

Figure 3. Entity Object Editor - Remove Method checkbox

 

The following is an example of the code to remove the child rows:

 

public void remove()

{

 

  getDBTransaction().executeCommand(

     "Begin  ste_rnd.p_DisconnectDigrmHookedClasses(" + this.getDigrmId() +

                      " );  End;" );

 

    //remove child rows when deleting a Parent row

    oracle.jbo.Row r;

    this.getRmDDURClass().reset();  

    while (this.getRmDDURClass().hasNext()){

      r = this.getRmDDURClass().next();

 

            r.remove();

      this.getDBTransaction().commit();     

    }

 

    super.remove();  

    this.getDBTransaction().commit();

}//End remove()

 

C. Use JClient Layout classes

JClient Layout classes are designed to improve portability across operating systems and hardware variations such as monitor resolutions.  Traditional client applications have been designed with rigid XYLayout values that were geared to a single pre-defined size/resolution on the client’s monitor.  Each item would be set to a specific location, and given an exact size. 

With the need for more portable solutions, JClient applications have a wide variety of Layout editors to dynamically accommodate wide differences in end-user preferences.  Objects used to display information in JClient applications can be made to resize and reposition themselves as available screen real estate changes.  Objects can “flow” around on the screen as widows are resized, or as data changes.  For example, you can use the GridBagLayout to place information into cells in a grid or use the FlowLayout to arrange components into rows similar to a word-wrap feature in a word processor. Failure to take advantage of these new Layout classes will leave your client applications with an out-of-date look and feel.

 

D. Tips for Building ADF BC – JSP/Struts-Based Web Applications

Use the App-Module_Impl class to hold custom Java code. Expose custom methods to the client, using the Client Interface node in the Edit Entity wizard. (Do not put Java directly into the JSPs). The following code illustrates a custom method called getBrimErrorMessage added to the AppModuleImpl.java class to be used in a Struts data action.

 

public class AppModuleImpl extends ApplicationModuleImpl implements model.common.AppModule

{

  // *********Add custom code here ********

  public String getBrimErrorMessage()

  {

    //send data down to the database

    this.getTransaction().postChanges();

    //check for errors

    this.getBrimErrorView().executeQuery();

    if( this.getBrimErrorView().first()!=null && 

       ((BrimErrorViewRowImpl)this.getBrimErrorView().first()).getMessage()!=null &&

       (((BrimErrorViewRowImpl)this.getBrimErrorView().first()).getMessage()).length()>0)

    {

 

      //refresh clean data from database on rule failure

      int currentRowIndex = this.getPageOneEmpDetailsViewView().getCurrentRowIndex();

      this.getPageOneEmpDetailsViewView().executeQuery();

      this.getPageOneEmpDetailsViewView().setCurrentRowAtRangeIndex(currentRowIndex);

      this.getTransaction().commit();

 

      return "isError";    

    }//else no problems found - just return “success”

      return "success";

  }

 

Next, expose the code to the client by moving the method names to the Selected pane in the Application Module Editor shown in Figure 4.

 


Figure 4. Application Module Editor

 

Keep the code in the JSPs limited to presentation-only objects.  Conditional logic belongs in Struts, and complex Java code should be placed in the AppModule or database.

E. Leverage “event_MyCustomCode” Forwarding in Struts

Leverage the “event_MyCustomCode” forwarding architecture that Oracle provides in the enhanced Struts framework.  Navigation for Events/Actions is automatically handled for you when you name buttons and actions per Oracle’s new Struts standards.    As shown in Figure 5, this snippet of Struts code shows how one of these (event_Submit) is used to navigate to the forward named “Submit.”   The DataPage in the upper left corner has a Submit button named “event_Submit”.  When the button is pressed, data from the form is returned to ADF BC.  After the transfer, Struts will look for a forward from the page that is named without the leading “event_”.  Thus in the case of the Submit button, Struts will look for a forward named “Submit”.  As shown in Figure 5, the forward from the page goes to the next data action “/getBrimError”. 

 

 

Figure 5. Example of Struts forward architecture

 

When the Struts controller sees /getBrimError, several things happen.  First, some custom code in the appModule checks for any custom error messages that the database may have returned.  Next a string will be returned via “methodResult” with the name of the appropriate forward.  Thus the controller will be redirected back to pageOneDP when “isError” is returned, or to the successPage when “success” is returned.  The code shown below overrides the findForward method for /getBrimError to receive the transition passed back in methodResult and use that to forward to the next page or action.

 

public class GetBrimErrorAction extends DataAction

{

  protected void findForward(DataActionContext actionContext) throws Exception

  {

    HttpServletRequest request = actionContext.getHttpServletRequest();

    if(request.getAttribute("methodResult")!=null &&
        ((String)request.getAttribute("methodResult")).length()>0)

    {
      actionContext.setActionForward(actionContext.getActionMapping().findForward(

                                                      (String)request.getAttribute("methodResult")));

    }

    super.findForward(actionContext);

  }

}

 

F. Clean up Generated Data Bindings after Deleting Objects from a Data Page

Remember to clean up any data bindings generated in Java classes named like “pageNameUIModel.xml” any time you delete data-bound-objects from the corresponding user interface pages.   For example, when you drag-and-drop data bound objects onto a JSP page and later decide to remove them, you must do additional clean up outside of the JSP.  Each data object that is added to a page has its model bindings generated in an XML file.  If you add, delete, and re-add ManagerId to pageOne you will see multiple entries that start with “ManagerId”.  To clean this up, right-click each of the “ManagerId”entries in the Structure Pane shown in Figure 6. Then click Delete.  Finally, remove the object bound to ManagerId in the JSP and re-drag-and-drop to establish the correct binding.



Figure 6. Cleaning up the Data Bindings

G. Build Smart Objects in the Client User Interface

Build smart-objects in your client user interfaces that can be programmatically updated from the database (i.e. having a button’s displayed name come from the database.)

If you are stringing data actions to perform some task and you want to be able to access the view in a subsequent data action, make certain that you are using the same user interface model.  Notice in the following struts-config.xml file that for each action, the property modelReference has the same value of addmgrrequestUIModel.

 

            <action path="/savemgrrequest" className="oracle.adf.controller.struts.actions.DataActionMapping" type="oracle.adf.controller.struts.actions.DataAction" name="DataForm">

                        <set-property property="modelReference" value="addmgrrequestUIModel"/>

                        <set-property property="methodName" value="savemgrrequestUIModel.startToCreateMgrRequest"/>

                        <set-property property="resultLocation" value="${requestScope.methodResult}"/>

                        <set-property property="numParams" value="0"/>

                        <forward name="success" path="/loadimagefile.do"/>

            </action>

            <action path="/loadimagefile" className="oracle.adf.controller.struts.actions.DataActionMapping" type="oracle.adf.controller.struts.actions.DataAction" name="DataForm">

                        <set-property property="modelReference" value="addmgrrequestUIModel"/>

                        <set-property property="methodName" value="mgrrequestsUIModel.SetImageFile"/>

                        <set-property property="resultLocation" value="${requestScope.methodResult}"/>

                        <set-property property="numParams" value="2"/>

                        <set-property property="paramNames[0]" value="${bindings.RequestOid}"/>

                        <set-property property="paramNames[1]" value="${param.file1}"/>

                        <forward name="success" path="/mgrrequests.do"/>

            </action>

III. Advanced Level Tips

As you become more familiar with the depth and features of JDeveloper and have built more applications, the following suggestions may be useful:

1.        Communication between multiple Java processes is harder than between threads.  A useful workaround is to utilize the file-system as a scratch pad to communicate between processes.  Each process is set up to read and write to a given file.  Synchronization occurs using a polling-type routine within each process.  The shared file is tested at a given interval by each process. Thus, information can be developed and shared by two independent processes which normally could not communicate with each other by simply reading or writing the shared file.

2.        Use XML as a persistent-data store (using the Java Architecture of XML Binding (jaxb) technology to read/write XML).  You can automatically generate all of the necessary Java classes to read and write data to well-formed XML files using the XML Binding Compiler (xjc).  The generated classes will read, parse and write the data using simple object.get and object.set methods:  - i.e. PATIENT.setLASTNAME(“Smith”).

 

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<PATIENTLIST>

  <PATIENT>

    <IDNUMBER>10000</IDNUMBER>

     <LASTNAME>Smith</LASTNAME>

    <FIRSTNAME>Bob</FIRSTNAME>

      <DESCRIPTIONS>

       <DESC ROW="">hand trouble</DESC>

       <DESC ROW="Referred by">The Hand Clinic - Paris</DESC>

       <DESC ROW="Group As">Hand "Type 2" trouble...</DESC>

 

This code represents the XML persistent data store, which is simply an XML file stored on your hard drive and it can be used with or without a database.

Conclusions

JDeveloper has a fairly steep learning curve. The many wizards and editors in the tool can greatly expedite your application development. However, it is important to use many of the other resources available (Internet, OTN, Help files, Tutorials, books, etc.) to benefit from the experiences of others. When possible, get a mentor who has been using the product to build real systems to help guide your first few efforts.

About the Author

Dr. Paul Dorsey 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. He is the chief architect of Dulcian's Business Rules Information Manager (BRIM®) tool.

Paul is the co-author of seven Oracle Press books that have been translated into nine languages:

·         Oracle JDeveloper 10g Handbook

·         Oracle9i JDeveloper Handbook

·         Oracle JDeveloper 3 Handbook

·         Oracle Designer Handbook (2 editions)

·         Oracle Developer: Advanced Forms and Reports

·         Oracle8 Design Using UML Object Modeling – (the first book about UML data modeling – published 1999)

Paul won the ODTUG 2003 Volunteer of the Year award, the Chris Woolridge Outstanding Volunteer Award at IOUG-A-Live! 2001 and was one of six initial recipients of an Oracle 9i Certified Masters award from Oracle Corporation at OOW 2001. He is the President of the New York Oracle Users’ Group and a Contributing Editor of the International Oracle User Group’s SELECT Journal. He is also the founder and chairperson of the ODTUG Business Rules Symposium, (now called Best Practices Symposium), currently in its sixth year, and the J2EE SIG.