Often we need to access environment variables across all layers of ADF (Model and View-Controller). Usually we store environment variables in session scope, this makes them accessible for the duration of user session. Its common practice to retrieve values from session scope in View-Controller layer. However, is not so common to access session scope from ADF BC. Somehow there is such preconception, that its not possible to access session scope variables from ADF BC. But its possible (no need to add JSF libraries into Model) and I will explain in this short post how to do this.
If we want to store custom variable values in ADF BC, we can use UserData object - adf.userSession.userData. But this approach is not attractive - UserData is reset during passivation/activation and all custom variable values will be lost. Instead, we can store custom variable values in session scope. Download sample application - SecurityFormLogin_v2.zip.
Sample application populates environment variables during Login action (it sets server name and port):
Environment variables are stored in HTTP session, means accessible from session scope.
Now main topic of this post, you can access HTTP session from ADF BC by getting session scope from ADF context:
In this example, we are retrieving server name environment variable from HTTP session scope inside ADF BC prepareSession(Session) overridden method.
Let's test if value is not lost during passivation/activation. To test this, simply disable Application Module Pooling option from Application Module configuration:
Open sample application, login as redsam/welcome1:
Now, because AM pooling is disabled - on each request (button click) passivation/activation happens:
If we want to store custom variable values in ADF BC, we can use UserData object - adf.userSession.userData. But this approach is not attractive - UserData is reset during passivation/activation and all custom variable values will be lost. Instead, we can store custom variable values in session scope. Download sample application - SecurityFormLogin_v2.zip.
Sample application populates environment variables during Login action (it sets server name and port):
Environment variables are stored in HTTP session, means accessible from session scope.
Now main topic of this post, you can access HTTP session from ADF BC by getting session scope from ADF context:
In this example, we are retrieving server name environment variable from HTTP session scope inside ADF BC prepareSession(Session) overridden method.
Let's test if value is not lost during passivation/activation. To test this, simply disable Application Module Pooling option from Application Module configuration:
Open sample application, login as redsam/welcome1:
Now, because AM pooling is disabled - on each request (button click) passivation/activation happens:
Hi Andrejus,
ReplyDeletethanks for the interesting post.
I wonder if accessing the http session scope map from inside the application module is not a break of the MVC pattern.
You can save the data you store in the userData object with some effort when the am is passivated and read it back when the am gets activated.
Timo
Hi Timo,
ReplyDeleteMVC is not broken, we are just using public API of ADF BC. There is no import of any ViewController libraries - its the beauty of it.
As it is mentioned in the blog, UserData is not preserved during passivation/activation and is not supposed to be used to store session long environment variables (is good to store temporary values)
Regards,
Andrejus
Hi Andrejus,
ReplyDeleteI am a little confused. At the moment I use only adf.userSession.userData for storing some needed values.
It always means extra work for activation/passivation which enjoys no developer ;).
So the use of HTTP session (groovy adf.context.sessionScope.) is a very nice option but I never used that before because of
some comments like "you should not access the session scope from your model project" from John S.
second post at https://cn.forums.oracle.com/forums/thread.jspa?threadID=1014100
So now we can say?
1. use adf.userSession.userData for temporary values ("request scope")
2. use adf.context.sessionScope for values with a longer scope than "request", maybe a bindvariable for a VO
best regards,
Martin
Answers:
ReplyDelete1. Yes
2. Use it only for environment type variables, if bind variable remains the same for entire session for example.
MVC pattern would be broken, if you would import JSF libs into Model and access web session through ViewController API. But here we are using only ADF Model/ADF BC API, so there is no violation.
Thanks for question.
Andrejus
hi Andrejus
ReplyDeleteI have posted a related question in the forum thread "Should we try to access session scope in ADF BC ?"
at https://forums.oracle.com/forums/thread.jspa?threadID=2336307
regards
Jan Vervecken
Very good, lets see Oracle feedback.
ReplyDeleteI would like to point that your OTN Forum post is not exactly right - "Andrejus Baranovskis suggests it is no problem to access session scope in ADF BC using". I don't suggest it as no problem - but rather describe approach, and it depends from use case to use case what approach to choose.
Also, MVC pattern is not broken, its just different access between framework layers is chosen.
Question should be - why public API is available to access HTTP session from ADF BC context.
Andrejus
Hi Andrejus,
ReplyDeleteLong time back, I got a chance to discuss with Maiko Rocha regarding some issues in our application. In the flow, at some point, he stated that ADFContext.getCurrent() should never be accessed in ADF BC. Instead, he suggested to make use of Custom JUApplication class to pass data from view layer to Application module by writing code inside beginRequest(HashMap pRequestCtx). After we read your post, we got confused. I wonder why he suggested us not to access ADFContext at Model layer.
There can be different scenarios and use cases - sometimes its good and sometimes no. All depends on requirements and options to implement these requirements.
ReplyDeleteI would argue about no access for ADFContext.getCurrent() in ADF BC. Even ADF Security context in ADF BC is accessed through ADFContext.getCurrent.getSecurityContext().
I prefer to access Session data in ADF BC from HTTP session, when working with user preference variables stored in HTTP session.
Regards,
Andrejus
Hi Andrejus,
ReplyDeleteI am trying to set the userId in the session while running the Junit test.
Is it possible to set the session variable while running a unit test. Like, I need to set the currentUserId based on the user who is testing it. For this I have used a Jpanel component to get the user ID.
Will setting the UserId or any session variables in this way a violation of the MVC pattern ?
You can get User ID from ADF Security context may be?
ReplyDeleteAndrejus
Hello,
ReplyDeletewhat happens to the variables stored in the HTTP session in a high availability scenario? Will they get transfered to another server in case the one you are working with fails? I am currently testing an application with high availability, and anything in the session scope is lost when the server fails (even though the session itself isn't), so I'd like to make sure I am not missing anything.
Thank you
Jordi
Hi,
ReplyDeleteSession replication should happen, cross check with instructions from my previous sample app: http://andrejusb.blogspot.ca/2009/04/weblogic-in-memory-http-replication-for.html
But in general I would recommend to apply different solution for this problem, described here: http://andrejusb.blogspot.ca/2012/05/solution-for-sharing-global-user-data.html
Store values in ADF BC and replicate ADF BC (basically store in DB).
Andrejus
Hi Andrejus,
ReplyDeleteThanks for this useful post. You made my day..:)
Sri
I am unable to download your zip file, although the code was quite helpful.
ReplyDeleteBut it would be great gesture if give that zip file.Please...