1
votes

Say I have a list of objects over which is iterated with an <ui:repeat> tag and the user has a list of actions for every object, but - depending on his permissions - some of those actions are disabled, because the user lacks the permission.

<ui:repeat var="item" value="#{myBean.selectedItems}">

     <h1>#{item.name}</h1>        

     <h:commandButton value="Edit" disabled="#{myBean.getPermissions(item, user).has('EDIT') .../>
     <h:commandButton value="Move" disabled="#{myBean.getPermissions(item, user).has('MOVE') .../>
     <h:commandButton value="Copy" disabled="#{myBean.getPermissions(item, user).has('COPY') .../>
     <h:commandButton value="Delete" disabled="#{myBean.getPermissions(item, user).has('DELETE') .../>
     <h:commandButton value="Rotate" disabled="#{myBean.getPermissions(item, user).has('ROTATE') .../>


</ui:repeat>

So lets say, the operation to retrieve the permissions [myBean.getPermissions()] is quite expensive and I don't want it to be executed multiple times for one item.

So what can I do in JSF/EL to achive this?

Lets say I use a <ui:param> like this:

<ui:repeat var="item" value="#{myBean.selectedItems}">

     <h1>#{item.name}</h1>        

     <ui:param name="itemPermissions" value="#{myBean.getPermissions(item, user)"/>

     <h:commandButton value="Edit" disabled="#{itemPermissions.has('EDIT') .../>
     <h:commandButton value="Move" disabled="#{itemPermissions.has('MOVE') .../>
     <h:commandButton value="Copy" disabled="#{itemPermissions.has('COPY') .../>
     <h:commandButton value="Delete" disabled="#{itemPermissions.has('DELETE') .../>
     <h:commandButton value="Rotate" disabled="#{itemPermissions.has('ROTATE') .../>


</ui:repeat>

But as far as I understand, the <ui-param> is just a shortcut, it does not cache the actual value associated with it, but the value-expression is re-evaluated every time it is used? Is this correct?

So what can I do else? <c:set> is not an option, because it is only set during view-build-time afaik.

Is the only option, to cache the permissions manually in a bean variable and then use the bean to access them again? Is there no mechanism in JSF/EL that allows to define a variable (like in a normal Java method) that I can set a value to and read the value later?

And I noticed, that the rendered=".." or disabled=".." gets called sometimes even multiple times, so the expressions are not only evaluated once per tag, but in some case 2-3 times. Is this a correct observation and what's the reason for this?

Thanks in advance for your answers.

Edit: BalusC marked it as duplicate of a question, but I didn't find their an answer, as <c:set> that is recommended there does not work in my case. Or do you want to say, that it is not possible and if I want to cache it e.g. in an ui-repeat I have to do that with a bean for myself?

1
I found that question on my research before i asked, but it doesn't answer by question, because &lt;c:set&gt; which was recommended there is not working e.g. inside an ui-repeat, and ui-param does not cache the value (but is merely a shortcut to a more complex expression). So do you want to say, that there isn't any general mechanism in EL/JSF to achive that, other than to cache the value manually in a bean or use a bean-method e.g. to put it as variable in the request-scope? - deconstruct
Where exactly does 'user' come from? Is there only one singular user (probably the logged in one)? - Gimby
The user object is the currently logged in user (which is fetched from a session-scoped bean). The getPermissions() method fetches the permissions of the user from the database for the given item, which is then basically a Java Map object. I want to store this map in some sort of variable, so it doesn't need to be fetched again inside the ui-repeat. I could of course cache the Map manually in my bean, but I am wondering, if there is not a more general-purpose solution. Because I would think that this is a very common problem, so I supposed that there would be a built-in solution in JSF/EL. - deconstruct
Yes - backing beans. If I would solve this I would create a proper bean class that will become the "item" variable which can provide all the information that bit of the view needs. Business logic does not belong in the view. - Gimby
So there is no mechanism in JSF/EL to store (really store, so cache the value, not reevaluate EL) something in a variable? I don't think that this has something to do with business logic being done in the view, because the business logic already provides all the necessary information for the view in my example. I just want to use that information multiple-times, without fetching the same information again and again. - deconstruct

1 Answers

0
votes

Usually the permissions of a User/Role are saved together with the User session information during login, so there should be no need to call the DB anymore.

This is how Apache Shiro and Spring Security works, just to name a few Authentication/Authorization frameworks ...

If you are using a session scoped bean to store the User, you may just use it to store its permissions as well...