adf - как изменить компоненты в дереве?

Из спецификации jsf 1.2 revB mrel2: внизу страницы 65

■ Приложение должно иметь возможность программно изменять дерево компонентов в любое время в течение жизненного цикла обработки запроса (кроме периода рендеринга представления) и обеспечивать ожидаемое поведение системы. Например, должно быть разрешено следующее. Изменение представления во время рендеринга может привести к неопределенным результатам. Должна быть предусмотрена возможность удаления компонентов, добавленных системой шаблонов (например, JSP), из дерева перед рендерингом. Должна быть возможность программно добавлять компоненты в дерево и отображать их в нужном месте в иерархии. Должна быть возможность переупорядочивать компоненты в дереве перед рендерингом. Эти манипуляции требуют, чтобы любые компоненты, добавляемые в дерево, имели уникальные идентификаторы в пределах области действия ближайшего родительского компонента NamingContainer. Значение свойства rendersChildren обрабатывается должным образом и может быть либо истинным, либо ложным.

Так как же это сделать в adf 11g? Я пытаюсь внедрить систему авторизации для всего приложения, в которой компоненты видны/редактируются в зависимости от ролей пользователя. Однако я не могу найти способ подключиться к adf для изменения компонентов (например, RichInputText.setDisabled(true)) до того, как ответ будет записан. Я пробовал как с PhaseListeners, так и с ViewHandlers. Ни один из них, похоже, не позволяет мне выполнять вышеупомянутые функции. Так что дает? Мне не повезло? Я что-то упускаю?

Спасибо, Бен

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();
  }
  ...
}

person andersonbd1    schedule 14.07.2009    source источник


Ответы (3)


Вам действительно нужно сделать это на стороне презентации. Не делайте это с помощью фазовращателя, там он не для чего. Используйте атрибут rendered с умом. Вот несколько основных примеров того, как вы можете его использовать:

<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'}" />
person BalusC    schedule 07.12.2009

Согласно моему (ограниченному) поиску в документах, объект UIViewRoot является корневым узлом дерева представлений. Вы можете использовать его методы getChildren, чтобы найти соответствующие UIComponents и внести свои изменения. Однако я бы предложил другой путь.

Если вы предоставляете свою службу авторизации как bean-компонент, вы можете напрямую добавлять методы в разметку. Например...

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

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

Еще лучше было бы использовать структуру безопасности, которая еще больше упростила бы это.

person Drew    schedule 14.07.2009
comment
Дрю, получение UIViewRoot не помогает, потому что, как я задокументировал в комментариях, верно одно из следующего: // соответствующие компоненты пользовательского интерфейса еще не существуют // соответствующие компоненты пользовательского интерфейса существуют, но уже были записаны в поток, который я хотел бы скорее не нужно вручную добавлять отключенный атрибут ко всем моим jsfs. С одной стороны, это утомительно. Во-вторых, мы позволяем пользователям настраивать роли. Таким образом, наши требования гораздо более детализированы, чем позволяет это решение. - person andersonbd1; 21.07.2009
comment
Для начала мы используем структуру безопасности (acegi), но наши требования гораздо глубже. Я в значительной степени пишу нашу собственную структуру безопасности. Я использовал aop делать то, что необходимо. Это хак, но он работает. - person andersonbd1; 21.07.2009

Это позволяет получить доступ/изменить компоненты пользовательского интерфейса в дереве, если его можно найти. Вам необходимо указать идентификатор клиентского компонента при использовании findComponent(). Единственная проблема остается в том, что он не дает вам доступа/управления для начальной загрузки страницы (restore_view). :-( Для этого на данный момент я нашел только один способ указать EL в jspx/jsp/jsff.

person Kedar    schedule 07.12.2009