Русский English Тэги View Sergey Zolotaryov's profile on LinkedIn Вход
Луч света в царстве JSF
Постоянная ссылка 11-07-2008 anydoby java

Возможно я предвзят, но технологию JSF (по собственному опыту и набитым шишкам) считаю довольно тормознутой и неприспособленной для оживленных бизнес приложений. Однако совершенно недавно вышел в Open Source некогда платный набор компонент от IceFaces и должен вам сказать, это что-то. А началось все вот с чего...

У нас, как обычно, начался новый проект. И как обычно мы начали изучать текущее положение дел на фронте AJAX для Java. Самым удачным решением, как нам показалось, было бы решение на GWT. Однако, кастомер считает иначе - у них, как обычно, созвали совет высоколобых архитекторов и те порешили, что будет только JSF. Агрументация обычная - это стандарт и никаких гвоздей. Так что, порывшись по JSF фреймворкам, не нашли лучшего. И оказалось, все совсем неплохо.

Итак, как выглядит работа с IceFaces? Очень просто, качаем любой из сэмплов от производителя и надстраиваем над тем, что есть. Сначала я попробовал рисовать JSP и понял, что здесь придется действовать в обход - как, например, в Swing или Echo или GWT. За основу берется JSP с вот таким примерно кодом:


<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://www.icesoft.com/icefaces/component" prefix="ice"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Core 4.0</title>
<link rel="stylesheet" type="text/css" href="./xmlhttp/css/xp/xp.css" />
<link rel="stylesheet" type="text/css" href="./css/main.css" />
</head>
<body>
<f:view>
	 <ice:panelGroup id="container" binding="#{testController.master}"/>
</f:view>
</body>
</html>

В сеттере setMaster UIPanel привязывается к нужному свойству и можно тут же положить в панельку свои компоненты, созданные программно.

Типичная ошибка, которая довольно часто выкидывается при использовании API IceFaces:


java.lang.NullPointerException
	java.lang.String.endsWith(String.java:1296)
	com.icesoft.faces.application.D2DViewHandler.findComponent(D2DViewHandler.java:896)
	com.icesoft.faces.application.D2DViewHandler.findComponent(D2DViewHandler.java:771)
	com.icesoft.faces.application.D2DViewHandler.findComponent(D2DViewHandler.java:776)
	com.icesoft.faces.application.D2DViewHandler.findComponent(D2DViewHandler.java:776)
	com.icesoft.faces.application.D2DViewHandler.findComponent(D2DViewHandler.java:776)
	com.icesoft.faces.application.D2DViewHandler.findComponent(D2DViewHandler.java:776)
	com.icesoft.faces.webapp.http.core.ReceiveSendUpdates.service(ReceiveSendUpdates.java:39)
	com.icesoft.faces.webapp.http.core.ViewBoundServer.service(ViewBoundServer.java:65)
	com.icesoft.faces.webapp.http.core.RequestVerifier.service(RequestVerifier.java:44)
	com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer$Matcher.serviceOnMatch(PathDispatcherServer.java:50)
	com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:19)
	com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19)
	com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63)
	com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:139)
	com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:53)
	com.icesoft.faces.webapp.http.servlet.PathDispatcher$Matcher.serviceOnMatch(PathDispatcher.java:52)
	com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:29)
	com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:82)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	com.icesoft.faces.webapp.xmlhttp.BlockingServlet.service(BlockingServlet.java:46)

не забываем вызывать setId(String) у каждого созданного в коде элемента - хотя со стандартными компонентами JSF этого не требуется, IceFaces иногда забывает автоматически сгенерировать id - устанавливаем его руками.

Еще одна деталь. Если вы собираетесь использовать master-detail паттерн, используя таблицу с row listener и форму для редактирования выбранного объекта, то запомните - изменять значения в объекте формы можно только в фазе UPDATE_MODEL_VALUES. Делается это просто - в слушателе нужного ивента нужно просто сделать так:



  public void rowSelected(RowSelectionEvent rowSelectionEvent) {
    if (phaseHadArrived(rowSelectionEvent, UPDATE_MODEL_VALUES)) {
       // do something with my model
    }
  }


  /**
   * Checks if current event phase matches the desired phase and if so returns <code>true</code>.
   * Otherwise <code>false</code> is returned and event is queued.
   * @param event
   * @param desiredPhase
   * @return <code>true</code> if the desired phase had arrived
   */
  public static boolean phaseHadArrived(FacesEvent event, PhaseId desiredPhase) {
    PhaseId phaseId = event.getPhaseId();
    if (phaseId.equals(desiredPhase)) {
      return true;
    }
    event.setPhaseId(desiredPhase);
    event.queue();
    return false;
  }

иными словами, отложить выполнение события до нужной нам фазы.

Для упрощения работы с API IceFaces я даже написал небольшой Builder, но об этом чуть позже, когда сам билдер будет достаточно стабилен :)

Добавить комментарий

Предыдущая статья IE file could not be written to the cache Следующая статья Настройка JAAS в Tomcat