Tuesday 16 December 2014

how to hide and resize fields within af:query panel

If you're using af:query forms probably you've encountered an issue with the list of queryable fields. The list should be limited only to few of them, some values shouldn't be updateable and so on. Textboxes dimensions were too big or too small. Sounds familiar?

First I'll distinguish the problem with the list of fields that are rendered within af:query. Option "All queriable attributes" is exactly what the name says. Each attribute from view object which Queryable checkbox is set will be listed there. No additional comments here.



Next, each bind variable marked as Required, or in other words, which Kind="where" will be listed in af:query by default.




To hide it just change it's Display Hint property to Hide for instance using Property Inspector.


Third and last possibility are view criterias and related view criteria rows and bind variables (which Kind="viewcriteria"). I've defined view criterias as shown below. Please go to UI Hints tab.



A bit of magic is hidden there. You can specify where the criterias should be applied (in database, in memory or both), default mode (Basic or Advanced). When Query automatically isn't selected by default you'll receive an empty row set. Otherwise the query will be executed on database. From af:query point of view i'd like to list only few view criteria rows in the panel. Just select one row from Criteria Item UI Hints and change its Render Mode to Never.


And what about text boxes dimensions? Please review the steps performed here and play with Display Width control hint :)

Thursday 27 November 2014

simplify your code by using f:attribute tags


There are keywords which you're keep telling to your developers like write DRY code - Don't Repeat Yourself. It is very important to write easy, clear and self-describing code. The less code you develope the easier you'll maintain and enhance it. Please check the "base" solution:
 


One page, one bean, two very similar actions to perform. I hope that body of the method is not copy-pasted :)

And another more declarative approach that simplifies the solution - f:attribute tag inside af:commandButton. In your page source you need to add the attributes as shown below and in the action handle method consume it/them. The effect is the same.



 Which is more important, you can use an EL expression there.

Thursday 30 October 2014

Groovy expressions in BC4J - how to debug them?

Today I'd like to share how to debug Groovy scripts in BC4J. At the beginning you must be aware that it is not possible to debug it step by step. But you can help yourself and print comments to the console in the runtime.

Two approaches are possible. First bases on Debugging groovy in ADF post. In short few words, in Model project you need to create a Java class and use it in Groovy:



But what if the expression is much more complicated. Ok, you can call it inside the expression. There is also another way to print a line in the console in Groove - use print keyword.


And, as usually, rendered page and logs output at the end of the post.



According to ADF 12.1.3 features, in 12c it'll be possible to debug it in JDeveloper :)

Wednesday 29 October 2014

debugging EL expressions in your application

Debugging java code is relatively simple. But sometimes the stack trace which you can get is unreadable. You see a lot of lines from the core of the framework and... nothing more. No additional hints where to search for the cause. But stack trace contains a lot of UI-related classes. The reason may be in the EL expression.

One approach is to comment all UI components on the page and check which expression generates an error.

Second approach is a try to trace processed EL expressions on the page. Pages are usually very complex and usually contain many EL...

It is possible to override the default EL resolver in your application. First of all, please create the class that extends abstract ELResolver class or one of its subclasses. In this example I've used MapELResolver (reasons why I've used it you'll find in the documentation).


Then point it in faces-config.xml, as shown below:


I've decided to override getValue method becasue usually an error will be thrown there.


Please note, that this is only a simple implementation that I've used to solve my problem. To fulfill the example, the page that will be examinated.


It bases on DEPARTMENTS table in HR schema. Finally, logs from the application after opening the page:


Hope it'll simplify your debugging processes in the future :)

Friday 17 October 2014

differences between getPostState() and getEntityState()

If you don't pay a lot attention to the subject of this post it'll sound the same. First of all what is the role of an entity. It is something like a mirror image of database table which takes a part during object-relational mapping process. It could contain transient attributes which aren't persisted. It can be based on other database objects than a table. But more or less we can understand an entity as database table definition in ADF.

ORM role implies on it states. I think that everyone understand that the state machine implemented there will be quite complex and the transitions will depends on operations performed on the entity. It is illustrated on the graph below:

(source: http://docs.oracle.com/middleware/1212/adf/ADFFD/bcvalidation.htm)
 
For both of the cases the graph look similar but the meaning of the states is a bit different. Entity state represents corellation between object attributes value and the database. Post state is related to database transaction itself.

Lets deeper look to entity state first. There is no default initial state for the entity. There are two states that can be assumed as defaults depends on origin. STATUS_NEW, with byte value equal 0, while current entity is created in the middleware and will be commited within the database transaction. STATUS_UNMODIFIED, byte value 1, if the current changes entity has been commited or it has been synchronized with database (read from the database).

After at least one attribute is set, entity goes to STATUS_MODIFIED (2). STATUS_DELETED with 3 byte value is when a row will be deleted. The last option is STATUS_DEAD (4). Entity has been created and after that removed within the same db transaction or it has been deleted and DELETE DML operation has been performed on the database.

Post state holds information for the transaction manager what have already been done with the data within database transaction. Post state is new when a row is created in the middleware and waits to be commited. If you delete such row it'll go to STATUS_DEAD. STATUS_MODIFIED and STATUS_DELETED are also markers for related DML operations. Interesting is the STATUS_INITIALIZED with -1 value. It excludes the row from the database transaction, so it marks it as temporary one.

These two states are tightly coupled but usually you won't need to worry about it. Framework itself will carry on the transitions. The problem that i've struggled with was while doDML entity method thrown an exception. Framework thought that the entity has been commited (getPostState()==STATUS_UNMODIFIED) but getEntityState() was still STATUS_NEW.

Thursday 2 October 2014

resolve first and last row in the af:table using varstatus

During my current project i've been asked about rendering a button for first and last row in a table. There is very simple way to achieve that without a single line of Java code. The keyword to the success is varStatus. I've prepared simple application where on the testPage i've drag&dropped sortable and filterable read only table. Also i've added few columns where varStatus properties are displayed.



What can be noticed here:
  • begin always returns 0, it's the index of first element in the collection
  • count returns the number of objects in the collection for the current step
  • current returns the reference to the current row (in the iterators loop)
  • end is supposed to return index of the last element - unfortunately it returns null
  • last is supposed to return true for the last element and false otherwise, it's null (see bug: varStatus.last working?)
  • index returns row index, could be used to display order number value for each row as #{vs.index+1} because it starts from 0
  • step is always 1 - each row from the collection should be displayed
OK, so what needs to be done to properly point the last row? Just small and simple trick:



You need to compare current row index with row count in the collection #{bindings.TheNameOfTheIterator.estimatedRowCount==vs.index+1}. The screenshots above presents filtered collection. Filtering and sorting don't corrupt the solution.

Please notice that varStatus is not only related with <af:table> but also with other components like <af:iterator> or <af:forEach> and its attribute set (and returned values) may differ there.

Wednesday 24 September 2014

list of values hierarchy in af:query

The requirement is to provide ability to search locations by counties from HR schema using af:query component. Query panel should contain list of values for countries attribute which is filtered by regions list of values field. In other words - af:query contain regions select one choice UI component which influences on countries component.

As prerequisits please create three readonly view objects based od REGIONS, COUNTRIES and LOCATIONS tables. In the application module's data model put only the LocationsView.


In CountriesView please create view criteria on RegionId attribute. Ignore null values not needed here. Bind variable is created using the wizard, so don't change it.


Please open LocationsView and add there new transient attribute called (in this example) RegionId.


Now go to View Accessors section. Please add there CountriesView and RegionsView as accessors. Additionaly please select the CountriesView1 (default name) and click on the pencil icon. Apply view criterias there and, it is important, fulfill RegionIdVar value with RegionId. It doesn't mean it'll put it as a string but it'll evaluate Groove there - it'll get RegionId transient attribute.


For CountryId and RegionId in Attributes tab please create list of values. Screenshots for begginers:



Do similar to RegionId attribute and then click pencil icon to edit it. Select Control Hints from the menu and set Auto Submit to true.


You can use implicit view criteria to develope proof of concept but it'll add view criterias and then drag and drop them on the page as query panel with table.


Running example:


What else could be done - as you can see RegionId is not used in the query, it's transient. To make it useful, please read about SQL tricks in view criterias post and try to adapt it here :)

Wednesday 17 September 2014

TaskFlow Return Value example (communication between two task flows)

One of the interesting patterns regarding communication between task flows are return value parameters. It is possible to expose more than one return parameter. Also it is possible not to use them at all. OK, prerequisites are two task flows, one will be named innerTaskFlow and the second one outerTaskFlow. First one should contain two activities, one will be the view and the second will call an action in the parent (outer) task flow.




It should also define an output parameter. For example purposes I've defined it as a String. EL expression  in the Value column points to the attribute's value.



The page itself is as plain as it could be. I've decided to put the value directly (and implicitly) into pageFlowScope memory.



As for outerTaskFlow, it consumes innerTaskFlow as default activity. In its Property Inspector I've defined what needs to be done with innerTaskFlow output attribute - put it into current pageFlowScope.




The page is just to proof that value is properly consumed there. I've defined also back flow to allow you check it few times :)


Please create also test JSPX page to run and verify the example (drag and drop outerTaskFlow on it).

The question you may have is "why do I need to assign the pageFlowScope.varName1 to pageFlowScope.varName2 instead of using pageFlowScope.varName1 in both task flows?". To answer that please review (once again, I suppose :)) ADF memory scopes.


(source: http://docs.oracle.com/cd/E24382_01/web.1112/e16182/img/adf_scopes3.png)


The pageFlowScope from innerTaskFlow is something different than pageFlowScope in outerTaskFlow. There is another way to interact between two task flows - bean injection. More or less you could pass outerTaskFlow pageFlowScope as an input parameter to innerTaskFlow:


And after that in the innerTaskFlow view activity call #{pageFlowScope.parent.retVal}. But about bean injections I'll talk about in the future :)

Thursday 11 September 2014

af:query operators

One of few tricks that I'd like do talk about refers to advanced mode of af:query component. Each queryable attribute (property of an attribute at view object level) can be a part of SQL where clause. In basic mode framework builds the query with default equal operator. In advanced mode user can pick an operator from the list. By default we've got 14 operators which, for plain business user, may sounds silly. For example how to compare surnames using "Greater than" operator. What do i get as a result?

To cut the list of such "silly" operators you need to go to the view objects source. It is not possible to acheive it using wizards. The trick requires to add CompOper sub-nodes to the specified queryable ViewAttribute with additional proper values.



Each CompOper node has several flags. ToDo flag with -1 value means that the operator will be removed from the list. I've removed most of the "silly" operators. I've also defined one "less-silly" operator just to check if adding works as nice as removing. In the source code screenshot it's the node with ToDo="1".

Test page is build as drag&drop All Queriable Attributes from iterator's Named Criteria package in the Data Control to the Design section as ADF Query Panel with Table. Run the example:



Plain and simple, isn't it? Where to get more information about it? First place that you need to visit is the Fusion Middleware Developer's Guide documentation itself on http://docs.oracle.com/cd/E14571_01/web.1111/b31974/web_search_bc.htm#ADFFD2457. And how to solve operators' names? Not need to guess, they're described in oracle.jbo.common.JboCompOper table of Java API of ADF Model that can be found on http://docs.oracle.com/cd/E15051_01/apirefs.1111/e10653/constant-values.html.

Wednesday 3 September 2014

multiple master - one detail relationship in BC4J

In most of the cases the real life structures can be simplified to one master with 0 to N details. Each detail can be a treated as a master to other details. But there are cases when the cardinality changes 180 degrees. For the first time it sounds strange to have multiple master tables that influences on the detail one but... think about plane flights. The requirement is to display two lists of airports and display flights between them. For performance point of view destination list will be dependent on the departure one. Another example, we would like to filter employees basing on both departments and jobs lists simultanously. Lookups and employees should be displayed as tables. Is it possible in ADF? It is, and it doesn't need a lot of coding! I belive you've already got HR example scheme with you.

We need to have view objects departments, jobs and employees tables (read only will be enough). Also there should be view links between them (on EMP_DEPT_FK and EMP_JOB_FK foreign keys). Model project structure should be similar to this:


Now let us focus more on Application Module Data Model definition. Please click on DepartmentsView and rename New View Instance to Departments and move it right.


Select EmployeesView via EmpDeptFkLink, rename it to Employees and move it as detail of Depatrments instance.


Select JobsView, rename it to Jobs and move it to the right. Now please select EmployeesView via EmpJobFkLink and rename it, the tricky part, to Employees.



An error? Not exactly, it will be the same instance for both Jobs and Departments. So, please click Yes. Data Model and AppModuleDataControl should look like this:



Last thing to do is to prepare test page for it. Please expand Departments node in the AppModuleDataControl, select Employees iterator and drag it to the test page as ADF Master Table, Detail Table.


Then drag and drop Jobs iterator on the test page. Select table with employees and add partial trigger to the Jobs table (partial trigger to Departments table should already be there). My page structure after simple layout rework is:


And if somebody is interested in the page definition:



The running example: