61
ADF Tips and Tricks ADF : Change the Iterator Range size Database Views : Establish good naming conventions ADF Client : Establish good packaging conventions Dynamic / API Use of ADF Components Getting the application module of a panel Binding to Swing components Binding dynamically created ViewObjects to ADF Swing Components ' Unexplained ' problems do have causes Dynamic ADF : Create a View Object from a SQL Statement Setting Custom Properties and UI Hints on Dynamically Created View Objects ADF - SM Blog : ADF : JClient Login Dialog JDeveloper ADF Components and Refactoring Rebuidling Class Folder Renaming a JDeveloper Project DataBindings . cpx Connections . xml Rename a page definition Create a data control from a CSV file or a URL ADF JClient : Showing a splash screen when starting ADF JClient applications How to get the row index of a JTable row with a checked checkbox in it Set a checkbox in a ADF JTable ADF JPanels Working with Multiple Panels that bind the same Page Definition Working with Embedded ADF Swing Panels ADF JPanel Dialogs Framework for adding ADF Dialog panels ADF Method Dialog Workaround #1 ADF Method Dialog Workaround #2 Respond to Errors in Method Calls ADF Check Boxes Check Box in a Table Check Box for marking table selections ADF Master - Detail Forms Customizing Auto - generated M - D Forms

ADF Tips and Tricks

Embed Size (px)

DESCRIPTION

Oracle Application Development Framework (ADF) is a powerful data binding framework for building web and desktop applications that store, retrieve and manipulate records in a relational database. I have used ADF and its associated Swing components to build a variety of applications which I usually deploy as WebStart applications. This document includes useful notes and how-to 'tips and tricks' that I have either developed personally, or I have gathered from other sources on the web. Note that as of Summer 2011, Oracle has announced the deprecation and eventual abandonment of the ADF-Swing components. Their intend is to focus singly on ADF bindings for web application development.

Citation preview

Page 1: ADF Tips and Tricks

ADF Tips and TricksADF: Change the Iterator Range sizeDatabase Views: Establish good naming conventionsADF Client: Establish good packaging conventions

Dynamic/API Use of ADF ComponentsGetting the application module of a panelBinding to Swing componentsBinding dynamically created ViewObjects to ADF Swing Components'Unexplained' problems do have causesDynamic ADF: Create a View Object from a SQL StatementSetting Custom Properties and UI Hints on Dynamically Created View ObjectsADF-SM Blog:ADF: JClient Login Dialog

JDeveloper ADF Components and RefactoringRebuidling Class FolderRenaming a JDeveloper ProjectDataBindings.cpxConnections.xmlRename a page definitionCreate a data control from a CSV file or a URLADF JClient: Showing a splash screen when starting ADF JClient applicationsHow to get the row index of a JTable row with a checked checkbox in it

Set a checkbox in a ADF JTableADF JPanels

Working with Multiple Panels that bind the same Page DefinitionWorking with Embedded ADF Swing Panels

ADF JPanel DialogsFramework for adding ADF Dialog panelsADF Method Dialog Workaround #1ADF Method Dialog Workaround #2Respond to Errors in Method Calls

ADF Check BoxesCheck Box in a TableCheck Box for marking table selections

ADF Master-Detail FormsCustomizing Auto-generated M-D Forms

Page 2: ADF Tips and Tricks

ADF JUNavigationBarSet which buttons to show

ADF LOV PopupssetHelpActionListening to Navigation Events in the LOV Dialog

ADF ComboboxesSelections from ComboBox in ADF Tables

ADF TablesSelections from ComboBox in ADF Tables (see example below)

ADF TreesRecord Navigation using ADF JtreeRecreating ADF Tree Bindings for a new Swing treeRenaming ADF Tree Root nodesSaving and restoring a Hierarchical TreeRestoring the Last Selected NodeDetecting the type of the Current NodeHierarchical ADF Trees

Additional hierarchy levelsTree Node Binding: View link Accessor RowsetsADF Trees are not bound to ViewObject Instances but to their DefinitionsManual Editing of Tree Node BindingFolder Labels for ADF Tree Nodes.Expanding an ADF filtered tree nodeFiltering an ADF Hierarchical TreeSearch a Rendered ADF Bound TreeSearching an ADF Hierarchical TreeHow to use a partial branch of ADF View TreeRefreshing ADF Tree ObjectsHow to add a context menu on an ADF Tree

PanelBindingView Objects

How to programmatically populate a newly added view object row?Programmatically iterating over the RowSet of a viewViewObjects Come Up BlankView Object Bind Variables and Bind Variable Default ValuesFind a ViewObject Row by KeyUse a ViewLink to Access the Details of a Nested Collection or Nested Row

Page 3: ADF Tips and Tricks

Performing In-Memory Sorting and Filtering of Row SetsRecovery from Error Saving ViewObject XML file after UpdatesView Object Based on * queries

View CriteriaViewCriteria UsageNotes

Create and Apply ViewCriteriaRemove ViewCriteriaShould new ViewCriteria appended to the list of already applied view criteria?Is a view Object Filtered by some View Criteria?

How to use Named View CriteriaHow to use Dynamic Named View Criteria

Application ModuleWorking with multiple ApplicationModulesManual way to bind an AppModule Custom MethodHow to Access an Application Module Client InterfaceConnecting to a second database using a database linkConnecting to a second database using another project's application moduleConnecting to a different database by adjusting application module properties

Login and AuthenticationUsing database tables for authentication in ADF applications

ADF Eye CandyInclude Images in Swing Forms

QUESTIONSUNRESOLVED ISSUES

Creating Shuttle Component in Oracle ADFTree Binding fails after opening in Dialog more than once

Workarounds to Some JBO ExceptionsJBO-35001JBO-27022JBO-2900JBO-25001

Page 4: ADF Tips and Tricks
Page 5: ADF Tips and Tricks

ADF Tips and TricksSee also:● Oracle ADF Documentation ● Steve Muench blog (accessed DEC-01-2011)

ADF: Change the Iterator Range size

What does it do: affects how many entries can be seen in a combo box list

Target: the panel PageDef.xml page definition file

How: Change the RangeSize from the default 10 to -1 (for all)

Example: <iterator id="UIcbResult_NUMattrsIterator" RangeSize="-1"

Binds="UIcbResult_NUMattrs"

DataControl="am_createExecutableAnalysisSupportDataControl"/>

Database Views: Establish good naming conventions

What does it do: Allows one to easily understand what database views are used in the UI as opposed to other places. Greatly aids in system documentation

Target: ADF view objects and their corresponding database views

How: prepend an indicative suffix to database view names

Example: All view used for the MASSterMine client UI are indicated as V_NAME

ADF Client: Establish good packaging conventions

What does it do: Allows one to easily understand the Business component requirements for various UI components

Target: MODEL/VIEW packages

How: Establish MODEL packages that are common among UI components and keep all dependent Entity/View/Link Object definitions together. If an ADF component is specifically used in a UI component and is not shared, keep it in a MODEL side package that is named similarly to the one on the VIEW side. Keep definitions of dependent Entity/View/Link ADF objects together in the same package

Page 6: ADF Tips and Tricks

See also: 'An Introduction to ADF Best Practices' an Oracle white paper (July 2006)

Dynamic/API Use of ADF Components

Getting the application module of a panel

What does it do: Gets the appModule that a panel is bound to. This is required when subsequent steps need to create other ADF components such as view objects and iteratorsTarget: Java source codeHow: Call the appropriate methods on the JU Swing panel Example:panelAM=(ApplicationModule)this.panelBinding.getDataControl().getDataProvider();

Binding to Swing components

What does it do: Allows dynamic ADF components to provide data binding to Swing UI componentsTarget: Java source codeHow: see: Frank Nymphius http://www.orablogs.com/fnimphius/archives/001694.html Example:JUIteratorBinding iterBinding=getIteratorBinding(p0);panelBinding.addIterBinding("iter"+p0, iterBinding);JUTableBinding tblBinding = new JUTableBinding(log_jTable, iterBinding, null);log_jTable.setModel((TableModel)tblBinding); The above example binds a Swing table (log_jTable) to a TableModel created form the JUTableBinding

Binding dynamically created ViewObjects to ADF Swing Components

Yesterday I answered a question on the JDeveloper discussion forum on OTN about binding ViewObjects that are dynamically created based on a SQL query to ADF Swing.It will take some time for me to write this down in a proper howto format, so I though it would be a good idea to put it out here first.After implementing the steps outlined here, you will be able to add a SQL query to a text field and have the result set shown in a JTable component. A JUNavigationBar can be used to scroll through the records To create the application1. Create a Business Components project with an ApplicationModule and at least one

ViewObject2. Create an ADF Swing project3. Create an empty ADF Swing panel and make it runnable4. To create all required entries in the DataBindings.dcx file, drop an existing ViewObject

Page 7: ADF Tips and Tricks

from the data control palette and choose Table from the ADF menu. Delete the table immediately from the Swing panel. You can also manually create the DataControl binding to the ApplicationModule, but this takes longer to finish ;-)

Page 8: ADF Tips and Tricks

5. Add a JScrollPane from the Component Palette and place a JTable component into it6. Add a JUNavigationBar Component from the "ADF Swing" selection of the Component

Palette7. Add a text field for query input and a button to execute the query8. In the example code the following names are used for the components

○ JTable: myQueryTable○ JUnavigationBar: myQueryTableNavigationBar○ JTextField: qryText

9. Create a method that looks as follows: private void populateADFSwingComponentsFromQuery(String qstmt) { //get ApplicationModule using ADF data provider API ApplicationModule am = (ApplicationModule) panelBinding.getApplication().getDataProvider(); //if dynamic view object exists, delete it try{ am.findViewObject("myView").remove(); } catch (Exception e){} ViewObject myView= am.createViewObjectFromQueryStmt("myView",qstmt); DCJboDataControl jbodc = new DCJboDataControl(am); JUIteratorBinding iterBinding = new JUIteratorBinding(jbodc,myView ); JUIteratorBinding testIter = (JUIteratorBinding) panelBinding.findIteratorBinding("dynamicSql"); try{ panelBinding.removeIteratorBinding("dynamicSql"); } catch (Exception e){} panelBinding.addIterBinding("dynamicSql", iterBinding); JUTableBinding tblBinding = new JUTableBinding(myQueryTable, iterBinding, null); myQueryTable.setModel((TableModel)tblBinding); myQueryTableNavigationBar.setModel(iterBinding); }

10. from the query button call private void qryButton_actionPerformed(ActionEvent e) { this.populateADFSwingComponentsFromQuery(this.qryText.getText()); }

Thanks to Sathish and Shailesh from the development team for looking into this.FrankPosted by Frank.Nimphius at March 7, 2006 01:34 AM My Usage Notes: In one case I had somewhat unpredictable behavior trying to get this to work.The added JTabbedPane did not show the dynamic table. I ended up embedding the same panel with a design time ViewObject binding so that I could first see it, and then removed the binding and added a call to the populateADFSwingComponentsFromQuery . This

Page 9: ADF Tips and Tricks

appeared to work Help Using Navbar Find mode with dynamic viewobjects,Posted: Aug 23, 2006 6:22 AM What needs to be added to my coded to make the JUNavigatorBar QBE function in the "ADF Swing: Binding dynamically created ViewObjects to ADF Swing" example posted by Frank Nimphius on March 07, 2006. My table loads from the dynamic viewobject and the Navbar moves the cursor over each row in the table but when I go into Find mode ,the table row for entering the search criteria is not editable. I must be missing something basic here, but I am at a lost for the solution.

Ok, I found this solution to make the dynamic view objects example 'searchable' from the NavigatorBar 'Find' button. I had to extend and replace the JUTableBinding class when creating a TableBinding which is then set as the model for my dynamic JTable using .setModel(); The rest of the example code works without modification. class MyJUTableBinding extends JUTableBinding{public MyJUTableBinding(javax.swing.JTable control,JUIteratorBinding iterBinding,java.lang.String[] attrNames){super(control, iterBinding,attrNames);}public boolean isCellEditable(int row, int col) {return true;}}

'Unexplained' problems do have causes

A view no longer updates when you dynamically set its current row

Make sure that you are using attributes from the right data controls and NOT from a different Application Module. It's easy to get confused if you have been working on similar projects and similarly named views exist in other application modules. A good place to examine this is DataBindings.cpx file. Attributes from a different application module add a new BC4JDataControl element. Examine this section closely to make sure that only a single BC4JDataControl element exists, if that's what you wanted! Also, examine closely the DataControls in the PageDef of embedded panels, since it could be them causing the problem.

New Java WebStart Wizard Fails to ID DataModel Definition

Also trying to continue by defining a <New..> does not proceed past the first step

Page 10: ADF Tips and Tricks

It seems that I had commended out (but did not remove) an <BC4JDataControl> element in the DataBinding.cpx file. I needed to physically delete this element (and not just commend it out) before the wizard would proceed.

[March 6, 2010] Receiving a bunch of non-informative JBO-2900 errors.

Check for remnants of deleted pages that exist in the DataBinding.cpx file. The <pageDefinitionUsages> elements are not cleaned appropriately when a page is deleted.

Occasionally these errors re-appear. I have not been able to find what really causes them. However, if you open the DataBindings.cpx file and reformat the code (right click on source and reformat) the errors frequently resolve! (go figure!)

Dynamic ADF: Create a View Object from a SQL Statement

What does it do: Creates a read only view object from a SQL statementTarget: Java source codeHow: Call the createViewObjectFromQueryStmt method on the ApplicationModule. See javadoc for interface ApplicationModule Example: ViewObject vo = am.createViewObjectFromQueryStmt("MyVO", "SELECT EMP.ENAME as EmpName, EMP.MGR as EmpMgr FROM EMP");

In this example, the resulting view object will have two attributes, named EmpName and EmpMgr. Internally, this method create a temporary view definition with no entity object base and maps database columns to attribute definitions. Then, it uses that view definition to create the view object.

Setting Custom Properties and UI Hints on Dynamically Created View Objects[accessed DEC-01-2011] ADF-SM Blog:

71.Dropdown Lists in Table with Different Choices per Row [10.1.3, HR schema]

ADF: JClient Login Dialog

See on line help on how ro create one (no longer available as of Oct-06-2010) http://forums.oracle.com/forums/thread.jspa?messageID=1399987&#1399987

Page 11: ADF Tips and Tricks

JDeveloper ADF Components and Refactoring

Rebuidling Class Folder

[NOV-01-2010]This is a good idea so that old ADF components get a chance to get cleaned-up. Otherwise, they 'fester' and may eventually lead to some strange problems (where removed or incorrect components still work using left-over ADF components (suach as PageDef xml files) in the class folders. I have lost many hours trying to recover from these after I accidentally deleted the adfsrc folder which required checkout from SVN.

Renaming a JDeveloper Project

August 26, 2008 Note: A JDev project is nested inside an application workspace.

1. Open the Application workspace node and select the Project to be renamed. From the JDev menu select File->Rename

2. The project is renamed, BUT not the project directory. Exit JDev.3. Rename the project directory manually4. Re-Open JDEv.The new project directory does no immediately appear in the

application workspace5. Go on the applications node and <Add to applications>. Navigate to the renamed

directory and add the renamed project. TODO: identify where the directory information is persisted on the file systemDONE: index.xml in folder C:\DEVTOOLS\ORACLE\JDEV\jdev\system\oracle.ide.10.1.3.40.66\projectsSo this is where we can rename the folder as well but it appears that the process above is the right way to do this.Of course there might still be dependencies in files like the ant build file (ctbuild.xml) that will need to be updated

DataBindings.cpx

Oracle Ref Oracle JDeveloper 11.1.1.0.2 NoteI had this file update from the SVN repository using the build-in SVN plugin. When I attempted to run the ADF application it complained about a missing PageDef that was added during the file update. So it was there but not detected. I had to shut down JDev and restart it to make this change visible.

Connections.xml

Page 12: ADF Tips and Tricks

This file maintains connection properties. Can be found in .adf/META-INF directory (on the source side). It is copied to the META-INF directory on the class folder. There ate two similarly named files one maintaining the jdbc connections and the other those for URL/CSV files used in data controls (see below)

Rename a page definition

December 10, 2009The technique described in "Working with Multiple Panels that bind the same Page Definition" can also be used to rename the page definition of a page. This is useful when one wants to start a new panel by duplicating an existing one. Although you can use the refactoring operations of a class to duplicate a panel, the operation DOES NOT create a new pageDef.xml but rather binds both panels to the same pageDef file (which typically is NOT what you want). So a new pageDef.xml has to be created and bound to the panel as described above.

Create a data control from a CSV file or a URL

Note that the CSV file needs to be on web server Here is an example:http://biemond.blogspot.com/2007/11/yahoo-maps-with-csv-and-ws-url.html I developed a similar example that worked using JDev 10.1.3.4 (earlier version was throwing an exception) Start by creating a 'URL data Control'

Page 13: ADF Tips and Tricks

File must be accessible via HTTP

The created DataControl is added to the list of data controls and can be used in an ADF Swing component (drag and drop)

Page 14: ADF Tips and Tricks

Create an ADF Swing Table and run

Page 15: ADF Tips and Tricks

ADF JClient: Showing a splash screen when starting ADF JClient applications

[copied comments] Performance is not only a figure that can be physically measured for each application, it also describes end-user perception.If the end-users perception of a starting application is that it runs slow, no matter how good your arguments are to justify the time needed to launch an application, you can't win this fight. However, if you can't deal with them, trick them! One way of making your Java applications appear starting fast is to use a splash screen up front. This kind of 'end-user entertainment' is commonly used by many kinds of applications and also easy to implement with ADF JClient, using the splash screen solution published on www.javapractices.com. I tried it with ADF JClient in Oracle JDeveloper 10g and it just works great.To implement it, I created a private method as follows to instantiate the Splash screen and called it first thing in the try/catch block of the ADF JClient application classes' main method: private static void showSplashScreen(){ fSplashScreen = new SplashScreen("/Images/splash.gif");fSplashScreen.splash();}The image file "splash.gif" is the code above is expected to be in the directory "Images", which is a subdirectory of the project's "src" directory.Make sure that the "splash.gif" image gets added the JDeveloper project so that it gets deployed with the application source files during compilation.To close the Splash screen in a thread safe manner, create an inner class: private static final class SplashScreenCloser implements Runnable{

public void run(){ fSplashScreen.dispose();}

} and call it at the end of the try block and the catch block, or using the finally block of the try/catch block construct.EventQueue.invokeLater( new SplashScreenCloser() );FrankPosted by Frank.Nimphius at 01:53 AM

Page 16: ADF Tips and Tricks

How to get the row index of a JTable row with a checked checkbox in it

Code by Frank Nymphius TableColumnModel tcm = jTable1.getColumnModel();JUTableLOVEditor jTableLOVEditor = (JUTableLOVEditor) tcm.getColumn(0).getCellEditor();JComboBox component = (JComboBox) jTableLOVEditor.getComponent();component.addFocusListener(new FocusListener(){public void focusGained(FocusEvent e) {DCIteratorBinding dciter = (DCIteratorBinding)panelBinding.get("EmployeesView1Iterator");System.out.println(dciter.getCurrentRowIndexInRange());}public void focusLost(FocusEvent e) {}});

Set a checkbox in a ADF JTable

Here is a code snippet: Code Snippet Comments

ancestorPropertyTable.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

1. Set the table selection model

private void checkSelectedButton_actionPerformed(ActionEvent e) { int[] vInt =ancestorPropertyTable.getSelectedRows(); System.out.println("Selected Rows:"+vInt.length); for (int i:vInt){ //now get corresponding model row int m= ancestorPropertyTable.convertRowIndexToModel(i); ancestorPropertyTable.getModel().setValueAt(1,m,0); } ancestorPropertyTable.repaint(); }

1. Return an array of the selected rows

2. These need to be mapped back to the JTable model rows (using the convertRowIndexToModel(i) ) since the user could have sorted the table

3. Then we set the value (in this case we set the attribute to a boolean 1 so that a checkbox displays checked

4. Finally repaint the JTable to refresh the modified cells

Page 17: ADF Tips and Tricks

ADF JPanels

Working with Multiple Panels that bind the same Page Definition

November 26, 2008 References to this issuehttp://www.oracle.com/technology/products/jdev/htdocs/9.0.5.2/readme.htmlhttp://forums.oracle.com/forums/thread.jspa?messageID=1179594&#1179594 oracle.jbo.JboException:35001Initial attempts to resolve this issue following the provided instructions did not work. So, I took a somewhat simpler approach (that works with my current requirements but may not scale well). Since my problem arose from the use of TWO panels binding the same page definition, I've copied and renamed the page definition and used the new copy for one of the two panels. This resolved the oracle.jbo.JboException:35001 being raised when adding multiple instance of an existing JClient panel to another JClient panel or when launching multiple instances of a panel from the same binding context. To do this:1. Open the PageDef file and Save As with a new name2. Then Manually add the required XML element for the new page definition in the

Databindings.cpx file3. Edit the corresponding panel class to use the new PageDef name

○ private JUPanelBinding panelBinding = new JUPanelBinding("NewNamePageDef");

Working with Embedded ADF Swing Panels

This one had me scratching my head for a while.I developed an ADF bound panel that was tested and run fine by itself. I then embedded the panel in another ADF panel only to find out that it was no longer displayed! It appeared the the jbInit() method was never executed.

By comparison with other embedded panels that displayed properly I was able to trace this issue to the fact that the jbInit() method of the embedding panel was missing a small but crucial piece of code shown below.

Page 18: ADF Tips and Tricks

The bindNestedContainer method exists for all default ADF panels and it must be called by an embedding panel during initialization (or later as needed, see below). Reusing Databound ADF Swing Panels

with Different View Object Instances Using Model Parameters [10.1.3]

http://blogs.oracle.com/smuenchadf/examples/

91.

Delayed Binding of an Embedded JPanelSometimes you require that an embedded panel will appear only after a certain action and not upon initialization of the parent panel component. For example, the panel component may have a button that it will add the embedded panel as a new tab.

In this case the panel binding may be unnecessary and even result in slow loading of the parent panel. Also,errors may arise since the embedded panel may not be fully prepared for display. For example, you may be preparing a dynamic viewObject that requires data from the parent panel.

Below I describe a simple strategy that allows you to delay the embedded panel loading until it is needed.

1. Define the binding in the page definition as needed2. Do not include the embedded panel binding in the jbInit method of the parent panel3. Bind the embedded panel as needed using the following type of code

embeddedPanel.bindNestedContainer(panelBinding.findNestedPanelBinding("com_nibr_bdm_EmbeddedPanelPageDef"));

So for example ,

ADF JPanel Dialogs

Framework for adding ADF Dialog panels

Page 19: ADF Tips and Tricks

ADF Method Dialog Workaround #1

Occasionally, we need to open a dialog containing an ADF panel to collect variables bound to an application module method (typically reflecting a stored procedure). There has been a recurring problem with updating the JTextBox value bound to the method variables with the text that is used to pre-set. It is known that we require a call to the requestFocus() method of the JTextBox, but this seems to be problematic during the creation of a JDialog (probably because during the time the JTextBox text is set and we programmatically requestFocus the controls have not yet become visible). A solution that seems to work better is to call the requestFocus code as part of an ActionPerfomed listeneρ that the method execution button is bound to. Although I'm not sure when this executes it seems to work if it is also accompanied by an information pop-up dialog which is useful anyway to indicate that the method call has been performed.ΝΟΤΕ¨In another situation I could not get this to work. Here is a code fragment that can be used: private void jButton1_actionPerformed(ActionEvent e) { jTnameHint.requestFocus(); jTsourceArtId.requestFocus(); jCNameRule.requestFocus(); jSlider1.requestFocus(); JOptionPane.showMessageDialog(this, "Object: " + jTnameHint.getText() + "\nSuccessfully Replicated "+jSlider1.getValue()+" times"); }

ADF Method Dialog Workaround #2

Turn the automatic binding of the method button OFF (rem) ...

...and instead use similar code to what is shown below to fire off the method:

Page 20: ADF Tips and Tricks

basically we manually create and execute a method binding. This ALWAYS works Here is the code fragment private void jBGenerateBifArtifact_actionPerformed(ActionEvent e) { OperationBinding opB=(OperationBinding)panelBinding.getOperationBinding("gen_bif_artifact"); opB.getParamsMap().put("art_name",jTName.getText()); opB.getParamsMap().put("art_doc",jTDocumentation.getText()); opB.getParamsMap().put("genActitivtyId",jTActivityId.getText()); opB.execute(); JOptionPane.showMessageDialog(this, "Output: " + jTName.getText() + "\nSuccessfully Generated"); }

Respond to Errors in Method CallsTo provide users with a visual feedback in case an operation (method) throws error we can follow the execution of the method with the following conditional that open a dialog to confirm or warn the user

opB.execute(); /* Note how we check for errors and present appropriate dialog */if (opB.getErrors().isEmpty()){ JOptionPane.showMessageDialog(this, "Object: " + objNameHint.getText() + "\nSuccessfully Created ");}else{ JOptionPane.showMessageDialog(this, "Creation of Object: " + objNameHint.getText() + "\nFAILED due to errors! ", “Error Title” JOptionPane.ERROR_MESSAGE); }

Page 21: ADF Tips and Tricks

ADF Check Boxes

Check Box in a Table

You can display a check box in the UI for boolean values including as a table cell editor). Such a default check box sets the value in the database to 1 when checked and to 0 when not. Things will work if your design adheres to the following guidelines:1. SET the Database column data type to NUMBER(1,0) (for True False, Yes NO). In

fact this is less confusing than setting it to a single CHAR (T,F or Y,N) as any of these would need translation to 0 or 1 sooner or later

2. Set this attribute to a Boolean in the entity attribute definition3. Edit the attribute and provide a CONTROL HINT. Set the CONTROL TYPE to a

CHECKBOX4. The Checkbox will appear in the UI and will respect the 0,1 values when it is de-

selected or selected5. JUN-27-2011 NOTE: The binding of the check box MUST be set to selected=true/

unselected=false or you will not be able to toggle it on and off (even if it displays the database values correctly)!

Check Box for marking table selections

[FEB-18-2011]I have used check boxes to mark table rows as selected. This is a more reliable way for marking than standard multi-row selections which appear tob eproblematic with ADF (dy design ADF tables do not support multi-selection?)The approach involves the creation of a transient boolean attribute in the ADF table. This column should be set as alway editable. This allows its display as a checkbox, the ability to check it and uncheck it and the ability to query the rowsetiterator (a copy of the one that the table is bound to) for which rows are selected

Page 22: ADF Tips and Tricks

ADF Master-Detail Forms

Customizing Auto-generated M-D Forms

Find the basal panels and Change their layout to VerticalLayout.This will allow you to add a Title region as in the example shown below:Biofiler Activity and Activity Properties were added as a title

ADF JUNavigationBar

Set which buttons to show

Use the JUNavigationBar API as shown below to set which buttons are shown setHasDeleteButton(boolean b)

Page 23: ADF Tips and Tricks

Tells the toolbar whether to include the delete button or not.

setHasExecuteButton(boolean b)

Tells the toolbar whether to include the 'Execute' button or not.

setHasFindButton(boolean b)

Tells the toolbar whether to include the 'Find' button or not.

setHasInsertButton(boolean b)

Tells the toolbar whether to include the insert button or not.

setHasNavigationButtons(boolean b)

Tells the toolbar whether to include the navigation buttons or not.

setHasTransactionButtons(boolean b)

Tells the toolbar whether to include the commit/rollback buttons or not.

ADF LOV Popups

This kind of control/binding is used when the LOV row count is large enough to make navigation in a ListBox or ComboBox difficult. Also this binding allows easier application customization as the display of LOV data is completely delegated to the LOV dialog/LOV panel. We access components and events using the JULovButtonBinding class. Here is an example where the row selected is used to provide a variable value inputType=((JULovButtonBinding)panelBinding.getControlBinding("InArtifacttype1")).getLOVRowSetIterator(). getCurrentRow().getAttribute("Name").toString(); In this case InArtifacttype1 is the ID of the LOV binding as defined in the page definition <lovButton StaticList="false" IterBinding="BpmnActivityView1Iterator" id="InArtifacttype1" xmlns="http://xmlns.oracle.com/adfm/jcuimodel" ListIter="BpmnArtifactView1Iterator" Title="LOV Dialog Title" AllowSearch="true">

An action listener can be assigned to the button that fires the event.

Note: The action is executed upon exiting the LOV dialog.

Page 24: ADF Tips and Tricks

setHelpAction

public void setHelpAction(java.awt.event.ActionListener al)

If the default LOV dialog is being used to display LOV Data, this method should be used by applications to set the ActionListener that is triggered on activating the help button in the LOV Dialog.

This allows applications to display custom help for the LOV dialog.

Listening to Navigation Events in the LOV Dialog

This is an interesting idea that would allows us to respond dynamically to navigation events in a LOV popup dialog.After a bit of searching I was able to implement this with a RowSetListener which implements the navigated interface method So here is the bit of code to accomplish this activLOVButtonBinding=((JULovButtonBinding)panelBinding.getControlBinding("Name"));

After getting the JULovButtonBinding here we will use it next

Page 25: ADF Tips and Tricks

activLOVButtonBinding.getLOVRowSetIterator().addListener(new RowSetListener(){ public void rangeRefreshed(RangeRefreshEvent rangeRefreshEvent) { } public void rangeScrolled(ScrollEvent scrollEvent) { } public void rowInserted(InsertEvent insertEvent) { } public void rowDeleted(DeleteEvent deleteEvent) { } public void rowUpdated(UpdateEvent updateEvent) { } public void navigated(NavigationEvent navigationEvent) {// System.out.println("navigationEvent firing!"+navigationEvent.getSource().toString()); Object activityID=((JULovButtonBinding)panelBinding.getControlBinding("Name")).getLOVRowSetIterator(). getCurrentRow().getAttribute("Activityid"); Object imageID=((JULovButtonBinding)panelBinding.getControlBinding("Name")).getLOVRowSetIterator(). getCurrentRow().getAttribute("ImageId"); setVisualCue(imageID); setPropertyView(activityID); } });

We get the LOV RowSetIterator and we add a RowSetListener.This interface has several methods that need to be implemented but since I'm only interested in the navigation events I left everything else blank. The navigated method implements the action.The example is from the biofiler class InsertWrkFlActivityConfigurator using two custom methods I set a visual cue and show the activity parameters in response to navigating the list in the LOV dialog. No need to exit the dialog, so this acts as a dynamic way to review the activities before selecting the desired one.

ADF Comboboxes

Page 26: ADF Tips and Tricks

Selections from ComboBox in ADF Tables AUG-26-2011 A LOV can provide controlled terms for a viewObject attribute value. What I have found though is that although the LOV list is used automatically when the column is displayed in the text field of a form it does not do so in an ADF Table.

In that case you must manually set bindings for a ComboBox editor in the table attribute properties. You must then configure it to bind dynamically to an instance of a viewObject. The default LOV list is not sufficient.

ADF Tables

Selections from ComboBox in ADF Tables (see example below)

Page 27: ADF Tips and Tricks

ADF Trees

Record Navigation using ADF Jtree

MAY 17, 2010 This is a technique I have been using for a while. It consists of the following 3 steps:1. Make the Swing JPanel implement the TreeSelectionListener interface2. Implement the valueChanged(TreeSeelctionEvent) method3. Add a tree selection listener on the tree. The Panel Listens for Tree Selection

events Ways to implement the valueChanged methodOne helpful suggestion was derived from the following blog.In summary we obtain the row of the tree node and then set any iterators we need using the FindByKey method. /** * This method responds to TreeSelection events generated by the embeddedArtifactNavTree . * [MAY-17-2010] Of interest is the code that creates a Key from the tree node and * synchronizes the currentRow of the BpmnArtifactView1Iterator accordingly using this Key. * This seems to be a better approach than filtering the Viewobject to get back a single row * [AUG-25-2010] By checking for path.getPathCount()>1 we ensure * that no errors are thrown when user clicks on root node * @param e */ public void valueChanged(TreeSelectionEvent e) { TreePath path=((JTree)e.getSource()).getSelectionPath(); JUTreeNodeBinding tb=null; /* * Note how we verify the source of the TreeSelectionEvent * by checking that it equals the JTree object in this class only */ if (path != null&&e.getSource().equals(embeddedArtifactNavTree)&&path.getPathCount()>1) { ApplicationModule am = (ApplicationModule) panelBinding.getApplication().getDataProvider(); DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); tb = (JUTreeNodeBinding)node.getUserObject(); DCBindingContainer bc=(DCBindingContainer)getPanelBinding(); DCIteratorBinding iter=(DCIteratorBinding) bc.findIteratorBinding("BifxImageView1Iterator"); Key key=new Key(new Object[] {tb.getRow().getAttribute("ImageId")}

Page 28: ADF Tips and Tricks

); RowSetIterator rsi=iter.getRowSetIterator(); Row row=rsi.findByKey(key,1)[0]; rsi.setCurrentRow(row); } }

path.getPathCount()>1This ensures that we do not respond to click event on the root node! Notes on Adding the Tree Selection Listener //class declarations private JTree embeddedArtifactNavTree = new JTree(); //in the init method... embeddedArtifactNavTree=artifactBranchNavTree1.getArtifacTempltNavTree(); embeddedArtifactNavTree.addTreeSelectionListener(this);

The above code fragment demonstrates a common scenario.The JTree emitting the click events may not reside in the same JPanel that is registered as the listener (and implements the valueChanged method). In the example above it resides in the artifactBranchNavTree1 embedded JPanel. We need to implement a getter method and provide a local variable for the returned JTree

Another important consideration is the ability to listen to the 'right' tree event. Remember that the source of the event can be discovered from the event itself.

NOTE: I have been unsuccessful implementing (in Swing) a method that has been described by Steve Muench in the July/August 2009 Oracle Magazine.

The article describes targeting another iterator in tree selection. Although it sounds rather easy to implement in several attempts I was not able to get it to work with a Swing JTree as the navigator.

Recreating ADF Tree Bindings for a new Swing tree

July 2, 2008Tree bindings and their rules are somewhat complicated to setup. Once you have a working tree binding configuration it would be nice to be able to re-use itYou can accomplish this by copying and pasting the <bindings><tree> node in the XML of the PageDef from a working tree binding to a new one.[MAY-17-2010] . You may also need to copy the iterator on which the tree is based.In addition, if you are replacing the binding of an existing tree, you may also need to point the tree model binding of the existing tree (in the jbinit) to the new iterator

Renaming ADF Tree Root nodes

Page 29: ADF Tips and Tricks

From the bindings tab, select the iterator, right click: Refactor->Rename. Enter a new Name (no spaces allowed)

Saving and restoring a Hierarchical Tree

This is an interesting piece of code from the JDeveloper Forum What does it do: Saves the state (expanded nodes and selected nodes) of a hierarchical tree so that it can be re-loaded.Note (June 2009): Unfortunately these methods are for web components and not ADF swing components. I was able to develop a similar behavior that works satisfactory albeight still has an issue in that during the initial addition of a tree node the current node selection appears NULL. Still don't know why and have not investigated this further. private static RowKeySet savedExpanded;private static RowKeySet savedSelected; public String saveButton_action() {// Add event code here...savedSelected = tree1.getSelectedRowKeys().clone();savedExpanded= tree1.getDisclosedRowKeys().clone();return null;} public String loadButton_action() {// Add event code here...tree1.setSelectedRowKeys(savedSelected.clone());tree1.setDisclosedRowKeys(savedExpanded.clone());return null;}

Restoring the Last Selected Node

[March 19, 2011]In several cases after the indirect addition of a tree node (ie. via a stored procedure) we need to refresh the tree by executing a query on the root iterator. This collapses the tree and potentially confuses and frustrates the user that now has to go back and re-expand the nodes of interest. Although it would preferable too simply find a solution that fully restores the expansion of the tree, a satisfactory workaround is to simply restore the last node that the user was working on. In the last couple of days I took a detour to examine how this an be accomplished. Things to watch out for while working with ADF tree node expansion!1. There exist typically TreeSelectionListeners with a

valueChanged(TreeSelectionEvent e) method that will also automatically respond to the collapsing tree event. As a result various node and selection assignments right before the query are reset or changed immediately after (that had me scratching my head for a while). A solution to this is to set a flag immediately before the query that will cause the valueChnaged method to not fire if we are in the middle of restoring the expansion of the tree.

Page 30: ADF Tips and Tricks

○ OFINT: Examining the code above I observed the use of the object clone method. Presumambly this caches the objects so they do not get changed after the tree collapses and is getting restored

○ TODO: Examine this method further.○ APR-15-2011: It does not appear that TreePath implements the clone-able

interface2. If your are assigning variables based on the tree node, model, selection model etc

these will be changing even if the valueChanged method does not fire since they are simply members of the corresponding JTree. So store in a cached model (or simply strings) and use this cached values to restore the tree.

So, now on the technique to restore the expansion state of the last selected node.

1. In this example, the last selected node path was stored during the valueChanged event in a map and it is retrieved.

2. Then I build a String array that maintains the names of each of the nodes in the path

1. TreePath lastAssayPath=(TreePath)model.getPropertiesMap().get("assayPath");2. String[] lastAssayPathObjects=new String[lastAssayPath.getPath().length];//lastAssayPath.getPath(); for(int i=0;i<lastAssayPath.getPath().length;i++){ System.out.println("Added: "+lastAssayPath.getPathComponent(i).toString()); lastAssayPathObjects[i]=lastAssayPath.getPathComponent(i).toString(); }

1. We then set the flag (in the shared model) that will prevent the valueChanged method from firing

2. Execute the root view query to refresh the tree

1. model.getPropertiesMap().put("isTreeRefreshed",true); 2. experimentIterator.executeQuery(); Finally the expansion of each of the ancestor nodes of the last node happens in a loop.Of interest is the use of the getNextMatch method that matches the name from the cached path node names.

for(int i=0;i<lastAssayPathObjects.length;i++){ System.out.println("Expanding: "+lastAssayPathObjects[i].toString()); navTree.setSelectionPath(navTree.getNextMatch(lastAssayPathObjects[i],0,Position.Bias.Forward)); navTree.expandPath(navTree.getSelectionPath()); }

The effect of this targeted restoration is quite useful, as it focuses the user by collapsing all other nodes and expanding the last node that an action was fired from The examples are taken from the following Biofiler classes1. public class ActionNewProcess extends AbstractAction2. public class PNavBifExperiment extends JPanel implements JURegionPanel,

Page 31: ADF Tips and Tricks

TreeSelectionListener

Detecting the type of the Current Node

[JUN-21-2011]In a tree where the type of the node can't be easily determined from the node path depth, the type can be identified from the ViewObject name returned by the node. Use code similar to thisFirst you can print out the ViewObject name so that you check whether the node indeed comes from it

if(tb.getIteratorBinding().getViewObject().getName().endsWith("ActivityHierarchy")){ //DO}

Sometimes the nodes include LABEL nodes. These are not bound to a ViewObject. Use a conditional to check first if the node can return a row object

/** Note: A getRow may return a null when users selects label node* generated from an iterator LABEL*/if(tb.getRow()!=null){ //DO}

Hierarchical ADF Trees

July 3, 2009 and updated August 21, 2010 What does it do: Creates a hierarchical tree view of parent child relationships. The tree expands to as many levels as they are required by the occuring parent-child relationships. Prerequisites to get this to work are:1. Hierarchical data in the form of [objectID, objectProperties, parentObjectID]. For a

root object the parentObjectID is null or has a special indicator.2. A RO view object (voA) of the above data, based on a query that uses the CONNECT

BY PRIOR Oracle statement. This is a hierarchical query against db records that have a parentID column from the same table. The query should use the LEVEL predicate to obtain the hierarchy level of a record.

3. A named ViewCriteria clause (vcN1) that selects the root objects of the hierarchy (Level=1).

4. A view link between voA and itself with an association defining the parent-child relationship. For example, voA.objectID=voA.parentObjectID. This, essentially, links root level parents to their children an so on. For this to happen correctly, the ViewCriteria vcN1 must be applied to the parent instance of the voA ViewObject.In the module data model select the parent voA instance and edit it by applying the vcN1 ViewCriterion (use the <edit> button in the data model UI)

5. In the application module, the link should appear as:

Page 32: ADF Tips and Tricks

voA:vcN1

|_voA

How to construct the tree rules

Start by creating a tree with the parent voA:vcN1 (LEVEL 1 Nodes) ViewInstance. Then edit the tree binding to define the branch rules. Select the root node viewObject and add children nodes from the voA view (step 4 above ViewLink). Interestingly, although you are allowed to add this rule IT WILL NOT APPEAR as a new rule in the tree binding configuration wizard UI. However, it will appear once the tree is displayed in the UI. This will allow you to navigate and expand from the root Level 1 nodes to leaf node, adding as many node levels as required to display the entire hierarchy

Additional hierarchy levels[JUN-25-2011]

Intention: The goal was to create a hierarchical tree for an Ontology. In this case a separate view object (the ontology namespace) provides the root level nodes for the hierarchy.The ontology terms must branch from these nodes using the ISA ->TERMID child -> parent relationship in each ontology term.

Initially, I worked with an existing hierarchical view (H1View) and tried to add a new view link between the namespace view and the ontology term hierarchy view. Strangely, but as designed, the level 1 nodes are no longer filtered for the ‘Level 1’-View criteria. The view criteria are applied only if H1View is the root view but not once the namespace view is the root.

In this case I added, a ‘Name-space’ Root level without using view criteria. This was accomplished by direct tagging of the namespace root records with a boolean flag.

Tree Node Binding: View link Accessor Rowsets

MAR-18-2011REF:

Passing RowIterator of Selected Tree Node to AM Method 20-JAN-2009-Example 142 A very common mistake developers make is that they write application module custom methods that operate on a view object instance in the datamodel, only to be surprised when the changes they've made are not reflected in the tree on the page. Their approach fails because the ADFM tree binding uses view link accessor rowsets rather than data model view link instances to work with detail rows.From a JUTreeNodeBinding we can actually get both the iterator and the viewObject Starting with a method that receives TreeSelection events:

Page 33: ADF Tips and Tricks

public void valueChanged(TreeSelectionEvent e) {TreePath path=((JTree)e.getSource()).getSelectionPath(); JUTreeNodeBinding tb=null; DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); tb = (JUTreeNodeBinding)node.getUserObject(); From there we can get various row attributes such as:tb.getRow().getAttribute("Assayid").toString()

The Row Iterator

tb.getIteratorBinding()

and the ViewObject (name)

tb.getIteratorBinding().getViewObject().getName()

NOTE: I have not been able to successfully query the ViewObject (as it seems to require a BIND VARIABLE that I have not figured out how to set). However, I have been able to successfully query the Iterator. I have done this in an attempt to refresh the tree node display after the addition of a new node (via a stored procedure). This does not seem to work. Its only after refreshing the Root node that the display gets refreshed (which also collapse the tree, which was what I was trying to avoid!)

ADF Trees are not bound to ViewObject Instances but to their Definitions

[FEB-08-2011]

I finally understood better that ADF trees are not bound to ViewObject instances but rather to the ViewObject structure and ViewLinks.

What this means is that what you view in the visual binding editor is not specific instances of ViewObjects, but Viewobjects that are accesible via the ViewLinks that are part of the ViewObject definition. In fact ADF Trees can be constructed in th eabsence of any view objects as long as the correct viewLinks exist.

Page 34: ADF Tips and Tricks
Page 35: ADF Tips and Tricks

Manual Editing of Tree Node Binding

Although JDeveloper provides a GUI for editing tree node bindings, there are (desperate) situations where you may be forced to edit the tree node binding manually. Occasionally bugs prevent the GUI editor from working properly. In addition, manually setting up tree bindings is useful in understanding how the binding mechanism works and potentially how to fix it if it causes errors. The details will be described in a separate documentHowever, the secrets to manually setting up tree node bindings and understanding how this works, reside in the ViewObject definition and its ViewLinkAccessor elements. A typical tree node binding xml structure is shown below

Interestingly the node-Definitions are NOT nested but simply use a simple 'flow layout'. The Accessors elements in each nodeDefinition refer to the ViewLinkAccessor(s)that are defined in the XML of a ViewObjetc The AttrNames must exist in the viewObject accessible via the ViewLinkAccessor

Folder Labels for ADF Tree Nodes.

Although it's NOT obvious, when the FOLDER LABEL option is available it can be applied to multiple iterators at the same level in the tree hierarchy.Select each iterator from the combo box and apply a different Folder Label to it!

Expanding an ADF filtered tree node

Page 36: ADF Tips and Tricks

Make sure that the iterator RangeSize="-1" when the RangeSize (by default at 25) would filter parent nodes out. Otherwise you get an error trying to expand the parent nodes to the child level

Filtering an ADF Hierarchical Tree

Many times a nested tree requires expansion and visual inspection to find a node of interest. It can be really a nice if nodes of interest can be filtered easily.In the Biofiler application this is a common requirement as many of the navigation trees contain several levels of nesting. The following method creates a filterable tree based on ANY LEVEL Node in the tree. Upon filtering only Level 1 nodes that can lead to the search term are displayed. All other terms are filtered out. In summary the process involves the following steps 1. Create a view to support the hierarchical tree.2. Ensure that the view works with a BINDING variable that encapsulates the search

term. When the view is executed with the search term only level 1 nodes should be returned

3. Create a two-part panel so that you can place the search panel on the top and the tree at the bottom

4. Add the root node view operation ExecuteWithParams as a method to the top panel.

5. Add the tree to the bottom and you are ready to go!

The Level 1 nodes of the tree can be filtered by entering the search term and pushing the ExecuteWithParams button.

Search a Rendered ADF Bound Tree (The Frank Nimphius approach)

URL on JAN 25, 2012

http://www.oracle.com/technetwork/developer-tools/adf/learnmore/61search-in-rendered-trees-177577.pdf

Searching an ADF Hierarchical TreeAn alternative to filtering the nodes of a JTree, is to search through its nodes to find nodes whose label matches a user specified text. Iteratively we can match nodes of interest.

This approach uses the

javax.swing.tree.DefaultMutableTreeNode.breadthFirstEnumeration()

which creates and returns an enumeration that traverses the subtree rooted at this node in breadth-first order.

Page 37: ADF Tips and Tricks

This method is now (10-17-2011) encapsulated in the JTreeUtil.findMatchingTreeNodes(DefaultMutableTreeNode rootNode, String nodeStr) static method

This method returns an array list that can be iterated to guide a successive matching node traversal. An example action performed by a search button is shown below (taken from ArtifactTemplateTreeNavigator class)

private void searchButton_actionPerformed(ActionEvent e) { if (!navIsExpanded){ navIsExpanded=JTreeUtil.expandJTree(artifacTempltNavTree,JTreeUtil.EXPAND_FULLY); } String findTerm=searchTermField.getText(); /* new way for finding based on array list of terms */ if (findTerm.equalsIgnoreCase(currentSearchTerm)&&matchingTreeNodes.size()>0){ if (currentNodeIndex>=matchingTreeNodes.size()) { //reset node index so search starts from top currentNodeIndex=0; } String nextMatchingNode=matchingTreeNodes.get(currentNodeIndex).toString(); int currentTreeRow=artifacTempltNavTree.getRowForPath((artifacTempltNavTree.getSelectionPath())); artifacTempltNavTree.setSelectionPath(artifacTempltNavTree.getNextMatch(nextMatchingNode,currentTreeRow+1,Position.Bias.Forward)); artifacTempltNavTree.scrollPathToVisible(artifacTempltNavTree.getSelectionPath()); currentNodeIndex++; }else{ currentNodeIndex=0; currentSearchTerm=findTerm; matchingTreeNodes=JTreeUtil.findMatchingTreeNodes(rootNode,findTerm); if (matchingTreeNodes.size()>0){ String nextMatchingNode=matchingTreeNodes.get(currentNodeIndex).toString(); int currentTreeRow=artifacTempltNavTree.getRowForPath((artifacTempltNavTree.getSelectionPath())); artifacTempltNavTree.setSelectionPath(artifacTempltNavTree.getNextMatch(nextMatchingNode,currentTreeRow+1,Position.Bias.Forward)); currentNodeIndex++; }else{ System.out.println("Node with string " + findTerm + " not found"); } } }

How to use a partial branch of ADF View Tree

Page 38: ADF Tips and Tricks

December 10, 2009I've tried to use a partial branch of ADF view tree

For example given the View Tree above, I have a panel where only the ActivityInputArtifactView1 and BifvArtifactIngroupView3 are used.

However, the row filtering on the leaf view BifvArtifactIngroupView3 depends on setting a BIND VARIABLE in the root View node that is not included on this panel. THIS DID NOT WORK as expected.

Setting the bind variable on the root node did not return any rows!

The trick that made this work was to add the BifvActivityInputView1.Activityid as a text field and then delete it. When I was asked to remove the unused iterator I replied NO.

The remnant of this iterator NOW MAKE the filtering work as expected! Apparently we need the iterator in the page definition

Refreshing ADF Tree Objects

In a few cases I had problems refreshing ADF-Trees.

It turn out that the panelBinding.refreshControl() is an effective way to refresh such trees (although they end up collapsing)

OCT-20-2011

Page 39: ADF Tips and Tricks

I have observed that panelBinding refreshing does not appear to be effective if new root level nodes have been added. A slightly more drastic approach is to refresh the ViewObject that the root level nodes are bound to. This is accomplished by executing the query on the ViewObject with code similar to the one shown below:

ApplicationModule am = panelBinding.getBindingContext().findDataControl("BpmnAppModuleDataControl").getApplicationModule(); ViewObject targetView = am.findViewObject("L1Process"); targetView.executeQuery(); panelBinding.refresh();

TO-TRY this IDEA (JULY 26, 2011)

An alternate way to refresh an ADF tree after some action that modifies its model in the database (such as the exectuiton of a stored procedure) is to get the internally generated view object that ADF trees generate and execute after the action has been completed.

Here is some example code

TreePath path = ((JTree)e.getSource()).getSelectionPath(); JUTreeNodeBinding tb = null; ApplicationModule am = (ApplicationModule)panelBinding.getApplication().getDataProvider(); DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); tb = (JUTreeNodeBinding)node.getUserObject();

System.out.println("VO_Name: "+tb.getIteratorBinding().getViewObject().getName());

The name printed out is the internally generated name for the VO bound to the selected tree node. An example of how you may proceeed is shown below with the internally generated name shown in bold.

ViewObject treeNodeVO=am.fndViewObject("BpmnProcessView_ActivityHierarchy_BpmnProcess2ActivtitySequenceVL_ActivityHierarchy");treeNodeVO.setNamedWhereClauseParam("Bind_Processid",currentWorkflowRow.getAttribute("Processid").toString());treeNodeVO.executeQuery();

Page 40: ADF Tips and Tricks

If the VO requires a BIND VARIABLE use code similar to the one shown in blue. If left out you may get a helpful diagnostic message that will allow you to identity the required BIND VARIABLE.

The re-execution of the view should refresh the tree.

How to add a context menu on an ADF Tree

This requires a special helper class that i've createdImport

Define private JTree jTree1 = new JTree(); private String[] menuItems = { "ActionAddAssay","ActionEditAssay","-","ActionNewProcess","ActionConfigureProcess","-","ActionQueryResults","ActionCustomQuery" }; private ContextMenuHelper menuHelper;

in the jbinit method jTree1.setModel((TreeModel)panelBinding.bindUIControl("BifExperimentView1",jTree1)); // add the context menu to the Jtree menuHelper = new ContextMenuHelper(menuItems, this); menuHelper.addToComponent(jTree1); //Listen for when the selection changes. jTree1.addTreeSelectionListener(this); jTree1.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { jTree1_mouseClicked(e); } });

Listener action /** *Double click action opens up a dialog to configure the selected activity * @param e */ private void jTree1_mouseClicked(MouseEvent e) { TreePath path=((JTree)e.getSource()).getSelectionPath(); if (e.getClickCount()==2 & path.getPathCount()==4){ System.out.println("Double click"); ((Action)this.getMenuHelper().getModel().getActionMap().get("ActionConfigureProcess")).actionPerformed(null); } }

PanelBinding

Some useful info that can be collected from the panelBinding varaible, ubiquitous in ADF panels.

Page 41: ADF Tips and Tricks

Method Result

panelBinding.getFullName()

data.StartFormPageDef.com_nibr_bdm_ObjectManagerPageDef.com_nibr_bdm_OMArtifactTemplateMDPageDef.com_nibr_bdm_OMArtifactTemplatePropertiesTablePageDef

this is the entire hierarchy of PageDefs!

panelBinding.getName() com_nibr_bdm_OMArtifactTemplatePropertiesTablePageDef this is the clean page def name

View Objects

How to programmatically populate a newly added view object row?

March 17, 2008In one panel I have a button that I want to use to INSERT a new ROW in a ViewObject displayed as a table in another panel. How can we insert this new row and populate it with data from the action of the button? CODE FRAGMENT //create new row Row newRow=VO.createRow(); //Populate attributes of new row row.setAttribute("AttrName1","ValueAttr1"); row.setAttribute("AttrName2","ValueAttr2"); //insert new row VO.insertRow(newRow); The specific example below uses a button to open a JFileChooser that allows the user to select a file.Metadata from this file are then stored in a new row of the View Object named AnxDatafileview2

Page 42: ADF Tips and Tricks

Programmatically iterating over the RowSet of a view

If you get the IteratorBinding that also binds the Swing UI (for example the same iterator that is bound to a JUITable) you end up skiping the first row.Instead as it is suggested by Steve Muench you need to get a new RowSetIterator for the ViewObject and use that to iterate. Here is an example: //Get a View Object ApplicationModule am= panelBinding.getBindingContext().findDataControl("BifAssayModuleDataControl").getApplicationModule(); ViewObject propAncestryVO=am.findViewObject("ArtPropertyAncestryPivotVO1");//Create an Iterator on it RowSetIterator riter=propAncestryVO.createRowSetIterator("OutputSelectorPropertyIterator"); riter.setCurrentRowAtRangeIndex(0);

Page 43: ADF Tips and Tricks

ViewObjects Come Up Blank

July 30, 2009Symptom: View object does not display any data For some reason [especially when you see a message something like 'Reseting default WHERE clause' in the process of creating a ViewLink] ALL selection of columns in the View object are removed and IsPersistent is set to false.● BEST OPTION: Open the view.xml in overview mode and click the button

(upper right corner) <Add from Entity...> Re-add all of the attributes● Try recovering from history or● Create another View object from the entity object and copy its relevant section into

the damaged ViewObject definition.○ Note that the order of the SelectList attributes must match that in the

ViewAttribute elements below

View Object Bind Variables and Bind Variable Default Values

December 3, 2009When views are used to present a filtered result set it is useful to create a query BIND VARIABLE and then set it to default value1. Open the ViewObject definition and create a WHERE CLAUSE with a bind variable

(in the Oracle bind style)

2.

3. Then Define the BIND variable:○ You can either supply a default value○ or leave it null (in which case by default you don't get any results which in some

case is what you want)○ In some cases its is better to use queries with a LIKE where clause. For example

LIKE :BIND_VARIABLE. Then the default value of the bind variable can be set to % where it will select all the records. I have found this last approach to be more reliable.

Page 44: ADF Tips and Tricks

1. Subsequently to set the bind variable use code like the one shown below:

The code above gets the Activityid from a tree node and uses it to set the BIND Variable in the corresponding view.

Find a ViewObject Row by Key

[Feb-27-2010] The construction of a Key object takes an AttrDefList as a parameters NameValuePairs nvp = new NameValuePairs(); nvp.setAttribute("Workflowid", currentWorkflowId); Key cwfKey= new Key(nvp.getAttributeValues());

Row currentAssayWorkflow=assayWorkflowView.getRow(cwfKey); The above method constructs a key from scratch. What about if we can get the key from

another UI component (let's say a navigation tree) and now want to find the same record in a different view.

Here is an example from a Biofiler Action class: panelBinding = (JUPanelBinding)getValue("panelBinding");

Page 45: ADF Tips and Tricks

model = (ContextMenuModel)getValue("contextModel");//this is from a Biofiler class //next is the View object we need to synchronize with the contextModelViewObject expVo = panelBinding.getBindingContext().findDataControl("BifAssayModuleDataControl").getApplicationModule().findViewObject("BifAssay1View1");oracle.jbo.Row[] r =

expVo.findByKey(model.getSelectedComponentItem().getKey(),1);expVo.setCurrentRow(r[0]);//this is the trick! since the returned rowset is an array we need to select one!

Use a ViewLink to Access the Details of a Nested Collection or Nested Row

[JUN-01-2010]At run time the view link accessor behaves as an additional attribute in the current row.

(see Fusion Dev Guide 5.6.6)I have successfully used the following code to retrieve the attribute of the nested row as

follows:Object objectType= ((ViewRowImpl)panelBinding.getControlBinding(tableBifArtifactNBVView1).getViewObject().getCurrentRow().getAttribute("BpmnArtifactView")).getRowSet().getCurrentRow().getAttribute("Name"); Notice that BpmnArtifactView is the name of a ViewObject (not instance of VO) nested in

the ViewObject that the object tableBifArtifactNBVView1 is bound to. The example shown in the Dev Guide seems to use as attribute the name of an instance

(but in this case did not seem to work for me)

Performing In-Memory Sorting and Filtering of Row Sets

Chapter 35.6 on 11g documentation (have print out of this chapter)In 10.1.3 The view object's SQL mode controls the source used to retrieve rows to populate its row

set. The setQueryMode() allows you to control which mode, or combination of modes, are used:

ViewObject.QUERY_MODE_SCAN_DATABASE_TABLES This is the default mode that retrieves results from the database. ViewObject.QUERY_MODE_SCAN_VIEW_ROWS This mode uses rows already in the row set as the source, allowing you to progressively

refine the row set's contents through in-memory filtering.

Page 46: ADF Tips and Tricks

ViewObject.QUERY_MODE_SCAN_ENTITY_ROWS This mode, valid only for entity-based view objects, uses the entity rows presently in the

entity cache as the source to produce results based on the contents of the cache. You can use the modes individually, or combine them using Java's logical OR operator (X

| Y). For example, to create a view object that queries the entity cache for unposted new entity rows, as well as the database for existing rows, you could write code like:

setQueryMode(ViewObject.QUERY_MODE_SCAN_DATABASE_TABLES | ViewObject.QUERY_MODE_SCAN_ENTITY_ROWS) I've tried setRowMatch(RowMatch) but this seems to remove the rows from the collection!Rows can come from three different sources. If the row set currently has a collection of rows (View rows), QUERY_MODE_SCAN_VIEW_ROWS will indicate that the row match (see setRowMatch(RowMatch)) should be applied to further filter view rows. Unqualifying rows are removed from the collection

Recovery from Error Saving ViewObject XML file after Updates

[SEP-20-2010]While trying to edit a view object (in this case it was based on Expert mode SQL, that did use an Entity Object for updates) I started receiving JBO-2900 errors with the message 'cannot add an ancestor as a child node', and was unable to save the edits. Although they would appear in the SQL text area, they would not save. I also could no longer add ViewLinks to this ViewObject (I've received the same error). I've created a new ViewObject using the exact SQL that would fail in the original ViewObject. Testing indicted that the new VO worked without a problem. At that point, however, it was difficult o switch my application to the new ViewObject especially since the original ViewObject included a number of ViewLinks used in the application. I dared a hybrid transplant! I moved the attribute code from the new VO to the original one, while maintaining the ViewLink elements of the original VO. Indeed, I did some additional cleaning, removing some commented XML and cleanly separating the ViewLink section. I then saved the modifications to the original file and successfully tested the newly added attributes that had failed to save previously. The old VO was now working as expected, including the newly added attributes. [FEB-01-2011]Encountered similar errors trying to add a new ViewCriterion. Followed the same approach as previously described to transplant the new View Criterion in the original ViewObject. An additional edit was required as the name of the view object that the criterion belongs to is embedded in the view criterion. This must be edited to match the original ViewObject.

View Object Based on * queries

Page 47: ADF Tips and Tricks

[FEB-14-2011]

ViewObjects based on custom * queries (SELECT * FROM...) are not recommended. If the schema of the target table changes the ViewObjects break. Apparently they depend on a particular sequence of returned columns

Instead always enumerate the columns that a query returns as this is resistant to changes in the underlying table schema.

If you receive errors like:

(oracle.jbo.AttributeLoadException) JBO-27021: Failed to load custom data type value at index 28 with java object of type oracle.jbo.domain.Number due to java.sql.SQLException.

it’s probably due to the use of ‘star’ queries. Identify the offending VO definition and replace the star query with a named column query. Required column names can be easily obtained from SQL*Developer (need to append a comma).

View Criteria

ViewCriteria UsageNotes

March 16-18 2009What does it do: Creates Viewcriteria for filtering a result set with The use of ViewCriteria using JDev11G has been unusually problematic. Previous 10G code stopped working. More specifically it appears that for the dynamic views although I'm still able to create ViewCriteria in Find mode the UI bound values are NOT saved. Instead the returned attribute values are null. Since it was critical for me to re-establish lost filtering functionality, I was able to generate ViewCriteriaRows manually by grammatically reading the rows of the table in FindMode. This worked rather well although it still suffers from the inability to enclose attribute names in quotation marks. This had been a problem before and lead me to try to create custom WHERE clause.

Create and Apply ViewCriteria

// 1. Create a view criteria rowset for this view object ViewCriteria vc = procView.createViewCriteria(); vc.setName("processVcrit"); // 2. Use the view criteria to create one or more view criteria rows ViewCriteriaRow vcr1 = vc.createViewCriteriaRow(); // 3. Set attribute values to filter on in appropriate view criteria rows

Page 48: ADF Tips and Tricks

vcr1.setAttribute("Processid", "= " + propView.getCurrentRow().getAttribute("Processid")); // 4. Add the view criteria rows to the view critera rowset vc.add(vcr1); // 5. Apply the view criteria to the view object procView.applyViewCriteria(vc); System.out.println("Applied View Criteria"); procView.executeQuery(); System.out.println("ProcessID Filter applied");

Remove ViewCriteria

SEP-03-2010Having problems clearing and removing ViewCriteria. Trying the following variations do not observe any effect // ViewCriteria vc = procView.getViewCriteria("criteria_name");// vo.removeViewCriteria("criteria_name")// vc.resetCriteria();// procView.applyViewCriteria(vc); // ViewCriteria vc =procView.getViewCriteriaManager().getViewCriteria("processVcrit"); // vc.removeCurrentRow();// procView.applyViewCriteria(vc);// procView.getViewCriteriaManager().removeApplyViewCriteriaName("processVcrit"); What worked was the following: viewObject.applyViewCriteria(null)

Should new ViewCriteria appended to the list of already applied view criteria?

Note the API paraemters of the ViewObject.applyViewCriteria method

void applyViewCriteria(ViewCriteria criteria,boolean bAppend)

Applied the view criteria to this view object.

If bAppend is true view criteria is appended to the list of already applied view criteria. If bAppend is false the applied view criteria list is cleared prior to applying the passed view

Page 49: ADF Tips and Tricks

criteria.

Parameters:

criteria - view criteria to be applied

bAppend - flag to indicate if the applied view criteria list needs to be cleared before applying the view criteria.

NOTE: This has effects on adding as well as removing criteria.

By simply applying ViewObject.applyViewCriteria(null) all view criteria is reset. This may not be the desired effect. You may want to apply/reapply a new critrerion in addition to an existing one. the the recommended usage is ViewObject.applyViewCriteria(null, true) meaning that the criteria will be appended to an existing list

Is a view Object Filtered by some View Criteria?

FEB-07-2011Goal: Discover if a view object is filtered or not. This may be useful if you want to update a UI indicator that informs the user that what is displayed is either filtered or not. What has worked Comments

This is an example of a method that checks the View Criteria status of a View Object and updates the text of a label.Of Interest is the use of the getViewCriteriaClause to check whether its null or has been set to something and therefore the ViewObject is filtered.

Page 50: ADF Tips and Tricks

private void updateFilterStatusLabel(){ if (artifactOfTypeVO.getViewCriteriaManager().getViewCriteriaClause(true)!=null) { filterStatusLabel.setText("Rows :" + artifactOfTypeVO.getRowCount() + "(Filtered)"); System.out.println(artifactOfTypeVO.getViewCriteriaManager().getViewCriteriaClause(true)); } else { //the view is not filtered filterStatusLabel.setText("Rows :" + artifactOfTypeVO.getEstimatedRowCount()); } }

What has not worked is the count of getAllRowsInRange (see rem-ed code). Even when the ViewCriteriaClause is null (not filtered a far as I'm concerned) the count does not appear to be zero. So this did not work if (artifactOfTypeVO.getViewCriteria().getAllRowsInRange().length != 0) NOTE: FEB-14-2011: The reason this is not working as expected is that we apply multiple named criteria. Which ones does getAllRowsInRange retrieve?

private void updateFilterStatusLabel() { if (artifactOfTypeVO.getViewCriteriaManager().getViewCriteria("MatchPropertyViewCriteria").getClauses().getClauseForQuery()!= null) { rowCountLabel.setText("Rows :" + artifactOfTypeVO.getRowCount()); filterStatusLabel.setText("(Filtered)"); } else { //the view is not filtered rowCountLabel.setText("Rows :" + artifactOfTypeVO.getRowCount()); filterStatusLabel.setText(""); } }

We can be more specific about the ViewCriteria we are inspecting. This seems to be the most reliable method to detect the application of the specific Viewcriteria. On the left is an example of a method that drills down into the specific critetion to determine if its the one whose clause is null.

How to use Named View Criteria

[OCT-15-2010]Named View Criteria are declared on a ViewObject and can be added to instances of that ViewObject or can be used programmatically. This example below describes how we can use a Named View Criterium (UI20101015A1ArtifactPropery)programmatically private ViewObject objView; private ViewCriteria vco;

Required Declarations

Page 51: ADF Tips and Tricks

objView.applyViewCriteria(null);vco =

objView.getViewCriteriaManager().getViewCriteria("UI20101015A1ArtifactPropery");

Reset any previous view criteria and get the named view criteria from the Criteria Manager

objView.applyViewCriteria(vco); objViewexecuteQuery();

Then apply the UI20101015A1ArtifactPropery view criteria and refresh the view object

[APR-13-2011]An example of how to use a Named View Criteria clause with a BIND variable private void setPropertyView(Object bpmnActivityId){ ApplicationModule am = (ApplicationModule) panelBinding.getApplication().getDataProvider(); ViewCriteria vco; ViewObject propView = am.findViewObject("UI20110413BpmnPropertyViewRO"); propView.applyViewCriteria(null); vco = propView.getViewCriteriaManager().getViewCriteria("BpmnPropertyViewROCriteria"); propView.applyViewCriteria(vco); propView.setNamedWhereClauseParam("BIND_BPMNACTIVITYID",bpmnActivityId); propView.executeQuery(); }

This code has been encapsulated in a simple methodNote how we:1. First apply the Named View Criteria

and2. Then we set the BIND variable

How to use Dynamic Named View Criteria

[FEB-01-2011]Another useful application of named view criteria involves their dynamic update and application.A named ViewCriteria can be retrieved and updated at runtime. An important task in this process is to be ale to name the criterion that is updated with a fully qualified criterion name. TIP: A fully qualified criterion name can be derived easily from the ViewCriteria xml definition. Examine the names of the nodes that form the nested herarchy to the desired view criterion and concatenate them with a period (.) in between. Example 2 Reset previous view criteria

Page 52: ADF Tips and Tricks

artifactOfTypeVO.applyViewCriteria(null);

ViewCriteria matchByprop= artifactOfTypeVO.getViewCriteriaManager().getViewCriteria("MatchPropertyViewCriteria"); ViewCriteriaItem vci=(ViewCriteriaItem)matchByprop.findElementWithRelativeName("MatchPropertyViewCriteria.vcrow184.Artifactid");

Use View Criteria manager to get the named view criterion. Then use the findElementWithRelativeNamemethod to retrieve the specific ViewCriteriaItem whose value we will dynamically update. Note that we need to cast this to a ViewCriteriaItem as the method returns an object

vci.setValue(sqlCriterion); Update the criterion value with a new sql fragment in this case

artifactOfTypeVO.applyViewCriteria(matchByprop); artifactOfTypeVO.executeQuery();

Apply the updated named view criterion and refresh the view object

Application Module

Working with multiple ApplicationModules

November 26, 2008 Finding a ViewObject while working with multiple ApplicationModules is more reliable if the AppModule name is used as follows: ViewObject abcVo = panelBinding.getBindingContext().findDataControl("AppModuleDataControl2").getApplicationModule().findViewObject("AnxDatamanagerView1"); I have run into NullPointer exceptions when I used an alternate syntax that worked fine when I was dealing with a single AppModule

ViewObject expVo = panelBinding.getBindingContext().getDefaultDataControl().getApplicationModule().findViewObject("AniExperimentstepView1");

Manual way to bind an AppModule Custom Method

October 2, 2009Custom methods can be bound to a panel by inserting a method action element in the binding page defintion. Although I've spend some time researching how we can bind these programmatically through the context and the applicationMmodule, I was not successful. However, this declarative approach seems rather simple. For example:Example code from PBifArtifactPropertyEditor.java

Comment

Page 53: ADF Tips and Tricks

<methodAction id="update_bifartifact_prop" RequiresUpdateModel="true" Action="invokeMethod" MethodName="update_bifartifact_prop" IsViewObjectMethod="false" DataControl="BpmnStoredProcsDataControl" InstanceName="BpmnStoredProcsDataControl.dataProvider"> <NamedData NDName="new_value" NDType="java.lang.String" NDValue="${bindings.update_bifartifact_prop_new_value}"/> <NamedData NDName="bpmn_propertyId" NDType="int" NDValue="${bindings.update_bifartifact_prop_bpmn_propertyId}"/> <NamedData NDName="bif_artifactId" NDType="int" NDValue="${bindings.update_bifartifact_prop_bif_artifactId}"/> </methodAction>

Note how the NamedData elements are named from the method parameters.Once this MethodAction element is introduced we can accecss the operation via its panel binding as follows: OperationBinding opB=(OperationBinding)panelBinding.getOperationBinding("update_bifartifact_prop"); opB.getParamsMap().put("new_value",propertyValue); opB.getParamsMap().put("bpmn_propertyId",propertyId); opB.getParamsMap().put("bif_artifactId",artId); opB.execute();

How to Access an Application Module Client Interface

This is useful info from the online documentation.I have used it to bind an action to the required application module.

Connecting to a second database using a database link

It seems that each project can only connect to a single database.

One way to get around this limitation is to create a private link in the database for the

Page 54: ADF Tips and Tricks

schema that the ADF application is already connecting to. In turn a Entity Objects can be created on the remote link using the @REMOTE_LINK syntax (shown below)

Connecting to a second database using another project's application module

A way around the limitation stated above, is to create a second ADF Business Components project with a different database connection.You can then add the new project as a dependency.

Page 55: ADF Tips and Tricks

In the example shown above the View Project has dependencies on both the Model and ModelOMIXD projects allowing This allows you to access the application module of the new project and thus have access to more than one database connections.As an example, I've build a simple form that contains and displays bindings to two different databases simultaneously.

Page 56: ADF Tips and Tricks

Connecting to a different database by adjusting application module properties

[APR-27-2011]It seems that there is yet a different strategy (not tried) to connect to multiple databases. If in fact this strategy works, it would be the simplest of the described strategies so far.

Page 57: ADF Tips and Tricks

Different connection for different application ModulesOpen the configuration of a particular application module and adjust the connection

This connection is saved in the corresponding bc4j.xcfg file and is used for the connection of that application module.

(Note: there has been some discussion that nested application modules will only use the connection of the root application module)

Login and Authentication

Using database tables for authentication in ADF applications

ADF Eye Candy

Include Images in Swing Forms

Page 58: ADF Tips and Tricks

Oracle Case Study(August 2007)

My development notes

QUESTIONS

1. Can NamedViewCriteria be used at run time programmatically? [7/23/2009]. So far I have not found a way to decalre them and then use them programmatically

2. Can Tooltips be generated from an attribute binding? This would be useful in cases where due to space limitations a Swing component (such as JLabel or JText) can not display the full text of an attribute. In that case it would be useful to display the full text as a tooltip. Currently it seems that tooltips can be generated either form a static attribute OR the record that is displayed first when the component is initialized in the jbinit method

jULabel5.setToolTipText(jULabel5.getModel().getCurrentRow().getAttribute("Name").toString());

UNRESOLVED ISSUES

Creating Shuttle Component in Oracle ADF

Tree Binding fails after opening in Dialog more than once

August 31, 2009Symptom: A Tree bound to an ADF view opens in a modal dialog from a button event. The first time the tree opens in the dialog it is bound to its view object but the second time it fails and nodes appear as $place_holder$ It turns out that this is caused by the release of the DATACONTROL in the automatically generated code for launching the dialog

Page 59: ADF Tips and Tricks

SOLUTION: Once I've commented these two lines out I was able to re-open the dialog with the ADF bound tree showing correctly! SOLUTION2: Rather than using the auto-generated code use the following: exitButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { artifactManager.getPanelBinding().release(DCDataControl.REL_ALL_REFS);// rather than REL_VIEW_REFS); dialog.dispose(); } }); This does appear to resolve the issue of the tree becoming unbound when it is launched from an action that can be found in several panels and/or the application menu. Currently it's applied to the ActionBrowseBifArtifacts (Biofiler Object Manager GUI Dialog). Now this does not get us completely out of the weeds. It turns out that modal dialogs that get opened from within the original dialog are indeed also uncoupled. So I will need to find a way to probably release their REL_ALL_REFS upon exiting the main dialog. If you do it before they become immediately unbound PREFERRED SOLUTIONIt seems that DCDataControl.REL_ALL_REFS together with an adaptation of the multiple-form instructions resolves many of the problems. See MDI ADF Forms [SEP-2-2009] Additional complications arise once the same form is opened repeatedly. It seems to be a design issue on how MDI forms are bound in ADF. See this article for more details.At any rate, even after applying some of the recommendations I still have trouble with the tree loosing its 'binding context(?)'. NEW ISSUE: Using the approach described in the article, selecting nodes on the tree appears to generate multiple copies after the form is opened several times (One for each time the form is opened!)

Page 60: ADF Tips and Tricks

Finally if the form is launched from yet another form (such as the navigation tree) a JBO exception is thrown and the tree becomes un-bound!

Workarounds to Some JBO Exceptions

Page 61: ADF Tips and Tricks

JBO-35001

● Some solution to a somewhat similar problem (but not exactly). It could be that this is due to the fact that we have two separate action objects accessing the same view object. In some case it might be possible to share a single action object.

● Also see this thread from OTN Forum (JBOException 35001).● Also see some ADF recommendations

JBO-27022

[OCT-08-2010] JBO-27022: Failed to load value at index n with java object of type X● In several cases I have found this to be a JDev bug, where even though an attribute is

added to a ViewObject (lets say from the entity object), the addition is not propagated correctly to the VO source code.

● Check the SelectList attribute of the <ViewObject> definition to check whether the offending attribute is missing. If it is add it to the source code manually!

● Also check any VO extensions that may exist. In one case although the VO was updated (By JDev) correctly the extension was not!

JBO-2900

Trying to save ViewObject xml after edit receive JBO-2900 errors with the message 'cannot add an ancestor as a child node'. See workaround here.● Recovery from Error Saving ViewObject XML file after Updates

JBO-25001

oracle.jbo.NameClashException: JBO-25001: Name _LOCAL_VIEW_USAGE_com_nibr_bdm_model_bpmn_BpmnPropertyView_BifOntologyByIsa1 of object type View Object already existsIdentify the offending view object. in BpmnPropertyView one of the View Accessors is BifOntologyByIsa1: Right click and <Find Usages> The search pointed to two instances used in the same view to provide LOV valuesTo Resolve:Add a copy of the iterator with a differnt name and bound second property LOV to this.