-
1. Re: How to pass error messages returned from an @Asynchronous method to a different component?
cash1981 Sep 8, 2010 2:51 PM (in response to shin0135)Please next time use 10 seconds to search the documentation before asking a question.
-
2. Re: How to pass error messages returned from an @Asynchronous method to a different component?
shin0135 Sep 8, 2010 3:16 PM (in response to shin0135)Thanks Shervin,
Yes, I've looked at the document before. I don't know if this is right, but, in my case, I just need a message. So, what I did is
I passed an object when I raised an event and when an error occurs in the asynchronous method, I set appropriate fields like below:
Events.instance().raiseAsynchronousEvent("eventToWatch", myBean, obj);
@Asynchronous @Observer("eventToWatch") public void process(final MyBean myBean, final List<MyDto> records, final MyObjectToCapture obj) { final MyFacade facade = new MyFacade(myBean .getClient()); try { for (List<MyDto> temp : records) ) { facade.process(temp); } } catch (final Exception e) { LOGGER.error(e.getMessage(), e); // how to return this error - e.getMessage or just e // to a different component, which is in Conversation scope obj.setErrorMessage(e.getMessage); return; }
-
3. Re: How to pass error messages returned from an @Asynchronous method to a different component?
lvdberg Sep 8, 2010 3:29 PM (in response to shin0135)Hi,
I am not sure, but I think you want to get a message to the user. This is a bit trickier. For this I use a a4j:push in combination with the Primefaces growl component )although the normal message component should work also)
<h:form id="growlForm"> <a4j:region regionRenderOnly="true"> <a4j:outputPanel id="growl" > <p:growl showDetail="true" globalOnly="false" life="#{growlTime != null ? growlTime : 6000}" sticky="#{growlSticky != null ? growlSticky : false}"/> <a4j:poll id="msgEvent" interval="2500" timeout="5000" reRender="growl" limitToList="true" eventsQueue="inputQueue" action="#{pushBean.growl}" /> </a4j:outputPanel> </a4j:region> </h:form>
the growlSticky and and growlTime beans vars are Session scoped vars which determine if the message sticks on the screen and the other one is the time it is visible if it is not sticky..
the pushbean is as follows:
@Name("pushBean") @Scope(ScopeType.APPLICATION) public class IncidentMessagePushBean { @In(required=false) FacesMessages facesMessages; @In(required=false) protected User currentUser; @Logger Log log; protected HashMap<String,PushEventListener> listeners = new HashMap<String, PushEventListener>(); protected HashMap<String, LinkedList<FacesMessage>> operatorMessages = new HashMap<String, LinkedList<FacesMessage>>(); @In(required=false) private Map<String, String> messages; public void addListener(EventListener l) { synchronized(this){ listeners.put(currentUser.getUserName(), (PushEventListener) l); } log.info("Added a listener for user " + currentUser.getUserName() + " we now have " + listeners.size() + " listeners." ); } /** This method catsches all the defined events and sends an update * request to all the views. Its minimum delay time is 5 seconds to ensure that * the display stays relatively stable. */ @Observer(value={"es.esam.im4u.incidentmessage.new", "es.esam.im4u.operator.login"} ) public synchronized void processEvent(String o, String h, String d){ FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_WARN, messages.get(h), messages.get(d)); /** Check if this message if directed to all users at-once */ if (o != null && o.equalsIgnoreCase("all")){ Set<String> keys = operatorMessages.keySet(); for (String name: keys){ if (operatorMessages.get(name).size() < 8) operatorMessages.get(name).add(msg); else { LinkedList<FacesMessage> list = operatorMessages.get(name); if(!list.isEmpty()) list.removeFirst(); operatorMessages.get(name).add(msg); } } } else { if (operatorMessages.get(o) == null ){ LinkedList<FacesMessage> list = new LinkedList<FacesMessage>(); list.add(msg); operatorMessages.put(o, list); } else { if (operatorMessages.get(o).size() < 8) operatorMessages.get(o).add(msg); else{ LinkedList<FacesMessage> list = operatorMessages.get(o); if(!list.isEmpty()) list.removeFirst(); operatorMessages.get(o).add(msg); } } } } /** Provides a value which will be used to give a message to the current user */ public void growl(){ if (currentUser != null && operatorMessages.get(currentUser.getUserName()) != null && operatorMessages.get(currentUser.getUserName()).size() > 0 ){ FacesContext context = FacesContext.getCurrentInstance(); for (FacesMessage m: operatorMessages.get(currentUser.getUserName())) { m.setSummary(messages.get(m.getSummary())); m.setDetail(messages.get(m.getDetail())); context.addMessage("test", m); } operatorMessages.get(currentUser.getUserName()).clear(); } } }
What I basically do in the processEvent method is the username (o) and the normal and detail message of the component. I call this meyhod with a simple (async) event and the system does the rest for you.
Hopefully this helps!
Leo
-
4. Re: How to pass error messages returned from an @Asynchronous method to a different component?
cash1981 Sep 8, 2010 3:48 PM (in response to shin0135)Again this is very easy to do.
When you look at the link I showed you, you can create your exceptionhandler. In the exceptionhandler you can do whatever you want.
If you want to send the message to another component, this is very easily done:
@Override public void handleException(Exception exception) { //Get the message Writer w = new StringWriter(); exception.printStackTrace(w); //Now you send the stacktrace to some other component that listens to this. //Alternatively you can send the entire exception Events.raiseEvent("asynchException",w.toString()); }
-
5. Re: How to pass error messages returned from an @Asynchronous method to a different component?
shin0135 Sep 8, 2010 3:50 PM (in response to shin0135)Leo,
Thank you for your example. Is there a replacement of
growl
in RichFaces? Yes, basically, what I'm trying to do is to display any error messages to users. I'm using<a4j:poll>
currently, but I wasn't able to pass errors to a component calling the asynchronous method until I found a way by passing an object.
-
6. Re: How to pass error messages returned from an @Asynchronous method to a different component?
lvdberg Sep 8, 2010 5:40 PM (in response to shin0135)Hi James,
Rich doesn't have a growl-type component. Beceuase of browser compatibility problems I 'm not using PrimeFaces a lot, but growl is an great exception. It works great for warning the user. Another nice component is NotificationBar.
The problem wiyj poll is that it executes the action-method, while push just call the listener and only calls the action method when there is really something to do.
Leo
-
7. Re: How to pass error messages returned from an @Asynchronous method to a different component?
shin0135 Sep 8, 2010 7:21 PM (in response to shin0135)Thanks, Shervin and Leo!
I'll try to implement my own exception handler and try to use push.
-
8. Re: How to pass error messages returned from an @Asynchronous method to a different component?
serkan.s.eskici.online.nl Sep 9, 2010 4:55 AM (in response to shin0135)Keep it simple !
Pass a List of Exception into your asynchronous method as a parameter and add the exception to that list.
Thus:
//your calling bean: public class CallingBean { List<Exception> exceptions; public void foo() { bar.asynchronousCall(..., exceptions); for(Exception e : exceptions) { //do something } } }
public class AsyncBean { @Asynchronous public void asynchronousCall(..., List<Exception> exp) { try { ... } catch (Exception e) { ... exp.add(e); } } }
-
9. Re: How to pass error messages returned from an @Asynchronous method to a different component?
lvdberg Sep 9, 2010 5:56 AM (in response to shin0135)Hi Serkan,
Your solution won't work because of two reasons:
(a) you will get a NPE, because the List with exceptions is not initialized So you could add:
new ArrayList<Exception>();
but it still doesn't work because
(b) the call to the async method will return immediately (because the method creates a new Thread ) so after
bar.asynchronousCall(..., exceptions);
There is still nothing in the List
It is NOT that simple.
Leo
-
10. Re: How to pass error messages returned from an @Asynchronous method to a different component?
serkan.s.eskici.online.nl Sep 12, 2010 6:31 AM (in response to shin0135)
Leo van den Berg wrote on Sep 09, 2010 05:56:
Hi Serkan,
Your solution won't work because of two reasons:
(a) you will get a NPE, because the List with exceptions is not initialized So you could add:new ArrayList<Exception>();
but it still doesn't work because
(b) the call to the async method will return immediately (because the method creates a new Thread ) so afterbar.asynchronousCall(..., exceptions);
There is still nothing in the List
It is NOT that simple.
LeoIt is really that simple, because I've done it like that and it works. You simply make a call by reference and why should that not work (even though you pass the list in a seperate thread) ?
Although there is one thing that needs extra attention and it has to do with (b).
In your CallingBean you need to register those asynchronous calls in a Collection, otherwise you can't keep up with the speed (because they're executed in a seperate thread and it goes too fast).
Thus, in code it should look something like this:
@Name("callingBean") public class CallingBean { List<Exception> exceptions = ...; Set<Long> calledThreads = ...; public void foo(someUniqueIdForThisRequest) { if(calledThreads.contains(someUniqueIdForThisRequest)) return; calledThreads.add(someUniqueIdForThisRequest); bar.asynchronousCall(..., exceptions); } public boolean isFinished() { boolean finished = //place the condition, for example calledThreads.size() == 0; if(finished) return true; synchronized(exceptions) { for(Exception e : exceptions) { //do something //and increase/decrease some counter for the handled threads //example: calledThreads.remove(someUniqueIdForThisRequest); } } return finished; } }
In your .xhtml file: <a4j:poll action="#{callingBean.foo(someUniqueIdForThisRequest)}" enabled="#{not callingBean.calledThreads.contains[someId]}" reRender="comp1, comp2, etc."/> <a4j:outputPanel> <s:div id="comp1" rendered="#{callingBean.isFinished()}"> ... </s:div> </a4j:outputPanel>
-
11. Re: How to pass error messages returned from an @Asynchronous method to a different component?
lvdberg Sep 12, 2010 10:00 AM (in response to shin0135)Hi Serkan,
My first reaction was not to respond, because we get into a yes-no discussion on basic jave matters and this degrades the quality of this forum substantially. However I want to respond, because the main function of this forum is to help and share experience.
From your reply:
In your CallingBean you need to register those asynchronous calls in a Collection, otherwise you can't keep up with the speed (because they're executed in a seperate thread and it goes too fast).
The problem with astandard
Thread is that is out of your control once fired. There are differences between platforms in the way they handle Threads in their VM.First you have added the responsiblity of using a sort of Async-id to your calling bean and make the view-layer responsible for using it. So where do you store and retrieve
someId
?
Secondly - as indicated by you - there's the Thread-speed (and priority and exececution order etc.) which still isn't solved. So this approach can fail horribly on other platforms (OS or processorpeed).The nice thing of Seam is getting rid of all these cross-cutting concerns which don't belong in your business logic. Look at Shervin's solution which is very simple and can be used in combination with ajax-push/poll to render.
Leo