2012-06-04 3 views
1

У меня есть веб-приложение ICEfaces, которое содержит компонент со свойством, связанным с переменной bean-компонента. Теоретически переменное значение программно модифицировано, и компонент видит изменения и соответственно обновляет его внешний вид/свойства.Как можно мгновенно обновить параметры компонента JSF/ICEfaces?

Однако, кажется, что изменение переменной не «замечено» компонентом до конца цикла JSF (что, по моему основному пониманию, является render response phase).

Проблема заключается в том, что у меня есть длинная операция копирования файлов для выполнения, и я хотел бы, чтобы компонент inputText отображал периодическое обновление состояния. Однако, поскольку компонент обновляется только на этапе отклика рендера, он не показывает любой вывод до тех пор, пока методы Java не закончат выполнение, и это покажет, что все изменения скопированы сразу.

Я попытался с помощью FacesContext.getCurrentInstance().renderResponse() и других функций, таких как PushRenderer.render(String ID) заставить XmlHttpRequest инициализировать рано, но независимо от того, внешнего вида компоненты не изменяется до тех пор, код Java не закончит выполнение.

Одним из возможных решений, которое приходит на ум, является наличие невидимой кнопки, которая автоматически «нажимается» компонентом, когда шаг 1 длинной операции завершается, и, щелкнув по нему, он вызывает шаг 2 и так далее и так далее. Похоже, что это сработает, но я не хочу тратить время на взломать такое неэлегантное решение, когда я надеюсь, что есть более элегантное решение, встроенное в JSF/ICEfaces.

Я что-то упускаю или прибегаю к уродливым хакам - единственный способ добиться желаемого поведения?

ответ

4

Многопоточность был недостающим звеном, в сочетании с PushRenderer и PortableRenderer (см http://wiki.icesoft.org/display/ICE/Ajax+Push+-+APIs).

У меня теперь есть три потока в моем бэкбоне - один для выполнения длительной операции, один для опроса статуса и один «основной» поток для размножения новых потоков и возврата элемента управления пользовательского интерфейса в браузер клиента.

Как только основная нить запускает потоки выполнения и опроса, она завершается и завершает исходный HTTP-запрос. Мой PortableRenderer объявлен как PortableRender portableRenderer; и в моем инициализации() метод (называемый в конструктор класса) содержит:

PushRenderer.addCurrentSession("fullFormGroup");  
portableRenderer = PushRenderer.getPortableRenderer(); 

Для нарезания резьбы части, я использовал implements Runnable в моем классе, так и для обработки нескольких потоков в одном классе , Я следил за этой записью StackOverflow: How to deal with multiple threads in one class?

Вот несколько исходных кодов. Я не могу раскрыть явный исходный код, который я использовал, но это своя версия, которая не раскрывает никакой конфиденциальной информации.Я не тестировал его, и я написал его в gedit, поэтому у него может быть синтаксическая ошибка или две, но по крайней мере вы должны начать работать в правильном направлении.

public void init() 
{ 
    // This method is called by the constructor. 
    // It doesn't matter where you define the PortableRenderer, as long as it's before it's used. 
    PushRenderer.addCurrentSession("fullFormGroup"); 
    portableRenderer = PushRenderer.getPortableRenderer(); 
} 


public void someBeanMethod(ActionEvent evt) 
{ 
    // This is a backing bean method called by some UI event (e.g. clicking a button) 
    // Since it is part of a JSF/HTTP request, you cannot call portableRenderer.render 

    copyExecuting = true; 

    // Create a status thread and start it 

    Thread statusThread = new Thread(new Runnable() { 
     public void run() { 
     try { 
         // message and progress are both linked to components, which change on a portableRenderer.render("fullFormGroup") call 
      message = "Copying..."; 
      // initiates render. Note that this cannot be called from a thread which is already part of an HTTP request 
      portableRenderer.render("fullFormGroup"); 
      do { 
       progress = getProgress(); 
       portableRenderer.render("fullFormGroup"); // render the updated progress 
       Thread.sleep(5000); // sleep for a while until it's time to poll again 
      } while (copyExecuting); 
      progress = getProgress(); 
      message = "Finished!"; 
      portableRenderer.render("fullFormGroup"); // push a render one last time 
     } catch (InterruptedException e) { 
      System.out.println("Child interrupted."); 
     } 
    }); 
    statusThread.start(); 

    // create a thread which initiates script and triggers the termination of statusThread 
    Thread copyThread = new Thread(new Runnable() {   
     public void run() { 
     File someBigFile = new File("/tmp/foobar/large_file.tar.gz"); 
      scriptResult = copyFile(someBigFile); // this will take a long time, which is why we spawn a new thread 
      copyExecuting = false; // this will caue the statusThread's do..while loop to terminate 


     } 
    }); 
    copyThread.start(); 
} 
+0

Необычный материал ... Большое спасибо ... Icefaces Пример сосать, но вы предоставили такую ​​ясность :) Спасибо :) – Makky

+1

Я рад, что смог помочь! Не забудьте подтвердить ответ, если это будет полезно! Очень хорошая вещь о PortableRenderer заключается в том, что вы можете передать его как параметр для метода в другом классе, чтобы вызвать визуализацию из не-bean-контекста. – StockB

+0

Его просто стыдно, что они не предоставляют учебник в правильном коде. Я очень благодарен за предоставление примеров ... – Makky

0

Я предлагаю смотреть на нашем Showcase Демо:

http://icefaces-showcase.icesoft.org/showcase.jsf?grp=aceMenu&exp=progressBarBean

Под списком примеров Бар Прогресс один называется Push. Он использует Ajax Push (функция, снабженная ICEfaces), чтобы делать то, что, как я думаю, вам нужно.

На этой странице также есть учебное пособие под названием Easy Ajax Push, которое проведет вас через простой пример использования Ajax Push.

http://www.icesoft.org/community/tutorials-samples.jsf

+0

Спасибо за сообщение, но я смог понять это. Я был в замешательстве относительно того, как HTTP-запросы в основном работают. Один из сотрудников JavaRanch смог объяснить это мне: http://www.coderanch.com/t/583103/JSF/java/Updating-component-parameters-before-end Как вы думаете, это верное предложение ICEfaces для абстрагирования этого многопоточного решения (см. Ниже) к простой однострочной линии, которую может вызывать разработчик? Моя первоначальная путаница была вызвана всей маркетинговой шумихой о том, чтобы позволить ICEfaces выполнять всю грязную работу, и это, похоже, является исключением из этой мантры. – StockB

Смежные вопросы