I have a button that calls a method from the backing Bean. This method allows to extract data from parsing html code. While the method is running i have a dialog showing a progress bar and a command button Cancel
. I need when the user click the cancel button the method called by the extract button stops.
我有一个从后台Bean调用方法的按钮。该方法允许从解析html代码中提取数据。当方法运行时,我有一个显示进度条和命令按钮取消的对话框。当用户单击cancel按钮时,提取按钮调用的方法将停止。
This is my html code:
这是我的html代码:
<p:commandButton
value="Start" style="width: 12%;height: 100%"
update=":confirmPurchase, :confirmPurchaseTest, :mainform" id="extractbutton"
ajax="true" widgetVar="ButtonExtract"
actionListener="#{mailMB.searchEmails()}"
icon="ui-icon-disk" styleClass="ui-priority-primary"
onstart="blockUIWidget1.show();" oncomplete=" blockUIWidget1.hide();" />
<p:dialog widgetVar="blockUIWidget1" header="Hitonclick" modal="true"
resizable="false" closable="false">
<table border="0" style="width: 500px">
<tbody >
<tr>
<td>
<p:graphicImage url="pictures/loading81.gif" width="200" height="200" alt="animated-loading-bar"/>
</td>
<td>
<h:outputLabel value="Extracting is in progress. Please wait..."/>
<div align="center">
<p:commandButton value="Cancel" title="Cancel" />
</div>
</td>
</tr>
<div align="right">
</div>
</tbody>
</table>
</p:dialog>
And here is my searchEmails method in my sessionScoped Bean
这是我的sessionScoped Bean中的searchemail方法。
public void searchEmails() throws Exception {
idCustomer = (String) session.getAttribute("idCustomer");
System.out.println(idCustomer + " this is it");
Customer customer = customerBusinessLocal.findById(idCustomer);
data = dataBusinessLocal.createData(new Date(), number, keyword, moteur, customer, State.REJECTED);
mails = mailBusinessLocal.createEmails(keyword, number, moteur, data);
System.out.println("Method was invoked");
}
How can i stop the searchEmails method from running via the cancel command button?
如何阻止searchEmails方法通过“取消命令”按钮运行?
2 个解决方案
#1
12
ExecutorService with interrupt friendly tasks
ExecutorService文档
-
Instead of directly calling the method, convert the method into an
ExecutorService
's task.与其直接调用方法,不如将方法转换为ExecutorService的任务。
public class SearchEmailsTask implements Runnable { private EmailSearcher emailSearcher; public SearchEmailsTask(EmailSearcher emailSearcher) { this.emailSearcher = emailSearcher; } @Override public void run() { emailSearcher.searchEmails(); } }
You can use
Callable<Object>
if you want to return something.如果您想要返回某些东西,可以使用Callable
-
When you want call the method, submit that task to an
ExecutorService
.当您希望调用该方法时,将该任务提交给ExecutorService。
ExecutorService executorService = Executors.newFixedThreadPool(4); SearchEmailsTask searchEmailsTask = new SearchEmailsTask(new EmailSearcher()); Future<?> future = executorService.submit(searchEmailsTask);
-
Keep a reference to the task.
保持对任务的引用。
private static Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();
A map should be a good idea to store multiple
Future
objects. You can of course go for something better if you want.映射应该是存储多个未来对象的好主意。如果你愿意的话,当然可以选择更好的。
-
Call cancel on the task whenever required.
在需要时调用cancel。
future.cancel(true);
Note:
Task should have suitable checks for thread interruption for proper cancellation.
To achieve this, refer to
注意:任务应该对线程中断进行适当的检查,以便进行适当的取消。要实现这一点,请参考。
- Future task of ExecutorService not truly cancelling
- 未来的执行任务并没有真正取消
- how to suspend thread using thread's id?
- 如何使用线程id挂起线程?
Good luck.
祝你好运。
#2
3
With your current architecture it's not going to be easy. By looking at your code it seems that you are calling two big operations that can't be aborted in the middle. You must break the work into small units and make the processing abortable.
有了当前的架构,这就不容易了。通过查看代码,您似乎正在调用两个不能在中间中止的大型操作。您必须将工作分解成小单元,并使处理可中止。
The easiest solution that uses your current code could look something like this.
使用当前代码的最简单的解决方案可以如下所示。
public class SessionScopedMailBean {
volatile boolean searchAborted;
public void searchEmails() throws Exception {
searchAborted = false;
while(!searchAborted) {
// Process a single unit of work
}
}
public void abortSearch() {
searchAborted = true;
}
}
In JSF:
在JSF中:
<p:commandButton value="Cancel" title="Cancel" actionListener="#{mailMB.abortSearch()}" />
That said I'd recommend using executors and futures based approach for cleaner architecture. Then you can also implement a real progress bar not just an animated GIF spinner.
也就是说,我建议使用执行器和基于期货的方法来实现更清洁的体系结构。然后你也可以实现一个真正的进度条,而不仅仅是一个动画GIF旋转器。
Another problem with performing a long operation in command handler is that eventually the HTTP request will time out.
在命令处理程序中执行长期操作的另一个问题是,HTTP请求最终将超时。
A cleaner solution will look like this:
一个更干净的解决方案会是这样的:
public class SessionScopedBean {
ExecutorService pool;
List<Future<Void>> pendingWork;
@PostConstruct
public void startPool() {
pool = Executors.newFixedThreadPool(1);
}
@PreDestroy
public void stopPool() {
if(executor != null)
pool.shutdownNow();
}
public void startSearch() {
pendingWork = new ArrayList<Future<Void>>();
// Prepare units of work (assuming it can be done quickly)
while(/* no more work found */) {
final MyType unit = ...; // Determine next unit of work
Callable<Void> worker = new Callable<Void>() {
@Override
public Void call() throws Exception {
// Do whatever is needed to complete unit
}
};
pendingWork.add(pool.submit(worker));
}
}
public int getPending() {
int nPending = 0;
for(Future<MyResultType> i: pendingWork)
if(!i.isDone()) nPending++;
return nPending;
}
public void stopSearch() {
for(Future<Void> i: pendingWork)
if(!i.isDone()) i.cancel(true);
}
}
Then use an AJAX polling component to poll getPending to determine when it's done and hide the window.
然后使用AJAX轮询组件轮询getPending,以确定何时完成,并隐藏窗口。
See also:
参见:
- http://www.vogella.com/tutorials/JavaConcurrency/article.html#futures
- http://www.vogella.com/tutorials/JavaConcurrency/article.html期货
- JSF polling a database from an application bean at timed intervals
- JSF在时间间隔内从应用程序bean中轮询数据库。
- http://www.mkyong.com/spring/spring-postconstruct-and-predestroy-example/
- http://www.mkyong.com/spring/spring-postconstruct-and-predestroy-example/
#1
12
ExecutorService with interrupt friendly tasks
ExecutorService文档
-
Instead of directly calling the method, convert the method into an
ExecutorService
's task.与其直接调用方法,不如将方法转换为ExecutorService的任务。
public class SearchEmailsTask implements Runnable { private EmailSearcher emailSearcher; public SearchEmailsTask(EmailSearcher emailSearcher) { this.emailSearcher = emailSearcher; } @Override public void run() { emailSearcher.searchEmails(); } }
You can use
Callable<Object>
if you want to return something.如果您想要返回某些东西,可以使用Callable
-
When you want call the method, submit that task to an
ExecutorService
.当您希望调用该方法时,将该任务提交给ExecutorService。
ExecutorService executorService = Executors.newFixedThreadPool(4); SearchEmailsTask searchEmailsTask = new SearchEmailsTask(new EmailSearcher()); Future<?> future = executorService.submit(searchEmailsTask);
-
Keep a reference to the task.
保持对任务的引用。
private static Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();
A map should be a good idea to store multiple
Future
objects. You can of course go for something better if you want.映射应该是存储多个未来对象的好主意。如果你愿意的话,当然可以选择更好的。
-
Call cancel on the task whenever required.
在需要时调用cancel。
future.cancel(true);
Note:
Task should have suitable checks for thread interruption for proper cancellation.
To achieve this, refer to
注意:任务应该对线程中断进行适当的检查,以便进行适当的取消。要实现这一点,请参考。
- Future task of ExecutorService not truly cancelling
- 未来的执行任务并没有真正取消
- how to suspend thread using thread's id?
- 如何使用线程id挂起线程?
Good luck.
祝你好运。
#2
3
With your current architecture it's not going to be easy. By looking at your code it seems that you are calling two big operations that can't be aborted in the middle. You must break the work into small units and make the processing abortable.
有了当前的架构,这就不容易了。通过查看代码,您似乎正在调用两个不能在中间中止的大型操作。您必须将工作分解成小单元,并使处理可中止。
The easiest solution that uses your current code could look something like this.
使用当前代码的最简单的解决方案可以如下所示。
public class SessionScopedMailBean {
volatile boolean searchAborted;
public void searchEmails() throws Exception {
searchAborted = false;
while(!searchAborted) {
// Process a single unit of work
}
}
public void abortSearch() {
searchAborted = true;
}
}
In JSF:
在JSF中:
<p:commandButton value="Cancel" title="Cancel" actionListener="#{mailMB.abortSearch()}" />
That said I'd recommend using executors and futures based approach for cleaner architecture. Then you can also implement a real progress bar not just an animated GIF spinner.
也就是说,我建议使用执行器和基于期货的方法来实现更清洁的体系结构。然后你也可以实现一个真正的进度条,而不仅仅是一个动画GIF旋转器。
Another problem with performing a long operation in command handler is that eventually the HTTP request will time out.
在命令处理程序中执行长期操作的另一个问题是,HTTP请求最终将超时。
A cleaner solution will look like this:
一个更干净的解决方案会是这样的:
public class SessionScopedBean {
ExecutorService pool;
List<Future<Void>> pendingWork;
@PostConstruct
public void startPool() {
pool = Executors.newFixedThreadPool(1);
}
@PreDestroy
public void stopPool() {
if(executor != null)
pool.shutdownNow();
}
public void startSearch() {
pendingWork = new ArrayList<Future<Void>>();
// Prepare units of work (assuming it can be done quickly)
while(/* no more work found */) {
final MyType unit = ...; // Determine next unit of work
Callable<Void> worker = new Callable<Void>() {
@Override
public Void call() throws Exception {
// Do whatever is needed to complete unit
}
};
pendingWork.add(pool.submit(worker));
}
}
public int getPending() {
int nPending = 0;
for(Future<MyResultType> i: pendingWork)
if(!i.isDone()) nPending++;
return nPending;
}
public void stopSearch() {
for(Future<Void> i: pendingWork)
if(!i.isDone()) i.cancel(true);
}
}
Then use an AJAX polling component to poll getPending to determine when it's done and hide the window.
然后使用AJAX轮询组件轮询getPending,以确定何时完成,并隐藏窗口。
See also:
参见:
- http://www.vogella.com/tutorials/JavaConcurrency/article.html#futures
- http://www.vogella.com/tutorials/JavaConcurrency/article.html期货
- JSF polling a database from an application bean at timed intervals
- JSF在时间间隔内从应用程序bean中轮询数据库。
- http://www.mkyong.com/spring/spring-postconstruct-and-predestroy-example/
- http://www.mkyong.com/spring/spring-postconstruct-and-predestroy-example/