Как мы знаем, ограниченный поток задач может быть вызван по некоторому URL либо напрямую из браузера, либо из какого-либо внешнего приложения. Эта функция включена, если для свойства потока задач «URL invoke» установлено значение «url-invoke-разрешено», и оно обычно используется в интеграционных проектах. Обычно клиенты (или инициаторы) используют метод HTTP GET и передают свои параметры в URL. Давайте рассмотрим простой поток задач с одним обязательным входным параметром:
| 1 2 3 4 5 6 7 8 |   <task-flow-definition id="task-flow-definition">        <input-parameter-definition id="__23">      <name id="__24">userName</name>      <value id="__67">#{requestScope.userName}</value>      <classid="__63">java.lang.String</class>      <required/>    </input-parameter-definition>        ... | 
Поток задач может быть вызван следующим URL
| 1 | http://127.0.0.1:7101/TestApp/faces/adf.task-flow?adf.tfId=task-flow-definition&adf.tfDoc=/WEB-INF/task-flow-definition.xml&userName=xammer | 
Клиент использует простую HTML-форму для создания этого запроса GET:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | <html>  <head>        <meta http-equiv="Content-Type"content="text/html; charset=UTF-8"/>  </head>  <body>   <input type="hidden"name="adf.tfId"value="task-flow-definition"/>     <input type="hidden"name="adf.tfDoc"value="/WEB-INF/task-flow-definition.xml"/>     <label>             User Name       <input type="text"name="userName"value="xammer"/>     </label>      <input type="submit"value="Submit"/>    </form>    </body></html> | 
И это выглядит так:
Некоторые клиенты предпочитают использовать метод HTTP POST, и, кроме того, это их требование:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | <html>  <head>        <meta http-equiv="Content-Type"content="text/html; charset=UTF-8"/>  </head>  <body>   <input type="hidden"name="adf.tfId"value="task-flow-definition"/>     <input type="hidden"name="adf.tfDoc"value="/WEB-INF/task-flow-definition.xml"/>     <label>             User Name       <input type="text"name="userName"value="xammer"/>     </label>      <input type="submit"value="Submit"/>   </form>   </body></html> | 
И это прекрасно работает. URL в этом случае будет выглядеть так:
| 1 | http://127.0.0.1:7101/TestApp/faces/adf.task-flow | 
Вся остальная необходимая информация, такая как идентификатор потока задач и значение параметра, находится внутри запроса POST. Но проблема в том, что он работает нормально только для R1. Если мы попробуем это на R2, мы получим следующее:
ADF_FACES-30179: Дополнительные сведения см. В журнале ошибок сервера для записи, начинающейся с: UIViewRoot имеет значение null. Неустранимое исключение во время PhaseId: RESTORE_VIEW 1.
Почему? Из-за этого:
| 1 2 3 4 5 6 | oracle.adfinternal.controller.application.InvokeTaskFlowException: ADFC-02006: A task flow ID is not found inthe URL.    at oracle.adfinternal.controller.util.UrlParams.getTaskFlowInfo(UrlParams.java:144)    at oracle.adfinternal.controller.application.RemoteTaskFlowCallRequestHandler.invokeTaskFlowByUrl(RemoteTaskFlowCallRequestHandler.java:84)    at oracle.adfinternal.controller.application.RemoteTaskFlowCallRequestHandler.doCreateView(RemoteTaskFlowCallRequestHandler.java:63) | 
Все необходимые данные, включая идентификатор потока задач, который должен быть передан внутри запроса POST, теряются. Почему? Из-за «петли». Если мы обнаружим запросы, отправленные из браузера на сервер при нажатии кнопки «Отправить», мы увидим следующее:
Таким образом, вместо отправки «честного» ответа сервер отправляет некоторый «петлевой» скрипт, который генерирует «идентификатор окна» и отправляет следующий запрос GET с созданным идентификатором окна. Здорово! Но все почтовые данные исчезли. Запрос GET абсолютно пустой.
К счастью, фреймворк не генерирует никаких «петель», если исходный запрос POST уже имеет некоторый «идентификатор окна». Итак, обходной путь для нашего случая — разработать фильтр сервлета, установив атрибут «id окна» для нашего запроса:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | publicvoiddoFilter(ServletRequest servletRequest,                     ServletResponse servletResponse,                     FilterChain filterChain)  throwsIOException, ServletException{  HttpServletRequest r = (HttpServletRequest) servletRequest;  HttpSession s = r.getSession();  //May be this is not an initial request and window id has been generated earlier  //We want all the following requests to work with the same window id   //For our use-case this is ok      String windowID = (String) s.getAttribute(_WINDOW_ID_KEY);  if(windowID == null)  {    String pathInfo = r.getPathInfo();    //This is an initial POST request to get access to the task flow    if(("/adf.task-flow").equals(pathInfo) &&        "POST".equals(r.getMethod()))    {      windowID = WINDOW_ID;      //Save window id in the session       s.setAttribute(_WINDOW_ID_KEY, windowID);    }  }  //Setup attribute for the request  //This will prevent generating of the loopback  if(windowID != null)    r.setAttribute(_WINDOW_ID_KEY, windowID);  filterChain.doFilter(servletRequest, servletResponse);}privatestaticfinalString __WINDOW_MANAGER_KEY = RichWindowManager.class.getName();privatestaticfinalString _WINDOW_ID_KEY = __WINDOW_MANAGER_KEY + "#WINDOW_ID";  privatestaticfinalString WINDOW_ID = "wextflow"; | 
Обратите внимание, что этот фильтр должен стоять перед фильтром «Тринидад» в цепочке фильтров:
| 01 02 03 04 05 06 07 08 09 10 11 12 |   <filter>    <filter-name>ExtPostFilter</filter-name>    <filter-class>com.cs.fusion.core.view.filter.ExtPostFilter</filter-class>  </filter>   <filter>    <filter-name>trinidad</filter-name>    <filter-class>org.apache.myfaces.trinidad.webapp.TrinidadFilter</filter-class>  </filter>  <filter>    <filter-name>ServletADFFilter</filter-name>    <filter-class>oracle.adf.share.http.ServletADFFilter</filter-class>  </filter> | 
Это оно!


