At the Breaking PointBy Steve Muench
Debug more effectively with Oracle Application Development Framework.
Debugging is fundamental to successful enterprise application development. This column explores Oracle Application Development Framework (Oracle ADF) debugging features that go beyond the simple source code breakpoint. You’ll bolster your Oracle ADF debugging toolbox by learning how to break when an exception occurs, when an action binding is triggered, when a task flow activity runs, and when a query executes.
To begin, download the starter workspace and ensure that you are using the studio edition of the Oracle JDeveloper 220.127.116.11 (production) release, available as a free download on Oracle Technology Network (OTN). Start by extracting the contents of the o59frame.zip file, and open the FrameworksSepOct2009.jws workspace in Oracle JDeveloper. (If the Migration Wizard appears, allow the project to migrate, taking all defaults.) The Model project in the workspace defines a base set of Oracle ADF components for working with the data in the EMP table in the SCOTT schema. The ViewController project includes the Home.jspx page, which is based on a page template and includes the browse-dept-and-emps bounded task flow as a region. Before proceeding, adjust the properties of the connection named scott in the Application Resources zone of the Application Navigator until you can successfully test a connection to the SCOTT schema. If necessary, use the provided CreateDeptEmpTables.sql script to create the schema’s tables.
Using an Exception Breakpoint
When an unexpected operation occurs in a Java program, an exception signals the problem. To locate the problem quickly, you can use an exception breakpoint to stop the debugger whenever a specific kind of exception is thrown. The starter workspace contains code that throws java.lang.StringIndexOutOfBoundsException because of a programming error. Follow these steps to find and fix the problem:
From the main menu, choose View -> Debugger -> Breakpoints to show the Breakpoints tab. Right-click anywhere in this tab, and choose Add Breakpoint -> Exception Breakpoint . When the Create Exception Breakpoint dialog box appears, click in the Exception Class field and type SIO (the first few capital letters in the exception name), then select the StringIndexOutOfBoundsException (java.lang) entry, and click OK to define the new breakpoint.
In the Application Navigator, expand the Model project, the Application Sources folder, and the oramag.model package. Right-click the HRModule , and choose Debug to start the debugger. In Oracle Business Component Browser , double-click the HRModule application module at the root of the tree to see the list of custom methods it exposes to clients. The list consists of one initBrowseDeptAndEmpsRegion method, which the browse-dept-and-emps task flow uses to perform any necessary setup logic before executing. Enter a value of TestValue for the param1 property, and click Execute to test the custom method.
The debugger stops at a line in the String.java source and shows an alert dialog box with a message that begins, “The debugger has stopped in a class where tracing is disabled.” By default, the classes in packages that belong to the base Java Developer Kit (JDK) runtime—such as java.lang (which contains the String class)—are disabled from debugger stepping. You usually want to leave things configured this way to speed debugging of your own code, so dismiss the alert by clicking No in response to “Do you want to change the tracing options now?”
The debugger stops at a line in the String class’s substring() method. Select the Stack tab on the left to see the runtime call stack. (If you can’t see the Stack tab, select View -> Debugger -> Stack .) Observe that the HRModuleImpl class’s initBrowseDeptAndEmpsRegion method calls the substring() method on a String object. Double-click the HRModuleImpl line in the stack tab to jump to that line of code. As Figure 1 shows, the code adds +1 to the param1.length() expression when passing it to the substring() method, which is incorrect. Fix the problem by changing the param1.length()+1 expression to param1.length(). Click the red stop button in the main toolbar to stop the debugger. If you retest the method (right-click HRModule , choose Debug , double-click the HRModule application module in Oracle Business Component Browser , enter TestValue for the param1 property, and click Execute ), you’ll see that the exception no longer occurs. Finally, delete the breakpoint, by selecting it in the Breakpoints tab and clicking the red X (the delete icon) in the toolbar.
When you set a breakpoint for an exception, the debugger stops for all exceptions of that type or its subtypes . For example, if you set a breakpoint for oracle.jbo.JboException, the debugger will stop when subclass exceptions such as oracle.jbo.DMLException or oracle.jbo.ValidationException are thrown as well. To keep the debugger from stopping more frequently than you want, use the most specific exception subtype you can.
Using Binding and Activity Breakpoints
Oracle ADF simplifies problem-solving by letting you set breakpoints on key declarative constructs such as bindings and task flow activities. For example, you can set a breakpoint on a binding for a JavaServer Faces (JSF) page or page fragment. To try this out, expand the ViewController project, its Web Content folder, and the Page Flows folder inside that. Double-click the browse-dept-and-emps task flow to open it in the editor. Double-click the BrowseDeptAndEmps view activity to open the related page fragment in the visual editor.
You’ll set a breakpoint on the action binding related to the Refresh Current Department’s Employees button. Right-click this button in the editor, and choose Go to Binding . This switches the focus to the Page Data Binding Definition tab and selects the corresponding Execute binding for you. Right-click the Execute binding, and choose Toggle Breakpoint to set the breakpoint. Note the familiar red sphere icon in the margin to the left of the Execute binding, indicating that the breakpoint is set.
Next you’ll set an activity breakpoint. Click the browse-dept-and-emps task flow editor tab. Note that the default activity of this bounded task flow is a method call activity named initialize. This method call activity has already been configured to invoke the initBrowseDeptAndEmpsRegion method on the application module. (This was accomplished when the starter workspace was built, by a process that involved simply dragging the method from the Data Controls palette and dropping it onto the activity icon.) To set a breakpoint on the initialize activity, right-click it and choose Toggle Breakpoint.
To see the runtime effect of the two breakpoints you’ve just set, right-click ViewController in the Application Navigator and choose Debug . After Oracle JDeveloper opens your default browser to request the starting page but before anything appears in the browser, the debugger stops at the breakpoint on the initialize activity. Ensure that you can see the ADF Structure tab (you can use View -> Debugger -> ADF Structure to show it.) This tab displays a tree representing the Oracle ADF runtime context, showing that you’ve stopped at a breakpoint in the browse-dept-and-emps task flow, used as a region in the /Home page. You can select any node in the ADF Structure tab and inspect relevant information about that node in the ADF Data tab. (If you can’t see the ADF Data tab, select View -> Debugger -> ADF Data .) Select the browse-dept-and-emps node in the ADF Structure tab. In the ADF Data tab, expand the pageFlowScope folder as shown in Figure 2 to see the values of the two parameters this task flow accepts, named intParam and stringParam. This type of structural and parameter information can help you understand why a region doesn’t work as you expect it to.
Click the debugger resume button (two blue vertical lines and a right arrow) in the main toolbar to allow execution to proceed. When the page appears in your browser, click the Search button to show all departments. Click the Refresh Current Department’s Employees button to trigger the Execute binding on which you set the breakpoint. The debugger stops, showing the Execute binding as the current point of execution and giving you access to the ADF Structure and ADF Data tabs. If necessary, you can also use the EL Evaluator tab to evaluate expression language expressions you suspect might be causing problems on your page by failing to return the expected values. Click the debugger resume button to have execution continue, and then stop the default server by choosing Run -> Terminate -> Default Server from the main menu.
Using Method Breakpoints
You’ve seen how to set a breakpoint on an Execute action binding in a specific page definition. Other times your troubleshooting might require a more general-purpose breakpoint that enables you to stop when Oracle ADF performs a built-in operation —such as query execution—whether or not it is the result of an explicit end-user action. You can create this with a method breakpoint . This type of breakpoint stops the debugger whenever a specific method executes, even if you don’t have the source code for that method.
To illustrate this, you might want to stop the debugger when Oracle ADF executes a view object’s query. The best method to use for this purpose is the ViewObjectImpl class’s bindParametersForCollection() method. This method binds values for any relevant bind variables in the query just before the query executes against the database. To create the method breakpoint, select the Breakpoints tab (click View -> Debugger -> Breakpoints if the tab is not visible), right-click in the tab’s content area, and choose Add Breakpoint -> Method Breakpoint . In the Method Name field of the Create Method Breakpoint dialog box, enter
Click OK to create the breakpoint. Debug the application module, by right-clicking HRModule and choosing Debug . When Oracle Business Components Browser appears, double-click the WorksInDeptLink1 node in the tree to show a master/detail display of Departments and Employees rows. When you hit the breakpoint, if you don’t have the Oracle ADF source installed, you’ll see the Unable to Find Source File dialog box. Select Don’t ask me about this file again , and click OK.
At this point, the Stack tab shows you the chain of method calls that brought you to executing a view object’s query and binding its parameters. Click the Data tab to see the current object, shown as the this node at the top of the tree, as well as any method arguments such as params , which holds any parameter values to be bound. To see which view object is being executed, expand the this node and scroll to find the mObjName member. It holds the view object instance name, which you can see is Departments. Right-click mObjName , and choose Watch to add a watch to the watch list (on the Watches tab) for this value. Click back to the Data tab, and scroll to find the mViewDef member (also under the this node), which is a reference to the view object definition. By further expanding the mViewDef node and looking for its mFullName member, you can see the view definition’s fully qualified name: oramag.model.DeptView. Right-click the mFullName member, and choose Watch to add this member to the watch list. Return to the Data tab, and add the params argument (a top-level node) to the watch list.
While in the Watches tab, right-click in the content area and choose Add Watch . In the Add Watch dialog box, enter this.getQuery() as the expression to watch and click OK . This causes the debugger to evaluate the this.getQuery() method on the current view object. Its value is the full SQL text of the view object query being executed. To see the entire value (often a very long string) more easily, right-click the this.getQuery() entry in the Watches panel and choose View Whole Value . In the View Whole Value dialog box, if the value gets too long, click the Wrap Text check box to see it more easily. Click OK to dismiss the dialog box.
Click the debugger resume button to continue execution. You’ll stop again at the method breakpoint for the execution of the detail view object. In the Watches tab, you can see that the Employees view object instance of type oramag.model.EmpView is being executed. By expanding the params node and then the  node corresponding to the first array element, you can see a single bind parameter named Bind_Deptno whose value is 10. Again, click the debugger resume button to let execution continue.
If the debugger stops a third time, the Stack tab will show that a view object’s bindParametersForCollection() method is also called when asked for an estimated row count. When a view object is performing its estimated row count query, you can verify in the Data tab that the qc parameter is null. Click the resume button again to continue execution.
Fine-Tuning Your Breakpoints
For an application that involves tens or hundreds of view objects, a method breakpoint that stops when each view object executes might cause a maddening number of stops. You can use two additional Oracle JDeveloper features to fine-tune how the breakpoint behaves.
You can make the breakpoint conditional on a Boolean expression, so that it stops only when that expression is true. For example, you can edit your existing bindParametersForCollection method breakpoint so that it stops only when the view object instance’s name is Employees. To accomplish this, right-click the breakpoint on the Breakpoints tab and choose Edit . In the Edit Method Breakpoint dialog box, select the Conditions tab, and in the Condition field, enter "Employees".equals(this .mObjName)&&qc!=null and then click OK . Return to Oracle Business Components Browser , right-click the WorksInDeptLink1 node, and choose Re-execute Query . You can see that the debugger stops, and using the Watches tab, you can verify that it has stopped only for the execution of the Employees view object instance. Click the debugger resume button to let execution continue, and then click the debugger resume button once more if necessary.
As a final step, you’ll modify the method breakpoint to print information to the log instead of halting execution. This can be useful for crafting your own targeted diagnostic information, which you can search through later. Start by editing the method breakpoint again in the Breakpoints tab. On the Conditions tab, remove the conditional expression you added earlier so that the log message appears for every view object execution. On the Actions tab, uncheck the Halt Execution check box, and in the Expression field enter getQuery() and click OK . If you are still stopped at a breakpoint, click the debugger resume button. Then re-execute WorksInDeptLink1 in Oracle Business Components Browser as before to cause the master and detail view objects to requery. Select the Debugging: Model.jpr - Log tab to see the console log, which now includes the query statements of the view objects that have executed.
When you use the techniques you’ve learned in this column to debug your own applications, remember that the debugger watch expressions, breakpoint conditional expressions, and expressions to log in to the console can involve any combination of member fields, method calls, and Java operators. You should be able to devise creative ways of using them in your troubleshooting. For more information, see chapter 29, “Testing and Debugging ADF Components,” in Oracle Fusion Middleware Fusion Developer’s Guide for Oracle Application Development Framework 11g.
Steve Muench is a consulting product manager for Oracle JDeveloper and an Oracle ACE. Since 1990 he has developed and supported Oracle tools and XML technologies and continues to evangelize them. Muench coauthored Oracle ADF Developer’s Guide for Forms/4GL Developers (Oracle, 2006), wrote Building Oracle XML Applications (O’Reilly Media, 2000), and shares tips and tricks on OTN and in his Dive into ADF blog.