File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes JSF and the fly likes JSF custom tag requirement Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » JSF
Bookmark "JSF custom tag requirement" Watch "JSF custom tag requirement" New topic
Author

JSF custom tag requirement

Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Hi,

I need to build something to autorize the jsf components to be rendered on screen before the page loads.

We have a role to component to action mapping table which would be used to authorize the component and make it viewable/actionable or renderable.

I need find the component that needs to be authorized and then get the details from db and set its properties.

I was planning for a custom tag , which would find components based on their id's and then set properties .
I hit a road block when I found out that the UIComponent api does not have functions that alter the properties of the control.
eg: If i find a UIComponent usind id htmlCommbutId , I just get the UI component, but there is no way I can get to the HtmlCommandbuttion itself to alter its properties.

Any inputs are appreciated. ( Please suggest if there would be another way to adress this requirement)

Thanks,
Hari
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

Welcome to the JavaRach, Hari!

I'm not sure what you mean by "authorizing" tags. If you just want to control their rendering, that's as simple as defining boolean properties on a backing bean and using the "rendered=" attribure on the tags with an EL expression that references the boolean property.

As a general rule, the more JSF-specific stuff you try to do in JSF, the more likely that you're doing it the hard way. Don't mess around with the component tree's structure programmatically unless there's simply no other way to do it. Aside from being troublesome to code and fragile to maintain, that kind of stuff is more likely to break down entirely when a new, improved JSF architecture comes out.


Customer surveys are for companies who didn't pay proper attention to begin with.
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Thank you Tim!!

Well my actual requirement is that, before the page loads, I have to somehow get control of all ( or few components of interest) components on screens,
authorize them individually and then render the view.
By "authorizing" I mean that: eg:
if there were a command button called "Save" on the page, before rendering that page, I need to get hold of the buttion, send its id to DB where its authority for the logged in user is defined ( View, Execute , No display etc).
Based on the DB out put, i will have to set the button as disabled or not rendered or color changed and so on.

I could not find anything but an approach to intercept the view rendering , a tag, that would get the component from screen and then authorize it.
But a small test revealed that this might not work or I am doing something wrong..

Hope I could explain my requirement.

Please advise.

Thanks,
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

You are doing something wrong, yes. Before a page can be displayed, its corresponding View Definition is compiled and the EL expressions on it are analyzed in order to determine what backing bean(s) need to be available. JSF will then attempt to construct those beans. Thus, you can control what controls are visible by coding expressions of the form 'rendered=#{myBean.renderMe}". Or, if you prefer visible, but disabled, use the "disabled=" attribute instead on the control.

That will cause the page rendering engine to invoke the "isRenderMe()" public boolean method on "myBean", and isRenderMe can return true or false, based on the results of your user profile query.

There is one caution, however. It can really slow things down if you query the database every time the isRenderMe method is invoked, because this can happen several times per page fetch. So it's better to do your query once, cache the results, and have isRenderMe() return the cached value.

This kind of stuff is very common and easy to do. I do it all the time, myself.
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Tim Firstly thanks for the fast reply.

I understand your concern of the multiple DB hits and the acutal idea was to have some object cache to avoid this DB trips.

However, I still am not able to get a conclusive approach on the rendering part.

As you mentioned in the reply, I can have a "isRenderMe()" to do the trick but , say I have 5 components on screen that need to be authorized and I have to have "isRenderMe()" on all 5 of them, then how can identify which component is calling it at what time ?
(This because I know the core JSF EL calls are not parametrizable ).
I can however have 5 different boolean methods to do this in the backing bean, but I do not see it as a clean approach.

You comments please.

Thanks,
Hari
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

There are several ways of doing that. Since usually I'm controlling visibility/disabling based on business state or user role, I'd have properties that indicate that state or role, rather than defining a separate method for each control (which is less abstract). So I'd have "isAdministrator()" and/or "isCreateMode()" property methods.

In lieu of parameterizing, one could have a collection-referencing expression such as "rendered="#{bean.showMe[3]}"" or "disabled="#{bean.disableFor['admin']}", but as a rule, the "how" shouldn't be more important than the "what".
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Tim Holloway wrote:There are several ways of doing that. Since usually I'm controlling visibility/disabling based on business state or user role, I'd have properties that indicate that state or role, rather than defining a separate method for each control (which is less abstract). So I'd have "isAdministrator()" and/or "isCreateMode()" property methods.

In lieu of parameterizing, one could have a collection-referencing expression such as "rendered="#{bean.showMe[3]}"" or "disabled="#{bean.disableFor['admin']}", but as a rule, the "how" shouldn't be more important than the "what".


Tim,
For my current requirement, I have to do away the the business state role based authroization (as a complete approach) as the logged in user roles are not exclusive.
Eg: The logged in user can be an admin and moderator and the components need to be selectively displayed.
Even if it were exclusive, my problem with the approach is how will I identify in my controller as to which component invoked the "disabled="#{bean.disableFor['admin']}"? I know this gets called for that component where it is referred but, at the point I need to either go to DB or cache and ask it give me authorization for "admin" fot "<this>" component. My problem has been with marking that component on call as in DB i have component id, action to be performed on it and the role itself.

Apologize if I am causing confusion.

Thanks,
Hari
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

Actually, the container-managed security component of the J2EE security standard defines roles that way as well. so that's nothing new. You don't ask it, "is user x 'an administrator', you ask 'can user x ACT as an administrator'.

I think my biggest objection to what you're looking to accomplish is that it's all about specific implementation details and not about performing a business function. I usually don't care about what control on what page can do what, because the controls and pages are subject to change. What I care about is things like whether a user whose role is limited to auditor can access data entry functions, regardless of mechanism. From that point of view, hiding controls is more a case of removing temptations and confusions, because an actual attacker can spoof the form and add in the missing controls manually. So for strict security, defending the UI is only part of the solution. Likewise, controlling UI elements at the atomic level doesn't appeal to me, because it's all about the "how" and not about the "what" or the "why", it requires more day-to-day maintenance, and it's easier to miss making critical changes.

Still, there are legitimate reasons why sometimes gnarly control is necessary. And, alas, often times when some idiot who "knows better" is in charge and demands it. We spend a lot of time helping people try and get a decent job done despite having bosses who "know better", here.

As a rule, the less complexity in JSF, the more likely you're doing it right, but as Einstein once said, "Everything should be as simple as possible, but no simpler." So, if you can't do relatively simple EL like this:


And you need obsessive control on a per-page view, instead, try something like this:


or


I probably don't have to point out, that to do this kind of stuff when using a database and user credentials as the determining factors that the "role" and "render" properties would have to be custom objects implementing the Map interface. Or in the case of the final example, a Map of Arrays.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

BTW, I forgot to mention. We're not strictly speaking talking "Controller" here. In JSF, the Controllers are almost invariably the FacesServlet and the Tag processors, not user-written code.

In fact, one of the clearest signs you've got a clueless idiot in control is when shop standards mandate naming backing beans something like "XxxxController". Backing beans are not Controllers, they are Models.
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27



And you need obsessive control on a per-page view, instead, try something like this:
view plaincopy to clipboardprint?
rendered="#{bean.render['page250.box3.control7']"

Pardon my silliness but the above interpreted would be:
A HashMap in my bean with keys as specific as <xhtmlpageNAME.formID.controlID>, and the values specific that key would be a Boolean resolved from my DB processing?

Still, there are legitimate reasons why sometimes gnarly control is necessary. And, alas, often times when some idiot who "knows better" is in charge and demands it. We spend a lot of time helping people try and get a decent job done despite having bosses who "know better", here.

Can't agree more and have to confess that's our case


In fact, one of the clearest signs you've got a clueless idiot in control is when shop standards mandate naming backing beans something like "XxxxController". Backing beans are not Controllers, they are Models.


For some reason this is how my cureent design is.


Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

Hari Gundappa wrote:


And you need obsessive control on a per-page view, instead, try something like this:
view plaincopy to clipboardprint?
rendered="#{bean.render['page250.box3.control7']"

Pardon my silliness but the above interpreted would be:
A HashMap in my bean with keys as specific as <xhtmlpageNAME.formID.controlID>, and the values specific that key would be a Boolean resolved from my DB processing?


Oh, it can be MUCH more evil than that!

How's this?


Or, in other words, it just has to ACT like a (Hash)Map, not actually specifically be a HashMap!
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Thanks Tim. Sorry seeing you reply now.

So I am trying to do something like this now and it might work.
I am having a app level map that would have to be prepopulated with all components and their authority at the very beginning(even before my page renders) and when the jsf asks for this element in the map it would return the boolean already put it.
I kind of got this working. But sadly this comes with some constraints to me. 1) All component/authority has to be prepopulate once for the user as he logs in.
2) There are problems of how to synchronize (not thread sync) of this map. , (I know no new component will added to DB while a user is logged in and he cant see it)
3) A role/authority/component map is exclusivesly built per session / per user role. I cant possibly have this carried thro application context , as if I have to then I need to have track of the user roles too.

What do you say?
Thanks,
Hari
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

Well, there are a couple of refinements to my previous example that might make things easier.

First of all, instead of a master map for the application, consider a session-scope "user" object that the Views reference when they need to get control attributes. This "user" backing bean would then hold the security map(s). This saves resources, since once the user goes out of scope (logs off), the user's resources can be released.

The sample map class I illustrated did brute-force lookup, but you can make it better by making it do the caching for you. That is, instead of "implements java.util.Map", make it "extends java.util.HashMap". Then make this subclass override the standard HashMap get() method with a caching get():



It's fairly standard that a user's security privilege changes require them to log off and back on again. For one thing, it's safer, since you don't have possible loopholes from being in 2 different security states at the same time. However, if more immediacy is needed, just clear() the security map object. That will cause existing values to be discarded and the cache to reload on demand.

I've used an example where the authorization is done with a separate database table row per control, but of course, you can implement other schemes as well. Likewise if you have to cascade roles. It's just a matter of how you code the database interface in the "get()" method. I'm also doing population on-demand, which gives better performance, but you could preload the entire map if you prefer a long initial delay over shorter per-item delays.
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Just in time retrieval is costly as you said but I think its worth it.

Tim , I have implemented this approach and for some reason the get(key) method of my map class does not get called.

I have this on the jsf mybean.authmap['loginpageid']

and authmap extends hashmap and have a get(String key) inthere

Nothing happens!Am i missing someting?

Thanks,
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

First thing to check would be the getAuthmap() method and make sure it's returning something. Since a failure would probably cause an exception, it's fairly certain, but still worth checking.

The javaDocs for HashMap indicate that the signature should be "Boolean get(Object s)", so that may be the problem - get(String s) would have to change to get(Object s).
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Tim,

So it was the method signature.Changed the arugment to Object and it works. Everything is place. getAuth() returns a boolean and i can see the my hashpmap class is populate with key and value pairs.
But the component is not getting disabled. Is it one of those JSF lifecycle things?
I can see the get(key) gets called then the map is populated and then the screen renders but the control is not disabled

Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Sorry Tim, it was my oversight.
I have the same map to be used for rendered and disabled attributes on screen and the DB process gives me either true or false.
So i was getting a false for a component that had to be disabled. Semantically, db false was to say this needs to be disabled, but jsf understand "disabled=true" to disable the component and i did the necessare changes to my process . Things seem fine for now.

Thanks a ton for the timely and valuable inputs.
Will keep this post open until am completely done with this implementation.

Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Hi Tim,
Happy New Year.

I am back again with the Map problems.
So in context of the above implmentation, I was able to extend a class of HashMap and got the lookup things working.
But for some reason the Cache is not working I have my code very similar to the one you suggested but everytime the cached value is null.

I have the map object itself as a spring bean injected in session scope.


Am I missing something to cache this ?

Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

Hi Hari,

May you - and all our happy Ranchers - have a felicitous New Year as well!

There's nothing wrong I can see in your logic, so the conclusion is that probably your scope isn't what you wanted it to be.

I would have made this object a JSF managed bean myself. All my Spring objects are singletons. Other than that, I would have done it the same way you have.
Hari Gundappa
Greenhorn

Joined: Sep 13, 2011
Posts: 27
Thanks for all the help Tim. We were able to design and build good utility based on your inputs.
Brucelin Mento Clemens
Greenhorn

Joined: Dec 04, 2012
Posts: 2
Very Good information on this post.
I just completed implementation of authorization with the help of this post on my application. Thank you Tim and Hari.
simple and effective.
For new users, i am posting part of my impl and usage.
ie) during user login, we set the user id and permissions on sessions, and for every screen/form/action we use rendered attribute for checking authorization.

bean impl



xhtml


regards
bruce [www.loasoftwares.com]
-----------
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

Welcome to the JavaRanch, Brucelin!

I don't want to rain on your parade, but I have a few remarks.

1. We actually prefer that when a thread has been dormant for an extended period of time that people simply start a new thread instead. Our term for reviving old dead threads is "Awakening a Zombie".

2. The pedant in me feels obligated to point out that JSF Backing beans are NOT Controllers, they are Models. In JSF, the Controllers are mostly pre-supplied built into the FacesServlet and tag implementations.

3. Hang around here and you'll get mightily sick of hearing this, but I don't recommend user-designed login/security systems. I've been working with J2EE since literally before JSPs were invented and each and every user-designed security system I've encountered over all those years had holes in them. Most of them, in fact, can be cracked by non-technical people in about 10 minutes or less. Since a lot of these systems were implemented at banks and even a military installation or 2, I have to conclude that it's much safer to use a professionally-designed Authentication and Authorization manager, such as the one that's part of the J2EE standard.
Brucelin Mento Clemens
Greenhorn

Joined: Dec 04, 2012
Posts: 2
Thanks Tim, I am new to J2EE and JSF.
I agree with you on item#3
We started using JSF with JBoss(and oracle), our authorization requirement is
1) each user will be assigned with one or more operating unit
2) each user will have roles&permissions for each functionality ( add/edit/view/edit of operating unit info) on the assigned operating units
3) our GUI should render the applicable components(page/body, action/button, screen/form, menu, text field (editable/non-editable and/or visible/hidden)) based on the assigned roles&permissions

Let's know if this can be done with J2EE provided authorization.

regards
bruce
------------
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15641
    
  15

Role-based access control - known by its friends as RBAC - can definitely serve the purpose here. Although I'll make some qualifications.

A lot of people attempt to define roles in terms of program logic functions. I've found it works better to define roles in terms of business functions. Things like "clerk" (detail data entry) "auditor" (read-only), "manager" (admin functions). That allows adding or removing a user's business abilities in terms of their business functions. For example, if a manager goes on vacation, the manager role can be assigned to a senior clerk for the duration. This approach is also beneficial when using a central authorization database such as Active Directory, since many times the same role namespace figures in multiple applications. Especially, but not including Single Signon systems.

However, if you want truly fine-grained access controls, I recommend a hybrid approach. Once you have 20 roles or so, you end up with a system that requires fairly frequent modification and a confusion of roles. So a better approach is to assign container roles as major gatekeepers (since they're enforced at the container level) and then use a secondary system for the fine-grained control. Typically you'd use the userid (contained in the HttpServletRequest object) as a key to lookup a specific user's fine-grained authorizations. Because the really important stuff is being guarded by the container, you can safely invent your own secondary security. Or use a pre-existing one like Spring Security.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: JSF custom tag requirement
 
Similar Threads
Custom Component with dynamic components.
Problems Extending HtmlCommandLink
Dynamically create component from namespace and tag name
JSF partial validation
UIViewRoot findComponent