It happens to face exceptions in production environment, even if during development and testing everything was working good. In most of the cases, this strange behavior will be related to wrong transient attribute usage, transient attribute which value is not passivated and then its lost after activation. You can test your code, if it contains any bad practice implementations, by disabling application module pooling. Most of ADF developers know this, however only few really understand what is happening. Today I will present sample case, where bad practice is demonstrated practically.
Let's say developer decided to store temporary values in VO transient attribute and created new DummyAttr attribute in Employees VO:
Developer thinks - since I already have my temporary value in VO, why not to use it for another, this time permanent, attribute. And he calls transient attribute from permanent attribute getter method:
Thats it, Model is implemented. Next step, transient attribute should be somehow initialized. Its easy in ADF, we can use af:setActionListener component and initialize attribute directly from ViewController:
In our case, DummyAttr will be assigned with DepartmentName value:
At this point, functionality is implemented and can be tested. On runtime, transient attribute will be initialized in Departments page:
Employees page will be successfully opened:
Everything works good during testing. In production, when there will be high workload and many concurrent users, ADF will start to passivate Application Module instances and we will face a problem with such implementation. Production environment can be simulated by disabling Application Module Pooling:
User will open Departments page and will set transient attribute value:
Will try to open next page - Employees, and will get java.lang.NullPointerException. Why? Let's find an answer in detail log. When there is not enough space in the pool (during next submit in our test case), and Application Module instance is passivated, transient DummyAttr attribute value was not passivated and this means it was simply lost:
There is nothing to activate for transient DummAttr attribute, and since this attribute is called, exception is raised.
You should avoid such use cases as I just described and develop proper quality ADF code. In worst case scenario, which is not recommended anyway, you can force transient attribute passivation on attribute level:
Or even on VO level:
Then you can see that transient attribute will be passivated as well:
This means, code will work without exception, because activation will be done successfully. However, in my opinion, you should avoid this approach and use it only when you are really forced.
Download sample application, where Application Module Pooling is disabled and described bad practice is reproduced - AppModulePooling.zip.
so what is the way to avoid this approach?
ReplyDeleteJust not to use this approach :) Make sure all transient attributes are recalculated. Store temporary values in UserData on ADF BC level or in PageFlowScope in Controller.
ReplyDeleteRegards,
Andrejus
This comment has been removed by the author.
ReplyDeleteAndrejus,
ReplyDelete(I deleted my last post, and would like to replace it with this one if you don't mind. I left some things out and had a grammatical error or two I would like to fix.)
First thank you so much for posting this subject, and all your other extremely helpful blog entries.
Second, I think the class of issues surrounding what is tested when AM Pooling is shut off is a bigger issue than would be sensed just going by the lack of documentation and help available on the subject of "fixing bad things that happen when you shut off AM Pooling". I think Oracle's JDeveloper team should create a whole book devoted to this subject frankly. Here is why: the problems that are left over when you don't shut off AM Pooling as part of your application testing regimen, give everybody (Oracle, ADF, Oracle ADF Programmers, the contractor that hired you to do the work, etc.) a black eye and a bad name. This is because this class of insidious problems causes the uneducated developer (which you admitted is most ADF Developers in this case) to deliver products which will fail in ways which are very very hard to troubleshoot for those uneducated Developers.
And when you do this testing the problems that arise are often just as hard to understand, zero in on, and fix.
It is a short sighted approach (like not flossing because it is inconvenient) to focus on neat gui gadgets and components, and to not zero in on this issue and eradicate it. Yes I am calling the lack of documentation on this subject short-sighted. If Oracle thinks that having applications act unreliably in production with errors that are mystifying their developers will not hurt sales...then they need an IQ test or something.
That said, if such documentation already exists, I would really really appreciate knowing where to go to continue to get educated better on these AM Pooling-shut-off problems...
Michael Fons
Hi Michael,
ReplyDeleteThank you for such really interesting comment.
I agree with you - too often Oracle is focusing on popular and cool UI features, but not paying enough attention for heavy technology topics or improvements.
I hope this will change this or next year, we have pretty stable JDeveloper release, this means they can work on improvements.
Regards,
Andrejus
Andrejus,
ReplyDeleteWould you mind looking at my semi-rant I had today on the forum? It has to do with bc4j.xcfg properties, and some odd stuff that appears to be happening in my opmn log.
http://forums.oracle.com/forums/thread.jspa?messageID=4127259#4127259
Andrejus, this is an illuminating post but I'm a little confused about how to workaround the problem.
ReplyDeleteI'm not aware of a way in which we can 'make sure that all transient attributes are recalculated' (maybe by re-executing the query?). I think you'll agree, that a value that at any random moment can become null is a fairly useless one.
IMO nasty problems like this are the reason this stateful model for business components is just totally the wrong approach. The AM module pooling and passivation is an unholy mess, and one of the most significant reasons I wouldn't recommend ADF to a friend. The ironic thing is that most applications don't actually need these over-complicated features in the first place, they simply suffer from the consequences.
Hi,
ReplyDeleteYou just need to make sure, transient variable always gets data. Follow best practices, and all will be good :) And use ADF features, avoid custom coding.
Regards,
Andrejus
thanku for letting us know such information and you made us to get rid of this kind of variables
ReplyDeleteHi,
ReplyDeleteDo we need to passivate the calculated/transient attributes of an LOV VO which is based on a sql query.
The LOV VO is based on a sql query and created the LOV on someother VO's transient attribute. In this case, do we need to passivate the LOV VO also. We already passivating the VO where the LOV is created.
All transient/calculated attributes are not passivated by default. You should disable AM pooling, and test if nothing breaks.
ReplyDeleteAndrejus
Hi!
ReplyDeleteI have 2 VO.All attributes are calculated. This VOs have attribute CODE(with checked passivate for two VO) mapped to sql. For one Vo this attribute is passivated, for another - NO, as a result I have NullPointerException!
Query for VOs is the same!
What can I do?
Hm..., may be call Red Samurai? :-)))
ReplyDeleteAndrejus
OK. Very helpfull advice tocall Red Samurai or somebody else!!!
ReplyDeletethanks...
Advice is equal as a question. Please provide more details, create sample application to reproduce the case, etc.
ReplyDeleteIts pretty hard to give correct answer to such level of question, there might be many reasons what can go wrong.
If there is no detail description, you can call us onsite and we fix all issues :)
Andrejus
Hi Andrejus,
ReplyDeleteWhen I disable the AM Pooling to test the application as in production environment. them all the LOVs lost their bindings after any action on the form.
What the problem I have and how to avoid this kind of bug?
Thank you
HaDV
Something is very wrong with app implementation. It should not happen like that.
ReplyDeleteAndrejus
Thank you for your reply. I found that, after commit the current row was lost so I cannot do any action on the current open form anymore.
ReplyDeleteCan you have a way to keep the current row of the view object after commit?
Thank you so much!
Hi Andrejus,
ReplyDeleteYes, you're right! The built-in selectOneChoice was not lost their binding data but our customize auto-suggestion component was lost their binding data after commit.
And one more problem is after commit the current row was also lost. Do you have a solution to keep the current row after commit?
Thank you
HaDV
Hi,
ReplyDeleteAfter commit - current row is usually not lost. You should check in the log - may be there is rollback executed after commit?
Andrejus
Andrejus,
ReplyDeleteI checked and there's no rollback after commit. And I found that the current row is only lost in the create new form (CreateInsertWithParams). In the edit form (ExecuteWithParams), the current row is kept.
Do you have any idea about the different between the two?
Thank you
What you mean by current row in Create form? Is it new row that is inserted or the one you had opened before creating new one?
ReplyDeleteI always have idea :)
Andrejus
The current row that I mentioned is the new inserted row. I want to keep this current row because I need to do something else with this current row after commit.
ReplyDeleteWhat if you try this approach: http://andrejusb.blogspot.com/2013/03/adf-rollback-and-keep-current-row.html
ReplyDeleteAndrejus
Thanks Anderejus, I will try and report the result later!
ReplyDeleteAndrejus, Please help as we have unique case. We developed VO with only transient variables, which is being populated by calling Stored Proc. This VO has been incorporated as Tree Table in UI. This data of tree table is not being persisted for some reason. We did everything as mentioned in the ADF documentation as well in your blog and changed all properties. Please give some pointers. Many Thanks for the article and for your help. Cheers, Sachin Gupta
ReplyDeleteThanks for Article. I see in one of your image in this blog that we can print what is being persisted during passivation. Can you please share how this can be enabled ? In my case, I can see that activation/passivation is kicked-off but I am not able to print that. Thanks.
ReplyDeleteSachin
Hi Sachin,
ReplyDeleteI think that you can persistent the transient attribute by enable passivate state (Including All Transient Value) in the VO
Gud Luck!
We had same problem statement as sachin and set passivate properties for VO, still it is not getting activation/passivation safe.
ReplyDeleteYou can set FINEST log level for oracle.jbo package. This will allow to see what is being passivated/activated.
ReplyDeleteRegards,
Andrejus
Hi Andrejus,
ReplyDeleteI have a programmatic vo which doesn't contain any key attribute. I have tried your approach but still getting the exceptions while running by disabling application module pooling. Can you pls look into this post. https://community.oracle.com/thread/3997370 and give me a solution for that.
Best Regards,
Raju Chetri