Ответ 1
Через некоторое время я наконец смог найти решение, а это означает, что стратегия кодирования удовлетворяет всем требованиям, которые у меня были. Может быть, это не технически хорошее решение, но это функциональное решение в том смысле, что оно создает опыт, который мне нужно предоставить, и я сохраняю прикосновение к всем уже существующему моему Java-коду. Вот оно!
1. Управляемый bean для переключения и флопа режима доступности
Управляемый bean ниже отвечает за включение и выключение доступности в ответ на то, что пользователи нажимают на определенную командную ссылку. Идея состоит в том, чтобы добавить атрибут к сеансу, когда включен режим доступности и удалить его, когда отключен режим доступности.
Эти действия возвращают перенаправление текущей страницы, так что пользователь мгновенно видит переход интерфейса из одного режима в другой.
Когда доступность включена, путь просмотра изменяется, чтобы добавить /ac
, потому что все мои доступные представления имеют то же имя файла, что и для небезопасных, но в подкаталоге с именем ac
.
@ManagedBean
@RequestScoped
public class AccessibilityMB {
private boolean accessibilityOn = false;
@PostConstruct
public void init() {
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
if(session!=null) {
Boolean accessibilityMode = (Boolean)session.getAttribute("AccessibilityMode");
accessibilityOn = accessibilityMode!=null && accessibilityMode;
}
}
public String turnAccessibilityOff() {
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
if(session!=null) {
session.setAttribute("AccessibilityMode", accessibilityOn = true);
}
String viewId = context.getViewRoot().getViewId();
return viewId+"?faces-redirect=true";
}
public String turnAccessibilityOn() {
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
if(session!=null) {
accessibilityOn = false;
session.removeAttribute("AccessibilityMode");
}
String viewId = context.getViewRoot().getViewId();
int index = viewId.lastIndexOf("/ac/");
if(index>-1)
viewId = viewId.substring(0, index)+viewId.substring(index+3);
return viewId+"?faces-redirect=true";
}
public boolean getAccessibilityOn() {
return accessibilityOn;
}
}
2. PhaseListener для исправления пути просмотра при включенном режиме доступности
PhaseListener просто проверяет режим доступности и, в таком случае, перезаписывает путь, который будет искать в подкаталоге ac
. Если существует такое представление, текущее дерево компонентов отбрасывается и перестраивается из доступной версии того же вида.
Здесь решение не так хорошо, потому что JSF уже работал над построением дерева компонентов, и я просто отбрасываю его, чтобы переработать его из другого файла.
public class AccessibilityPhaseListener implements PhaseListener{
private static final long serialVersionUID = 1L;
@Override
public void beforePhase(PhaseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
if(session==null) {
return;
}
Boolean acessibilityMode = (Boolean)session.getAttribute("AcessibilityMode");
if(acessibilityMode==null || !acessibilityMode)
return;
String viewId = context.getViewRoot().getViewId();
if(acessibilityMode) {
int index = viewId.lastIndexOf("/");
viewId = viewId.substring(0, index+1)+"ac/"+viewId.substring(index+1);
} else {
int index = viewId.lastIndexOf("/");
if(viewId.substring(index-3, index).equals("/ac"))
viewId = viewId.substring(0, index-3)+viewId.substring(index);
}
URL url = null;
try {
url = context.getExternalContext().getResource(viewId);
} catch (MalformedURLException e) {
}
if(url==null)
return;
ViewHandler handler = context.getApplication().getViewHandler();
UIViewRoot root = handler.createView(context, viewId);
root.setViewId(viewId);
context.setViewRoot(root);
}
@Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
}
Заключение
Я мог бы удовлетворить все мои требования:
- Никакой код Java не должен быть рефакторирован, и приложение теперь работает в двух разных режимах;
- Я восстановил только те взгляды, которые я хотел, в тех случаях, когда исходное представление отлично работает с устройством чтения с экрана, оно хранилось как есть;
- Режим доступности может быть включен и выключен в любое время, и пользователь немедленно реагирует на такое действие;
Я понял, что это решение работает с любыми режимами приложений, а не только с доступностью. Каждый раз, когда кому-то нужно выбрать определенное представление вместо другого на основе параметра приложения или сеанса, он будет работать. Например, мультикультурное приложение, в котором настройка культуры идет дальше, чем цвет и язык, требуя полной перестройки представлений, может воспользоваться этой моделью.
Недостатком всего этого является тот факт, что, когда включен режим доступности и есть доступная версия определенного вида, JSF будет работать дважды, один раз, чтобы создать исходное представление, и второй раз, чтобы построить доступный версия.