debugging oaf application

25
Overview 1

Upload: isekars

Post on 22-Nov-2014

129 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Debugging OAF Application

Overview

1

Page 2: Debugging OAF Application

OverviewHere, you'll learn how to investigate and resolve typical OA Framework problems using the debugger. For additional information about this subject, see Debugging OA Framework Applications in the Developer's Guide.

Debugging Lab GoalsAfter completing this exercise, you should have learned how to:

Use source, method and class breakpoints in local project code, and in the underlying technology stack (OA Framework classes).

Debug three common exceptions: java.lang.NullpointerException, java.lang.ClassCastException and oracle.jbo.SQLStmtException.

Extract salient information from a stack trace. Read and use the call stack. Explore application module retention behavior using the debugger. Navigate the data structures of key OA Framework and BC4J classes using the

debugger.

Debug Lab Application IntroductionHere, you'll be working with a special "debug application" that was built to include errors for you to find.Note: This application is optimized for the purposes of this lab. It does not fully comply with BLAF UI Guidelines or the OA Framework coding standards. For example, you'll see some controller code that sets a web bean property that should be set declaratively. The code is included specifically so we can introduce exceptions. This code should not be used as a model for production code.The debug lab "application" is included in the LabSolutions project, and it includes the following components:File Descripti

onoracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugLabSearchPG Search for

employees page.

oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugSearchCO Controller for search region.

oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugSearchResultsCO

Controller for results region.

oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugLabCreatePG Create employee page.

oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugLabCreateCO Controller for create page.

2

Page 3: Debugging OAF Application

oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugLabAM Application module for debug search and create pages.

oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugEmpFullVO View object used in debug create page.

oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugEmpSummaryVO

View object used in debug search page.

oracle.apps.fnd.framework.toolbox.schema.server.EmployeeEOImpl (and its associated expert, validation application module and validation view objects)

Employee entity object.

oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugAPG Page used in state management debug task.

oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugBPG Page used in state management debug task.

oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugALabAM Application module for state management debug task.

oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugBLabAM Application module for state management debug task.

3

Page 4: Debugging OAF Application

PrerequisiteHere, ensure that your OADeveloperMode project option is enabled as described in Step 2 of the Hello, World! lab.If this is not enabled, you will not be able to access the error stack as intended in this lab.

4

Page 5: Debugging OAF Application

Task 1: Investigate Unexpected Code Execution (Part 1)Throughout this lab we ask that you run the test_fwklabsolutions.jsp instead of running the lab pages directly. When you debug your product code, you should do the same because of subtle runtime differences between these methods (launching from a test JSP more closely approximates production deployment). Furthermore, running the test JSP gives you a convenient stopping point for setting breakpoints before accessing "broken" pages, and it lets you navigate more freely around your application with the menu present.

In the LabSolutions project, run test_fwklabsolutions.jsp in debug mode. Select the Debug Lab link when the test page renders. When the Search page renders, select the Go button to perform a blind query (this page

does not comply with the coding standards that prohibit blind queries!). Note that no results are displayed in the table.

Add breakpoints to the following source code (use the instructions provided in the Hello, World! lab if you need them).

o In oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugSearchCO, add a breakpoint inside the processFormRequest method at this line of code: super.processFormRequest(pageContext, webBean);

o In oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugLabAMImpl, add a breakpoint inside the initQuery method at this line of code: DebugLabEmpSummaryVOImpl vo = getDebugLabEmpSummaryVO1();

o In oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugEmpSummaryVOImpl, add a breakpoint inside the initQuery method at this line of code: StringBuffer whereClause = new StringBuffer(100);

Select the Go button again.At this point, you'll notice that your processFormRequest method isn't called at all. Can you figure out why this isn't happening and fix it? See the corresponding Task 1 solution if you need help. Note that you cannot test your fix (you'll encounter the NullPointerException planned for Task 2). For now, simply make the required change and terminate your OC4J process.Tip: You must fix each error in sequence before moving on to the next task.

5

Page 6: Debugging OAF Application

Task 2: Resolve a NullPointerException (NPE)In this task, you'll resolve one of the most common exceptions that you'll encounter: a java.lang.NullPointerException. This means you tried to invoke a method on a variable that has not been initialized.

Run test_fwklabsolutions.jsp in debug mode. Select the Debug Lab link when the test page renders. Note that a standard OA

Framework error page displays as shown in Figure 1.Figure 1: Example of an OA Framework Error Page

This generic error page renders whenever an unexpected exception is thrown. To access additional information about the error so you can debug it, select the here link. The OA Framework then displays the complete stack trace associated with the uncaught exception (a "stack trace" is a snapshot of the code execution path at the point where the exception is raised). Don't be daunted by the size of the stack trace; most of the content is superfluous for your debugging purposes. To find the nugget of information that you need to proceed, look for the text ## Detail 0 ## in the stack trace and read the exception data that immediately follows it.For this particular error, Figure 2 shows that a NullPointerException was raised in the processRequest method at line 38 in the oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugSearchCO class.Figure 2: ## Detail 0 ## Stack Trace Information for a NullPointerException

Tip: Fortunately, when using the JDeveloper packaged for Oracle Applications, debug information is compiled into the code so line numbers are provided in the stack trace. If you work with a stack trace that doesn't contain explicit line numbers, you need to create an exception breakpoint as shown in Task 4 below. Since we know exactly what the source of the NullPointerException is, we don't need to bother creating an exception breakpoint (you can always create one later if you need it). Instead, we can go right to the broken source code as shown in Figure 3 below. In most cases, you can simply glance at your code and figure out why the object you expected to be instantiated (in this case, an OAMessageTextInputBean) is null.

6

Page 7: Debugging OAF Application

Figure 3: Source of the NullPointerException

Try to figure out what is wrong with this code so you can fix it. If you need help so you can proceed, see the corresponding Task 2 solution.Proceed to Task 3 before testing your fix.

7

Page 8: Debugging OAF Application

Task 3: Resolve a ClassCastExceptionIn this task, you'll resolve another common exception: a java.lang.ClassCastException. This means you tried to perform an invalid cast from one object type to another. Tip: If you're relatively new to Java and need additional information about class casting, please check the following for tutorials, documentation and book suggestions:

Oracle Technology Network JavaSoft Java Developer Connection

To proceed: Run test_fwklabsolutions.jsp in debug mode. Select the Debug Lab link when the test page renders. Note that a standard OA

Framework error page displays as shown in Figure 1 above. Select the here link to access the stack trace, and look for ## Detail 0 ## as shown in Figure 4 below.

Figure 4: ## Detail 0 ## Stack Trace Information for a ClassCastException

This tells us that we have a ClassCastException at line 37 in the processRequest method of the oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugSearchCO class. It also tells us that the class that we're incorrectly casting is oracle.apps.fnd.framework.webui.beans.message.OAMessageLovInputBean (this is the "message" part of the exception). In other words, we have an OAMessageLovInputBean that we're trying to cast to something else, and it's not working.Figure 5 shows the code at line 37 that is causing the exception. Try to figure out what is wrong with this code so you can fix it. If you need help so you can proceed, see the corresponding Task 3 solution.Figure 5: Source of the ClassCastException

8

Page 9: Debugging OAF Application

Task 4: Resolve a SQLStmtExceptionIn this task, you'll resolve a problem with the SQL statement that you try to execute when searching for employees.

Run test_fwklabsolutions.jsp in debug mode. Select the Debug Lab link when the test page renders. Select the Go button to perform a blind query. Note that query results are properly

displayed. Enter the value "1" in the Employee Number field, and select the Go button. The error

message shown in Figure 6 displays at the top of your page. This tells you that there is "something" wrong with the SQL statement you tried to execute, but it doesn't give you enough information about what you need to fix. For this, we need an exception breakpoint so we can dig a little deeper into the problem (exception breakpoints are essential if you need more information about the code that was executed before the exception is thrown, and you want to explore code state at the point where the exception is thrown).

Tip: The generic OA Framework error page doesn't display in this case because the underlying exception is caught and "packaged" by BC4J as a user-friendly error message to be displayed at the top of the page. Figure 6: SQLStmtException Displayed in an Error Message Box

To create an exception breakpoint: Place your cursor in the JDeveloper Breakpoints tab shown in Figure 7 below (note that

this tab generally displays only when you run in debug mode, however you can also add a breakpoint when you are not in debug mode by choosing View > Debug Windows > Breakpoints from the main menu).

Right-click and select New Breakpoint... from the context menu. In the New Breakpoint window, set the Breakpoint Type to Exception and set the

Exception Class to the fully qualified name of the exception (in this case,

9

Page 10: Debugging OAF Application

oracle.jbo.SQLStmtException). Select OK to save your breakpoint.

Figure 7: JDeveloper Breakpoints Tab

To proceed, select the Go button again (with your Employee Number search criteria). Assuming JDeveloper has access to the source code, it stops execution at the point where the exception is thrown as shown in Figure 8 below. Specifically, execution halts just before the highlighted line of code.Figure 8: Exception Breakpoint for SQLStmtException

In this case, the exception is being thrown in the executeQuery method in the QueryCollection class. This is reflected in the source code above, and in the call stack (the Stack tab) as shown in Figure 9. The call stack is a useful tool that reflects the code execution path in relation to the current breakpoint (it changes as you step through your code using the debugger). It is particularly helpful if you want to access code that was executed before your breakpoint was reached. So, for example, you might read the following and decide that you want to add a breakpoint in the OAViewObjectImpl's executeQuery method so you can step through the code from this point until you reach the exception. To quickly access the executeQuery method, simply double-click that line in the Stack window to open the corresponding source. Tip: Try right-clicking on the class or method names in the call stack. You'll see several other options that you might want to explore. For example, you can choose Export... to save a copy of the call stack. Figure 9: Call Stack State When the SQLStmtException is Thrown

10

Page 11: Debugging OAF Application

For this particular error, we really don't need to navigate the call stack and add breakpoints at earlier processing points. Instead, we need to examine the exception state to see if it includes additional information that is not included in the message BC4J presents to the user. Figure 10 shows the Smart Data debugging window contents when the SQLStmtException breakpoint is reached. At this level, the exception includes the underlying ORA error, which is much more specific about the root cause of the problem. Now, instead of just knowing that we have a bad SQL statement, we know what to look for: our SQL statement includes the identifier EMPLOYEE_NUMBER, and this is invalid.Try to figure out what is wrong with this code so you can fix it. If you need help so you can proceed, see the corresponding Task 4 solution.Note: When you know your code well, you can often solve these problems by simply reading your SQL statement as shown in the original error message in Figure 6 above. It's worth getting in the habit of looking at this quickly before bothering to debug the code since the problem may be obvious to you.

11

Page 12: Debugging OAF Application

Figure 10: Smart Data Window Showing Code State

Tip: When execution stops on the initial exception throw, and you select the Resume debugging action, JDeveloper halts each time this exception is rethrown in the call stack. If you don't need additional information about how this exception is handled throughout the call stack, you can always disable the breakpoint after the initial exception is thrown to save yourself some time. Select the breakpoint in the Breakpoints window, right-click and select Disable Breakpoint. You can toggle this as needed.Tip: When you create NullPointerException breakpoints, you'll notice that you encounter at least one in the course of normal page processing (for example, AppsConnectionManager throws and handles an NPE). You should simply select the Resume debugging option when you encounter these; the first relevant NPE is likely to be in your code.

12

Page 13: Debugging OAF Application

Task 5: Use a Class Breakpoint In this task, you'll use a class breakpoint to investigate all calls to a single class. This is very useful when trying to learn how an unfamiliar class is used, and is more efficient than setting multiple breakpoints if you have heavy interaction with a given class and want to verify numerous method calls.Tip: If you have problems with view object row initialization when creating new entity object based rows, you might want to use a class method on your entity objects to examine its initialization and data access.To create a class breakpoint:

Place your cursor in the JDeveloper Breakpoints tab. Right-click and select New Breakpoint... from the context menu. In the New Breakpoint window, set the Breakpoint Type to Class and select the

Browse... button next to the Class name field. In the Class Browser window, navigate through the packages and classes until you can

select the target class (in this case, you need to select oracle.apps.fnd.framework.toolbox.schema.server.EmployeeEOImpl). Note that you can also type your class name in directly without having to browse first.

Select OK to save your breakpoint.To execute your class breakpoint:

In the LabSolutions project, run test_fwklabsolutions.jsp in debug mode. Select the Debug Lab link when the test page renders. When the Search page renders, select the Create button.

You'll notice that JDeveloper halts execution every single time a method is called in EmployeeEOImpl and in any of its superclasses so you have a complete picture of how this object behaves (feel free to disable the class breakpoint before stepping through all the method calls!). Please proceed directly to Task 6, but delete or disable your class breakpoint and select the Resume debugging option first.

13

Page 14: Debugging OAF Application

Task 6: Investigate Unexpected Code Execution (Part 2)In the previous task, we used a class breakpoint for a fine-grained look at class usage. While this can be very helpful in some situations, if you're experiencing a failure at a specific point in your code, the class breakpoint provides far more information than you need. In this task, we'll investigate an unexpected validation failure in an entity object.To proceed:

Select the Cancel button in the Create page to return to the Search page. Select the Create button again to return to the Create page. Enter all the required information for creating an employee (don't change the Position

poplist value from President since the page isn't coded to let you enter the Manager value required for the other positions), and select the Apply button. Note that the attribute-level validation error shown in Figure 11 displays.

Figure 11: PositionCode Validation Error

Whenever entity object validation fails at the attribute level, the first thing you should do is set a breakpoint on the corresponding "setter" (in this case, setPositionCode). While you're in the entity object, it's often helpful to put a break point on another "setter" for a value that isn't having problems. Given this, please add breakpoints to the following methods:

oracle.apps.fnd.framework.toolbox.schema.server.EmployeeEOImpl.setPositionCode

oracle.apps.fnd.framework.toolbox.schema.server.EmployeeEOImpl.setLastName (any other setter in the entity object would work just as well)

Tip: You could also define method breakpoints without opening the source code in your project. For example, you could:

Place your cursor in the JDeveloper Breakpoints tab. Right-click and select New Breakpoint... from the context menu. In the New Breakpoint window, set the Breakpoint Type to Method and enter the fully

qualified method name. For example: oracle.apps.fnd.framework.toolbox.schema.server.EmployeeEOImpl.setLastName

Select OK to save your breakpoint.

14

Page 15: Debugging OAF Application

Remember that the OA Framework steps through a data "post back" phase when an HTTP POST request is issued (the OA Framework calls the processFormData method for all items in the web bean hierarchy). All the data on the page is written to the underlying view object(s), which in turn write data to the underlying entity object(s). When you select the Apply submit button, all the entity object setters corresponding to the data you enter on the page should be called.Tip: You might also want to add a breakpoint in the entity object's validateEntity method. After calling all the setters in processFormData, the OA Framework valides each row in the view object that it "dirtied" by setting values. If you add this breakpoint, you'll see when the entity-level validation is performed.For additional infromation about how and when data is read from and written to the server from the UI, please see Implementing the View: Model Interaction in the OA Framework Developer's Guide.To execute your breakpoints:

Select the Cancel button in the Create page to return to the Search page. Select the Create button again to return to the Create page. Enter all the required information for creating an employee (don't change the Position

poplist value from President since the page isn't coded to let you enter the Manager value required for the other positions), and select the Apply button.

You'll notice that the setPositionCode method is NOT being called -- even though a value is clearly selected in the poplist -- while the setSalary method is being called correctly. Think about what might be wrong here so you can fix it. Start with your page definition, and consider what must be defined correctly for the position value to be written to the entity object attribute. If you need help, see the corresponding Task 6 solution.Tip: When you've been debugging for a while, you often accumulate many breakpoints. When you're ready to move on, you might want to use the Breakpoints window context menus option Disable All or Remove All to quickly disable or delete your breakpoints.

15

Page 16: Debugging OAF Application

Task 7: Explore Application Module Retention BehaviorIn this simple exercise you'll use the debugger to explore application module retention behavior while navigating between two pages. For additional information about this, see OA Framework State Management in the Developer's Guide.

Step 7.1 Create Breakpoints Open oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugAPageCO and

add a breakpoint at the following line of code in processRequest: boolean isNew = pageContext.isAMStateNew(); The isAMStateNew() method in oracle.apps.fnd.framework.webui.OAPageContext is a convenient way for your controller code to see whether the application module state is new, or whether a cached application module with existing state was used for the page (in other words, the application module was retained).

Open oracle.apps.fnd.framework.toolbox.labsolutions.webui.DebugBPageCO and add a breakpoint at the following line of code in processRequest(): Boolean isNew = pageContext.isAMStateNew();

Create a method breakpoint using the technique described above. The fully qualified method name to use is oracle.apps.fnd.framework.server.OAApplicationModuleImpl.beforeRelease. The beforeRelease() method in oracle.apps.fnd.framework.server.OAApplicationModuleImpl is called just before an application module's state is reset. So, if you opt to release an application module instead of retaining it, the OA Framework will call this method just before it releases the application module.Tip: Remember that all application modules extend OAApplicationModuleImpl, so at runtime, this method will actually be called for the subclasses created for this lab: oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugALabAMImpl and oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugBLabAMImpl.

Step 7.2 Perform Test #1 In the LabSolutions project, run the DebugAPG page in debug mode (you need to run

this directly; it is not accessible from the test_fwklabsolutions.jsp). When your first breakpoint is reached in DebugAPageCO, toggle the Data debugging

window from the default Smart Data tab to the Data tab as shown in Figure 12 below. Use the Step Over debugging option to execute each line of code in the

processRequest method. Note the state of the isNew, aVal and bVal variables in the Data window. After executing the code that sets the transaction "APageValue" value, select the Resume debugging option so the page can render.

When the page renders, select the Page B (Retain AM) submit button. This will perform a JSP forward to the DebugBPG page with the retainAM request parameter set to true.

Figure 12: Data Window State When DebugAPG Initially Renders

16

Page 17: Debugging OAF Application

When you reach the DebugBPageCO processRequest breakpoint, carefully execute each line of code and note the state of the isNew, aVal and bVal variables. You'll notice that the isNew value is set to true, meaning that the application module state for this page is new. Since we retained the AM when navigating to this page (check the processFormRequest method in DebugAPageCO for confirmation), wouldn't you expect this value to be false? Why might it be true? Also, if we saved the aVal value on the transaction, why is it null? See the Task 7, Test 1 solution if you need help. Note: do not stop running or make any changes to the code at this point.

When the DebugBPageCO renders, select the Debug A (Retain AM) submit button. This will perform a JSP forward back to the DebugAPG page with the retainAM request parameter set to true.

Again, use the debugger to step through the processRequest code and check the state of the isNew, bVal and aVal variables. You'll notice that isNew = false, and aVal = "A". Can you explain this? See the Task 7, Test 1 solution if you need help.

When DebugAPG renders, this time select the Page B submit button. This will perform a JSP forward back to the DebugBPG page with the retainAM request parameter set to false.

At this point, JDeveloper will halt execution at the beforeRelease method in the OAApplicationModuleImpl source. However, if you look at the "this" pointer in the Data window (for those who are new to Java, "this" iterally means "this object" -- a reference to the current object), you'll see that the object type is actually DebugBLabAMImpl.

Select the Resume debugging option, and note that you again enter the beforeRelease method for DebugALabAMImpl. When you set the retainAM request parameter to false, ALL root UI application modules that are currently cached (retained) are released.

17

Page 18: Debugging OAF Application

Figure 13: Data Window State When beforeRelease Breakpoint is Reached

Step 7.3 Perform Test #2 Terminate the current OC4J process and change the AM Definition property of

PageLayoutRN region in DebugBPG to oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugALabAMImpl.

Run DebugAPG in debug mode. Step through the processRequest code noting the variable states, and when the page renders, select the Debug B Page (Retain AM) submit button. Again, the code performs a JSP forward to the DebugBPG while retaining the application module.

Before you debug the processRequest method in DebugBPG, what do you expect the isNew, aVal and bVal variable values to be? Step through the code and see if you were right. If you were wrong, and you're not sure why, see the Task 7, Test 2.

Try navigating back and forth between the pages using the buttons with the "Retain AM" label. Your cached DebugALabAM and its state remains intact.

Tip: In this test, both pages are using the same application module instance. Another way to verify whether pages are using the same instance of the same application module type is to check the object's memory address (it's internal unique identifier). To do this, double-click the "this" Name or Type value in the Data window (shown in Figure 13 above). This opens a Modify Value window with the Current Value set to the objec'ts memory address.Figure 14: DebugLabAMImpl Object's Memory Address

18

Page 19: Debugging OAF Application

Task 8: Resolve a Common Missing ImportThis task doesn't involve the use of the debugger, but it walks you through a common mistake that can be difficult to understand if you've not seen anything like this before.

Open oracle.apps.fnd.framework.toolbox.labsolutions.server.DebugLabEmpFullVOImpl and comment out the oracle.jbo.domain.Number import.

Rebuild the LabSolutions project; notice that you get the following compilation error: Error(34,28): class java.lang.Number is abstract; cannot be instantiatedWhenever you use a Number in an OA Framework application, you must remember to import oracle.jbo.domain.Number. If you fail to do this, the compiler assumes that this is a java.lang.Number class (the java.lang classes are automatically included, which is why you don't have to explicitly import commonly used classes like String). In this particular code example, we are attempting to instantiate a Number class so we're getting the error shown above. Alternatively, you might define a Number member variable without explicitly instantiating it, and you'll get a runtime error when you try to set the value. Just try to remember to always import oracle.jbo.domain.Number when you need it, and if you experience problems related to Numbers in your code, always remember to check your imports before spending a lot of additional time debugging this.

19

Page 20: Debugging OAF Application

Task 9: Investigate Unexpected UI ResultsSometimes, debugging won't help you solve a problem because nothing's actually wrong with the code. The downside of working with a "black box" that does a lot of the work for you -- particularly when you "code" declaratively -- is sometimes the smallest oversight on your part leads to an unexpected result.For example, you might have noticed that a header line is rendering above the Employee Number field in the debug lab Create page (see Figure 15). While something like this might be a bug, it's more likely to be caused by an incorrect property setting. Although a bit tedious, the only thing you can really do in this case is carefully inspect all the property settings for the regions and/or items related to the undesirable HTML. If you're uncertain about how various property settings affect the corresponding HTML, see the JDeveloper OA Component Properties documentation for a description of each property by region and item type. Also see the various UI implementation topics in Chapter 4 of the OA Framework Developer's Guide. Do you know why this line is rendering? Do you know how to stop it? See the Task 9 solution if you need help.Figure 15: Unwanted Header Line Above the Employee Number Field

Congratulations! You are now finished with this lab.

20