Andrejus Baranovski

Subscribe to Andrejus Baranovski feed
Blog about Oracle technology
Updated: 9 hours 12 min ago

Red Samurai Oracle JET Mobile Hybrid App Live on Android

Wed, 2016-06-22 10:38
We have implemented Oracle JET mobile hybrid app in less than 30 minutes and deployed it to Android device. This was done as a demo to the customer and could prove Oracle JET offers effective approach for hybrid mobile app development. Development process isn't much complicated with JET once you familiarize yourself with JavaScript development process and learn how to interact with REST services.

Red Samurai app based on JET (using out of the box JET template NavDrawer) is deployed on Android:


Out of the box JET allows to implement form validation, multi select and date entry controls:


Charts are rendered fast, animation is not lagging behind:


JET offers various grouping controls, to arrange content on the page:


Various types of charts can be rendered in responsive layout dashboard and are resized out of the box:


JET allows to build more complex screens, with large amount of UI components:


I'm happy with JET mobile hybrid offering. Stay tuned for more posts on this topic in the future.

Go Mobile with Oracle JET As Easy As 1 2 3

Mon, 2016-06-20 18:38
Oracle JET allows to build and run mobile hybrid applications. It is using Cordova to run on mobile device and provide access to device services. This is cool and what is great about it - it allows to get you started with mobile development in minutes. Besides all this - it is free.

I will describe steps I followed, to generate JET mobile hybrid app and run it in local browser (in the next posts I will describe how to run it on simulator and actual device).

First of all you must install Node.js and npm on your machine. This will allow to run shell environment to execute various commands related to JET app generation, setup, build and deployment. Read this article and you will learn how to do it - Installing Node.js and updating npm.

Next follow Step 1 and install Cordova in Step 5 from JET Get Started list.

You are ready to generate JET mobile hybrid app at this point. If you are on Mac OS, don't forget to use sudo, otherwise there will be permission related errors. Run Yeoman to generate the app:

yo oraclejet:hybrid JETMobileApp --template=navBar --platforms=ios

At this stage you can choose predefined JET template, here I'm generating it with navBar template for  iOS platform. It must complete with Done, without errors message:


Make sure to navigate to app folder with cd AppName:


Build generated app with grunt. Command I was using to build it for iOS (you can see from the log, it is producing *.app file, which can be deployed to mobile device as application):

grunt build:dev --platform=ios

It must complete with Done, without errors:


Run application to test in local web browser. See more options (deploy to simulator or device) here - Serve a Hybrid Mobile Application with Grunt. Use grunt command:

grunt serve --platform=ios --web=true --disableLiveReload=true

I'm running it with disableLiveReload=true for a reason. It seems like live reload initialization takes long time to start. Template based JET mobile hybrid app is started (in web browser, for testing):


Generated project can be opened in NetBeans, simply select project from the folder:


Under src folder you will find JET content. Try to change text in any of the generated pages:


Rebuild and serve application, you should see changes deployed for customers page in this case:

ADF BC Range Paging and ADF UI Table Pagination Use Case

Sat, 2016-06-18 09:45
ADF UI table pagination and ADF BC range paging sounds like a perfect combination. But to make it work perfect, a bit of extra effort is required. In the case of search/edit implementation, it can't remember updated record when navigating back to search screen (VO runs with Range Paging and UI table is displayed with pagination). I will explain how to solve it and show how to keep UI table displaying current page and prevent jumping to the first page.

Here is the working use case (download sample application - SearchEditApp.zip). Navigate to any page except first in UI table and select a record:


On edit, selected record should be opened in the fragment. Both buttons Save and Close/Close would return back to search screen, where current record and page should be preserved:


Close button will trigger Rollback operation, but current row should not be lost (see solution here: ADF Rollback Operation and Stay On Current Row):


Current row and page remains selected on return to search fragment:


Huge advantage of Range Paging mode for VO - faster navigation between UI table pages. This is especially important now, when we support pages. It is much easier for the user, to navigate to the last page (one click, without scrolling). We must ensure fast navigation in the table. This can be achieved with Range Paging - it will force VO to generate SQL query with ROWNUM and what is also very important - it will fetch only a subset of data (by default, ADF BC would fetch all rows until last, when navigating to the last page). Here we navigate to the last page:


Example of SQL query generated by VO enabled with Range Paging and subset of row data fetched for last page:


To force UI table to return display to correct page (navigation to search from edit), when Range Paging is enabled in VO - make sure to set first property for UI table (see solution here: ADF Rollback Operation and Stay On Current Row). We should keep track of current range start before navigating away from search screen and reset it back to the same value, when navigating from edit. I'm keeping this value in pageFlowScope variable managed through the bean method invoked on edit:


This is the method - it keeps track of current range start and updates pageFlowScope variable (later referenced from first property on UI table):


Bonus - see example how to refresh VO data (this is useful, when you want to display latest data to the user, before he starts editing it) and keep current row. When Range Paging is enabled, current row can be retained by re-setting current row key obtained from iterator binding (this executes SQL with find row by key and returns only current row):

Using the Oracle JET QuickStart Template

Tue, 2016-06-14 09:38
I will show in the post, how you can create single page applications with multiple modules in Oracle JET. As a starting point, you should use the Oracle JET QuickStart template, read about it here. This template comes with sample structure and you could follow it to split application functionality into different groups.

Download sample application, which is based on Oracle JET QuickStart template - JETCRUDApp_v10.zip (you must run ADF BC REST application in JDEV 12.2.1 and JET in NetBeans 8). QuickStart application is extended with new module, it contains CRUD implementation in JET (read more here).

I have slightly modified template and removed boxes for navigation and complimentary areas. It renders main content block stretched on the screen:


Under Employees tab, CRUD functionality to manage employees data is rendered. This includes CRUD functionality described in my previous posts about JET (see link above). Now it is part of real JET application:


Let's take a look into structure. QuickStart template comes with structure, where each module is separated into HTML/JavaScript files. There is a group available for employees CRUD - employees.html and employees.js:


Main page logic is implemented in index.html. This file includes page structure and references block with dynamic module (loaded through menu structure):


List of available modules is registered in main.js file router:


JET CRUD functionality use case HTML part is copied into employees.html file (this will be loaded through main.js router):


JavaScript part is copied into employees.js file:


JavaScript logic is changed to handle table row selection event through JavaScript listener method. Constructed employees view model is returned to be accessible from the router:

How To Control Row Removal in ADF BC

Sat, 2016-06-11 11:28
There is a flaw in ADF BC remove operation. Row could be successfully removed in ADF BC - it dissapears from UI as well, but if there is DB integrity constraint violation - row is not removed in DB and error message is displayed to the user. This could be misleading to the user, he sees message about failed removal, but at the same time row is not present anymore.

Easier to explain with example. Let's imagine we want to remove IT_PROG job (there are employees assigned with this job and row removal would fail in DB):


On delete, row is removed from ADF BC and UI, but operation fails in DB and error is returned:


ADF BC completes row removal before row is really removed in DB. This is why ADF BC doesn't really know about failed row removal and is not able to keep it.

Technically such behavior is valid, but hardly understandable for business user. If row is not removed it should stay in the application.

We could solve it by overriding doDML method and executing row removal through custom method defined in VO implementation class. In doDML we can catch DML constraint exception during delete and execute refresh for removed row. Removed row is accessible in doDML, it is not dead yet. Calling refresh would allow to fix row state. We should throw exception and catch it in VO implementation class method, to refresh rowset and set back current row:


Custom method to execute remove in VO implementation class. Current row key is saved before remove and restored in case of exception. We must call executeQuery to refresh rowset, before setting back current row. In this example, commit is called right after row is removed. This allows to produce DB constraint error and process it in the context of VO. You may implement similar logic from global commit method, in such case you would need to include information about VO to be refreshed into exception message (raised in doDML):


Try to remove the same IT_PROG row now:


Failed row removal message is displayed and row remains in the application:


Download sample application - ADFDeleteControlApp.zip.

UKOUG Slides - Forms, ADF and JET a Non-Aggression Pact

Thu, 2016-06-09 13:43
Florin Marcus was presenting topic on Forms modernization during UKOUG Development SIG seminar in London. Session was based on our production experience from recent Forms modernization project to ADF 12c and Alta UI.

Highlights:

- Who integrates Forms and ADF?

- Java Plugin to be Discontinued. Consequences for Oracle Forms.

- Why Yet Another Web Framework? Oracle JET.

- Forms and ADF and JET - Business Integration Patterns

- Forms Developer's perspective: life after learning ADF

Go through the slides and learn more about it:

Oracle JET Executing Dynamic ADF BC REST URL

Tue, 2016-06-07 10:56
I'm going to explain how to call ADF BC REST service from JET API and how to control parameters passed through to REST URL. Most of the time, REST should return data based on different parameter values, URL is not static. I will be exploring two cases - search functionality, where parameter value is entered by the user and LOV functionality, where current employee key is submitted to fetch colleagues list.

You can go through the slides from my AMIS25 session - Oracle JET CRUD and ADF BC REST. I explain similar concepts:


Download sample application (you must run ADF BC REST application in JDEV 12.2.1 and JET in NetBeans 8) - JETCRUDApp_v9.zip.

1. Filter implementation

We should take a look first, how filter/search functionality is implemented. User enters keyword for Last Name and filters data in JET table:


User can reset search results, change filter criteria. Filtering is done using startswith operator, by ADF BC VO (it creates temporary bind variable from REST URL parameter q=LastName LIKE value):


Filter block is implemented in a separate HTML div. Filter value is mapped with observable variable registered in JET View Model:


Table collection is based on collection with dynamic REST URL. URL is calculated through customURL property (referencing JavaScript method) in the collection. On filter event, we clear up all dependent data and call JET collection API method - refresh(). This ensures reload for collection and REST URL re-calculation. Similar is done on reset:


Method getURL is responsible to read filter value and construct REST URL accordingly (this will be used to re-fetch collection content):


Here you can see generated REST request URL logged by NetBeans Network Monitor. This URL contains filter information supplied through dynamic REST URL defined for the collection:


2. LOV data fetch implementation

There is LOV in ADF BC, which returns current employee colleagues (employees from the same job, except employee himself). ADF BC REST encapsulates parameters complexity and allows to simplify REST request. JET UI renders LOV data in a chart:


Each time when employee record is selected, we execute dynamic REST call (with new employee ID) to fetch colleagues collection:


This is chart definition in JET UI, it references observable variables for series/groups from JET View Model:


Similar as in the case with Filter, we supply dynamic URL for the collection, using property customURL:


Differently than in the Filter implementation, here we dont refresh collection. We execute JET API method fetch(...), to retrieve new collection and we push contents into observable variables, referenced by chart component in the UI:

Oracle JET Handling ADF BC 12.2.1 REST Validation Event

Sat, 2016-05-28 11:32
I already had a post about how to handle ADF BC validation messages in Oracle JET - Handling ADF BC 12.2.1 REST Validation in Oracle JET. There is an improvement I would like to share. JET submits data to ADF BC REST and there happens validation. In JET perspective data is correct, however it may fail validation in ADF BC and we need to reset values back to original in JET. Previously I was re-executing entire JET collection, drawback of this approach - current selected row was lost and control was returned to the first page in the table configured with pagination.

With improved solution, current row remains selected one, even if ADF BC returns failure for validation event. As you can see in the example below:


Callback method for JET model save API is set to parse ADF BC validation messages and at the end to refresh current row model. Current row is refreshed by re-fetching row data, only one row data will be re-fetched from REST. Previously entire collection was refreshed, causing current row reset:


Download sample application - JETCRUDApp_v9.zip (you must run ADF BC REST application in JDEV 12.2.1 and JET in NetBeans 8).

Oracle JET Master-Detail with ADF BC REST

Thu, 2016-05-19 11:37
One of the most typical use cases in enterprise applications - Master-Detail relationship implementation. I have decided to implement it in JET and to share this practical implementation with you. Hopefully it will be useful, when you will be learning and building JET applications.

Sample application - JETCRUDApp_v8.zip implements a table with row selection in JET (you must run ADF BC REST application in JDEV 12.2.1 and JET in NetBeans 8). On row selection, Job ID is retrieved from selected row and based on this - Job data is fetched. Minimum and Maximum salary values are fetched from Job data and displayed in the chart, along with selected employee salary. I'm executing separate REST call for each new selection in the master and detail data change, see how fast data is being changed in the chart:


Detail data displayed in the chart is fetched based on Job ID selected in the master table:


Each time when new row is selected in the table, chart is changed (REST call to ADF BC is executed in the background, using Job ID for selected employee as a key):


Great thing about JET - it is responsive out of the box. On narrow screen, UI components are re-arranged into single column layout. Editable form is displayed below table:


Chart is displayed below editable form:


Let's take a look, how detail data displayed in the chart is fetched. First of all chart UI component is defined in HTML, it points to series value observable variable:


This observable variable is defined as array in JavaScript. Observable variable allows to push value changes to UI automatically, without additional intervention:


I have defined data structure for Job response, this includes JobId key, Minimum/Maximum values. REST URL will be assigned later, in the table selection listener. This URL will change for each selected row, to retrieve different REST resource. We leave model definition without REST URL here:


Table selection listener creates new model and executes fetch operation for the job. REST URL with Job key is constructed to fetch required detail data. In the success callback returned data is accessed and pushed into observable collection, which is displayed in the chart:

We are Hiring - Red Samurai ADF and JET Team

Tue, 2016-05-17 02:19
Do you want to join Red Samurai force and become one of our technical experts? The moment is now - we are looking for additional team player.

You should be strong in ADF, highly preferable to be confident with JavaScript and Oracle JET. It never hurts to be fluent in PL/SQL and understand Oracle Forms. You will work in Red Samurai projects focused on ADF and JET.

What would be your position? You name it - you will get a chance to wear multiple hats - expert ADF or JET developer, performance tuning specialist or the guy who solves unsolvable.

Don't wait - drop me email: abaranovskis at redsamuraiconsulting dot com

ADF Hidden Gem - Export Collection Listener

Mon, 2016-05-16 13:02
How many times you complained about ADF export collection listener generated output? There are two options for the output - CSV and excelHTML. Both of them are not really Excel friendly (Excel complains, each time when such file is opened) and produced output lacks formatting. Luckily there is a way to specify custom formatter for ADF export collection listener and set your own output type. In this way we can produce better and customized output file for Excel, you can construct Excel document with different formatting and layout.

Demo application with custom formatter for ADF export collection listener is available on GitHub repository - rs-export-xls. This was implemented by Red Samurai Consulting colleague - Fedor Zymarev. You are free to check-out the source code - use it in your projects and add new formatting features.  It would be great, if you could contribute to the community and commit any improvements - simply request merge approval into master on GitHub repository.

Demo runs with the entry page, which contains ADF UI table with Export all/selected rows options:


This is how Excel output looks like. There is a placeholder for worksheet title, header is highlighted and format is recognized by Excel:


You only need to set custom type (RSExcelExport) for ADF export collection listener, instead selecting excelHTML available by default:


Custom type is not available in the list of options, you should type it:


Format type is defined with Java class registered in oracle.adf.view.rich.export.FormatHandler text file, located in ADF META-INF/services folder:


Formatting implementation logic take place in RSExcelFormatHandle class. We are using Apache POI, Java API for Microsoft documents, to prepare native format for Excel:

Oracle JET Input Search with ADF BC REST

Sat, 2016-05-14 14:33
LOV is popular component in ADF, it allows to seach for data entry in the list, select it and assign to the attribute. I was researching, how similar concept can be implemented in Oracle JET, based on data from ADF BC REST service. JET Input Search component seems to be useful for LOV like behavior implementation.

Job ID field is implemented with Input Search. It is based on value/label pair, user enters label and in the background selected value is returned and assigned to the attribute:


Watch this recording, to see how was it is. Search is performed on client side and value selection is instant:


List is being filter when user types value (you can configure it, to start filtering after user enters certain number of charachters):


Try to select a value from the list and update record:


In the background it is using key value SA_REP for update, we can track it in ADF BC log, where actual DB update takes place (through REST PATCH):


Let's take a look into implementation. In HTML I'm using ojInputSearch component with value and options properties. Property options provides list entries and property value holds selected value key:


Options are defined in JavaScript as observableArray, this allows to synch collection data to the UI. There is collection for options and REST service URL (pointing to Jobs ADF BC REST resource):


Data structure is defined by parseJob function, it contains JobId and JobTitle attributes - this will help to map REST response into JET collection:


JET collection is configured with REST URL for Jobs, unlimited fetch size (to fetch list of all jobs) and data structure mapping for REST resource:


Main part - we need to populate JET collection with data, this can be done by executing fetch method (see JET API documentation). In the success callback (executed asynchronously), we can access returned collection and push all entries into observableArray variable, attached to Input Search UI component:


Make sure to set RangeSize = -1 in ADF BC REST service resource definition for Jobs. This will enforce ADF BC to return all rows:


Download sample application (archive contains ADF BC REST sample and JET implementation with NetBeans, you must add JET runtime distribution to run JET sample) - JETCRUDApp_v7.zip.

Oracle JET 2.0.1 - Upgrade for CRUD Sample

Tue, 2016-05-10 09:39
Oracle JET 2.0.1 was released in April and I decided to upgrade my CRUD sample (based on ADF BC REST services) implemented with previous JET version. There is migration guide, describing main points to consider, while moving to the next JET version. I'm going to add few more points. Hopefully you will find it useful.

Here is CRUD sample UI running with Oracle JET 2.0.1 and interacting with ADF BC REST:


This sample comes with advanced validation rule integration, which is being enforced in ADF BC and propagated to JET UI (read my previous posts about this):


As per migration guide, you must update reference for Alta CSS (2.0.1):


Next update module names in main.js:


CRUD app is rendering paged table out of collection table datasource. Somehow it worked previously, without specifying ojs/ojcollectiontabledatasource module, now it must be specified, otherwise there is error about constructor:


There are changes on UI side. I have wrapped table/form into div with oj-flex-items-pad (includes padding). Table and form and places into separate div's, with oj-flex-item class:


To enable table pagination, I moved it out of div, in previous version it worked inside separate div:


Form group elements are wrapped into oj-flex/oj-flex-item class, this creates better layout for form items:


Update method was changed to handle ADF BC validation error in slightly different way. I'm showing error first and next resetting collection data - to return original value into the table.

Download sample application - JETCRUDApp_v6.zip.

Red Samurai ADF Performance Audit Tool Major Update v 5.0

Tue, 2016-05-03 14:42
Our ADF performance audit tool is growing and getting more advanced with each release. Current major update v 5.0 brings ADF Click History integration and allows to track ADF UI client request time. This allows to understand, how long it takes to execute action from user perspective. Combined with ADF BC performance monitoring, we could give precise answer about performance bottlenecks from top to bottom.

New features in v 5.0:

1. Redesigned UI with ADF 12.2.1 Responsive template. UI is aligned with Alta UI best practices

2. Group by ECID functionality. We can track request action from top to bottom. This includes client request time (time needed to complete action on UI, including network traffic time). Executed SQL queries and any issues in ADF BC performance for the given request

3. ADF Click history logging. Click history data about UI performance is being intercepted and logged into Red Samurai DB, for analysis. This gives a database of all user requests and time for each request

4. User request statistics visualization dashboard

Here you can see sample data from ADF demo application. User request statistics are presented to help in understanding system performance. Time for each user request is visualized, along with detail information about request (component ID, name, type, etc.). Average times are presented, along with user statistics and top actions. We display total requests count vs. recent requests, to visualize the load on the system:


Each of the logged requests can be tracked down by ECID. Here we can see a list of VO's invoked during UI request and any slow performance behavior happening in ADF BC:


In the next updated v 6.0, we are going to implement UI behavior analysis, to extract most common UI usage patterns in ADF application.

Optimize ADF HTTP Response Size with ChangeEventPolicy

Tue, 2016-04-26 03:18
You should read this post, if you are looking how to reduce ADF HTTP response size. This can be important for ADF application performance tuning, to improve PPR request response time. By default in ADF 12.2.1, iterator is assigned with ChangeEventPolicy = ppr. This works great for UI component bindings refresh, no need to set individual partial triggers. On other side, this generates extra content in ADF HTTP response and eventually increases response size. I would recommend to use ChangeEventPolicy = ppr, only when its really needed - dynamic forms, with unknown refresh dependencies. Otherwise set ChangeEventPolicy = none, to generate smaller response.

I will demonstrate below the difference for ADF HTTP response with ChangeEventPolicy=ppr/none. First let's take a look into page load response size:


Page contains list component and form. Both are based on two different iterators, set with ChangeEventPolicy = ppr. This generates AdfPage.PAGE.updateAutoPPRComponents calls for each UI item, referencing attributes from the iterator. In complex screens, this adds significant amount of extra text to the response, could increase size even by half:


Partial response also contains same calls added to the response. Select list item:


Each item from the form will be referenced by JavaScript call, to register it for refresh:


Let's change it to ChangeEventPolicy = none. Set it for both iterators:


We should set refresh dependencies manually. Form block must be set with PartialTrigger, referencing list component - to refresh, when list selection changes:


Next/Previous buttons dependency also must be set, to change form row:


With manual refresh dependency changes, there are no extra calls added to ADF HTTP response, reducing overall response size:


Same applies for PPR response:


Download sample application - ChangeEventPolicyPPRApp.zip.

ADF 12c Custom Property Groovy and AllowUntrustedScriptAccess Annotation

Sun, 2016-04-17 04:41
To execute Groovy expression in ADF 12c (to call Java method from Groovy), you must specify trusted mode. Read more about it in my previous post - ADF BC 12c New Feature - Entity-Level Triggers. Setting mode to trusted, works in most of the cases. It doesn't work if we want to execute Groovy expression (calling Java method in ViewRow or Entity class) for custom property. In a case of custom property and Groovy calling custom method, we need to annotate Java class with AllowUntrustedScriptAccess. This makes a trick and Groovy expression can call custom method.

To demonstrate the use case, I was using mandatory property. This is standard property to control if attribute is required or no. By default, mandatory property is static, but we can make it dynamic with Groovy expression. I have implemented a rule, where Salary attribute is required, if value is more than 5000:


Salary is not required, if value is less than 5000. This is just example, you can implement more complex logic:


There is a method in ViewRow class, to calculate required property for Salary attribute:


Method is callable from custom property Groovy expression, as we have set annotation AllowUntrustedScriptAccess for ViewRow class. Annotation definition, must list all allowed methods:


Here you can see Groovy expression, to call ViewRow class method - mandatory. Expression is assigned for custom property, this will be referenced from ADF UI:


There is issue with JDEV 12c, it fails to parse custom properties set with Groovy expressions. It fails to parse and removes custom property from the code. To prevent such behavior, specify empty string for custom property value (this will allow to keep Groovy expression):


Luckily in this case of mandatory check, JDEV by default generates mandatory property for ADF UI component. We simply override its original value with custom property and calculate new value in custom trusted method, referenced by Groovy expression:


Download sample application - ADF12cGroovyCustomPropertyApp.zip.

Monitoring ADF 12c Client Request Time with Click History

Sun, 2016-04-10 12:55
You must be excited to read this post, I will describe one very useful feature, available in ADF 12c. This feature - Click History. You can follow steps described by Duncan Mills, to enable and read click history data in server log. There is one more option available - we can read click history data from ADF request (captured by filter class) and log it in custom way (for later analysis). Click history gives such information as client request start/end time (you can calculate client request duration), component client ID, component type, action event type, etc. All this is useful to understand application performance perceived by the client.

Download sample application - DashboardApp.zip (it contains JET libraries, to render JET content within ADF). To test click history and view generated statistics, click on any button and selection component. Click history returns previous action statistics. Let's click on Cancel button:


You should see similar XML message printed in the log (click history statistics data):


To view it in readable way, you can copy it into XML file and format in JDEV:


Logged properties, useful to track client request performance:

1. CID - ECID number, identifies request
2. CST - client request start time
3. CET - client request end time
4. ETY - client event type
5. CLD - client component ID
6. CTY - client component type

XML message can be parsed and property values can be logged to DB for performance history analysis.

To enable click history, you only need to set parameter (true) in web.xml oracle.adf.view.faces.context.ENABLE_ADF_EXECUTION_CONTEXT_PROVIDER:


To read click history data from ADF request, we need to define custom filter in web.xml. Register filter under Faces Servlet:


In the filter, override doFilter and retrieve oracle.adf.view.rich.monitoring.UserActivityInfo parameter (this will return click history XML string, as above):

ADF BC View Criteria Query Execution Mode = Both

Thu, 2016-04-07 10:55
View Criteria is set to execute in Database mode by default. There is option to change execution mode to Both. This would execute query and fetch results from database and from memory.  Such query execution is useful, when we want to include newly created (but not commited yet) row into View Criteria result. Newly created row will be included into View Criteria resultset.

Download sample application - ViewCriteriaModeApp.zip. JobsView in sample application is set with query execution mode for View Criteria to Both:


I'm using JobsView in EmployeesView through View Accessor. If data from another VO is required, you can fetch it through View Accessor. View Accessor is configured with View Criteria, this means it will be automatically filtered (we only need to set Bind Variable value):


Employees VO contains custom method, where View Accessor is referenced. I'm creating new row and executing query with bind variable (primary key for newly created row). View Criteria is set to execution mode Both, this allows to retrieve newly created row (not commited yet) after search:


View Criteria execution mode Both is useful, when we want to search without loosing newly created rows.

Change ADF BC Data Update Locking with FOR UPDATE WAIT

Wed, 2016-03-30 08:43
Each time when data is changed and updated through ADF BC, before posting changes to DB, SQL query with FOR UPDATE NOWAIT is generated and executed. In case if other process locks row to be updated, or another user in the same moment is updating it, error will be generated and update will be stopped. There might be use cases, when you would like to wait for certain period of time, until row will be unlocked and then commit row changes. This is especially true, if 3rd party (PL/SQL) process is updating rows and you have defined change indicator attribute in ADF BC (see my previous post - ADF BC Version Number and Change Indicator to Track Changed Rows).

We can change default behavior, instead of requesting for immediate lock - we can wait a period of time. If lock becomes available during this period, session acquires lock. If row remains locked, error is returned. Instead of default FOR UDPATE NOWAIT, we can generate FOR UDPATE WAIT (time period in seconds).

To override default behavior, we need to specify custom SQLBuilder class. This can be registered in Application Module configuration jbo.SQLBuilder property:


Class must extend from OracleSQLBuilderImpl and override getSqlVariantLockTrailer() method. My sample application is implemented to return FOR UPDATE WAIT 30:


We can do a test. We can simulate PL/SQL lock by executing SQL query with FOR UPDATE from SQL Developer:


Try to update same row from ADF BC with default behavior, error will be returned - "Failed to lock the record, another user holds the lock". This is expected, because row remains locked:


With overriden SQL Builder, FOR UPDATE WAIT 30 is generated. It waits 30 seconds, as soon as lock is removed - lock from current session is set and row data is updated:


Download sample application - LockUpdateApp.zip.

ADF BC Version Number and Change Indicator to Track Changed Rows

Fri, 2016-03-25 11:12
One of the common use cases in enteprise applications is to track concurrent user changes. There are two types of changes possible - when two real users are changing data in the same row, or when single user is changing data and same row is updated by PL/SQL procedure/function (all happen in the same user session). In the first case, we would like to inform a user - row data was changed (two different users changing data). In the second case, there is no need to inform user (data wasn't changed by another real user, it was changed by PL/SQL function/procedure invoked in the same session).

ADF BC by default tracks all attributes and checks if they values were changed. This would mean, if any attribute value is changed directly in DB, EO cache will be out of synch and changed row error will be reported. We can minimize number of attributes to be checked to single attribute - Version Number. There must be additional number type column created in DB table, we are going to use it for Version Number in the EO. EO attribute should be marked as Change Indicator and set to be "version number" in Track Change History property. This means, row will be considered as changed by another user, only if Version Number attribute value will be changed. All changes happening directly from PL/SQL will not increment Version Number (it will be incremented only for the changes submitted from ADF BC):


There should be new column created in the DB for Version Number attribute:


Let's see how it works. I will use two different browser sessions, to simulate two users. Change value for First Name, take a look into Version Number. Value is equal to 4, before Save:


Data is saved successfully to DB. New value 5 is assigned automatically for Version Number:


Switch to different session now. Version Number is equal to previous value 4 (this session was opened before recent commit from first session). Both sessions are working with the same row. Change value for Salary:


Try to save this change. You will get standard error message, informing user about changes in the same row. This happens, because Version Number value doesn't match with recent Version Number for the same record:


At the same time, Version Number is synchronized automatically (updated to 5) and user can try to commit his changes again. This time data is saved and Version Number is increased to 6:


We should check now, how it works data is changed in the DB directly, without increasing Version Number (the case of update happening from PL/SQL). I'm changing Employee_Id = 100 record directly in DB (changing Salary value). Version Number is not changed:


Go back to Web session and change First Name value, press Save:


Despite data was changed in DB, save was successful - Version Number was recent. First Name was successfully changed and Version Number was increased to 7:


Download sample application (make sure to create manually VERSION_NO(10, 0) column in the EMPLOYEES DB table) - ADFChangedRowApp.zip.

Pages