tags:

views:

557

answers:

3

From the jsf 1.2 revB mrel2 spec: bottom of page 65

■ It must be possible for the application to programmatically modify the component tree at any time during the request processing lifecycle (except during the rendering of the view) and have the system behave as expected. For example, the following must be permitted. Modification of the view during rendering may lead to undefined results. It must be possible to allow components added by the templating system (such as JSP) to be removed from the tree before rendering. It must be possible to programmatically add components to the tree and have them render in the proper place in the hierarchy. It must be possible to re-order components in the tree before rendering. These manipulations do require that any components added to the tree have ids that are unique within the scope of the closest parent NamingContainer component. The value of the rendersChildren property is handled as expected, and may be either true or false.

So how does one do this in adf 11g? I'm trying to implement an application wide authorization system where components are visible/editable based on a user's roles. However, I cannot find a way to hook into adf to modify components (eg RichInputText.setDisabled(true)) before the response is written out. I've tried with both PhaseListeners and ViewHandlers. Neither of these seem to allow me to perform the above mentioned functionality. So what gives? Am I out of luck? Am I missing something?

Thanks, Ben

public class AuthorizationPhaseListener implements PhaseListener {
  ...
  public PhaseId getPhaseId() {
    return PhaseId.RENDER_RESPONSE; // I've also tried in the other phases including ALL_PHASES
  }
  public void beforePhase(PhaseEvent p1) {
    // relevant ui components don't yet exist
    ...
  }
  public void afterPhase(PhaseEvent p1) {
    // relevant ui components exist, but have already been written to the stream, thus it's too late to modify them
    ...
  }
  ...
}

public class MyCustomViewHandler extends ViewHandlerWrapper {
  ...
  @Override
  public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException {
    AuthorizationService as = (AuthorizationService)RiscsContext.getCurrentInstance().getBean("AuthorizationService");
    // relevant ui components don't yet exist
    as.applyAuthorization();
    super.renderView(context, viewToRender);
    // relevant ui components exist, but have already been written to the stream, thus it's too late to modify them
    as.applyAuthorization();
  }
  ...
}
A: 

According to my (limited) searching through the docs, the UIViewRoot object is the root node of the view tree. You can use it's getChildren methods to find the appropriate UIComponents and make your modifications. However, I would suggest a different way.

If you expose your Authorization service as a bean, you can directly add the methods to the markup. For example...

public class User {
...
Map<String, Boolean> allowedRoles;
...
public Map<String, Boolean> getAllowedRoles { return allowedRoles; }
}

<h:inputText value="#{SomethingImportant}" disabled="!#{User.allowedRoles['importantRole']}/>

Even better would be using a security framework which would simplify this even more.

Drew
Drew,getting UIViewRoot doesn't help because as I documented in the comments one of the following is true: // relevant ui components don't yet exist // relevant ui components exist, but have already been written to the streamI'd rather not have to manually add the disabled attribute to all of my jsfs. For one, it's tedious. For another thing, we're letting the users setup roles. So, our requirements are much finer grained than that solution allows.
andersonbd1
We are using a security framework (acegi) to get us started, but our requirements go deeper. I'm pretty much writing our own security framework.I've used aop do what's necessary. It's a hack, but it works.
andersonbd1
A: 

It does allow to access/modify the UI Components in tree if it is locatable. You need to provide Client Component Id while using findComponent(). The only problem remains that it does not give you access/constrol for Initial Page load( restore_view ). :-( For that as of now only 1 way i could find that is specifying EL in jspx/jsp/jsff.

Kedar
A: 

You really need to do this at the presentation side. Do not do it using a phaselistener, there it is not for. Make use of the rendered attribute wisely. Here are some basic examples how you can make use of it:

<h:someComponent rendered="#{bean.booleanValue}" />
<h:someComponent rendered="#{bean.intValue > 10}" />
<h:someComponent rendered="#{bean.objectValue == null}" />
<h:someComponent rendered="#{bean.stringValue != 'someValue'}" />
<h:someComponent rendered="#{!empty bean.collectionValue}" />
<h:someComponent rendered="#{!bean.booleanValue && bean.intValue != 0}" />
<h:someComponent rendered="#{bean.stringValue == 'oneValue' || bean.stringValue == 'anotherValue'}" />
BalusC