The above statement reads the JClient project file (myproject.cpx)
for an application module called MypackageModule and will use the
connection information defined for that application module to establish a
connection to the middle tier.
The JClient Panel Binding
Through the above code that returns a JUApplication object, JClient has established
the call required to bind to a particular application module. The next step
is to create a number of data structures which will manage the binding. To
accomplish this, unique branches of your UI (usually beginning with a panel)
will have a structure called a Panel Binding
which will contain Iterators.
private JUPanelBinding panelBinding = new JUPanelBinding("jclient.Mypackage1Module",
this);
The above statement creates a new panel binding and the following statement
registers this panel binding with the JUApplication object which was created
earlier.
panelBinding.setApplication(app);
A panel binding provides boths a container and a scope for Iterators. An
iterator instance is a pointer or an index into the model for a particular
control, and is created when the call is made to setDocument() or
setModel(). The control uses the Iterator to get an index into the
model (or data) and ultimately to reference the underlying rows of data in
the BC4J data source. The JClient application benefits from using panel bindings
specific to unique branches of the UI because:
-
As a container, all panels that share the same panel binding track the
state of the current or active iterator, which allows your panels to share
a Navigation Bar and Status Bar.
-
Relative to the scope, all iterators created for a given panel binding
will automatically be cleaned up for you when the last reference to the
panel binding is removed.
Consider this example, in which a separate panel binding is created for the
topmost panels of two UI branches. Perhaps the application starts with a menu
that lets the user choose different UI branches, say Orders and Catalog. The
top panel for Orders will have an OrdersPanelBinding and the top panel for
Catalog will have a CatalogPanelBinding. After the user chooses Orders and
then goes back to the menu to open the Catalog UI, the OrdersPanelBinding
will disappear and all its iterators will be cleaned up. Whereas, if the application
includes an informational dialog that users can display from both UI branches,
then it might be desirable for the application to create the panel binding
InfoPanelBinding on the frame that contains both UI branches. By changing
the scope of a panel binding, you can make the iterators persistent across
UI branches and avoid the overhead of creating the same iterators each time
the user opens a common dialog.
Understanding that the panel binding instance defines both a container and
a scope helps you decide whether to share a previously created panel binding
or to create a new panel binding when you create a new UI branch in your application.
Binding the Controls to BC4J
The final step is to actually call the SetDocument() or setModel()
method to bind the control to the BC4J data source. This is done with
the following line of code:
mDepartmentId.setDocument(JUTextFieldBinding.createAttributeBinding(panelBinding,
mDepartmentId, "DepartmentsView", null, "DepartmentsViewIter", "DepartmentId"));
Here, the document for the text field is being set. The object JUTextFieldBinding
is a helper class which will, using the parameters supplied, create a document
object which will define the binding between the control and the data source.
The parameters being passed include the panel binding, the iterator, and the
name of the BC4J view objects and attribute to which the control is bound.
At this point the JClient application checks to determine whether the panel
binding already contains the binding to the view object iterator. If the panel
binding contains the iterator, the application will reuse it. Otherwise, the
application will create and register one. Note, it is at this point where
decisions concerning sharing the existing panel binding and iterator instances
will determine your application's behavior.
In the above statement, the JClient application creates the binding and registers
listeners for that binding to the DepartmentId Swing control.
It will add this control binding to the panelBinding container and
register it in a table as DepartmentsViewIter.
Figure 4: Setting the Document for a text field
Accessing Objects through the API
Once you have an understanding of the components which make up the a JClient
UI it becomes easier to extend it. There are two main actions which
you will probably want to perform:
Referencing the Swing Control
The most obvious change you may want to make is to the visual representation
of the control. For example, to change the color of the foreground text
you would call:
mManagerId.setForeground(Color.red);
Another action you may want to perform is provide your own model (which for
example does client-side validation) and use this in addition to the default
model which binds the control to BC4J. For example:
mDepartmentId.setDocument(myModel); //Define your own model
/* The following line of code is the code which is generated for you.
This will take the existing model and bind the BC4J model "on top" */
mDepartmentId.setDocument(JUTextFieldBinding.createAttributeBinding(getPanelBind...
Referencing BC4J the Business Components
Through some UI actions (such as clicking on a button) you may want to set
a property of the underlying data: for example, filtering the data using a
where clause. This is a property of the view object and using the following
code you can access the BC4J view object.
//Get the handle to the view object
oracle.jbo.ViewObject vo = panelBinding.findIterBinding("DepartmentsViewIter").getViewObject();
//Set properties on the view object
vo.setWhereClause("LOCATION_ID > 1800");
vo.setOrderByClause("DEPARTMENT_NAME");
//Re-execute the query on the binding.
panelBinding.findIterBinding("DepartmentsViewIter").executeQuery();
Another example would be to delete a record from the view object:
//Get the handle to the view object
oracle.jbo.ViewObject vo = panelBinding.findIterBinding("DepartmentsViewIter").getViewObject();
//Remove the selected row from the view object
vo.removeCurrentRow();
//Set an indication that the transaction have been edited
if (!app.isTransactionModified())
{
app.transactionStateChanged(true);
}
Summary
While the JClient wizards free the developer from much of the code to link the
UI and the data, it is expected that developers will then modify the code to
meet their own requirements. Understanding that the panel binding instance
defines both a scope and container helps you decide whether to share a previously
created panel binding or to create a new panel binding when you create a new
UI branch in your application. Much of this information is contained within
the extensive online help; however, this white paper brings together JClient
concepts to give a simple introduction to the architecture.