-
1. Re: Refreshing Details With a Thread
jkronegg Sep 22, 2009 1:59 PM (in response to ohughes)Your Component.getInstance(...) is null because your Thread is not attached to a Seam scope.
You should have a look to org.jboss.seam.servlet.ContextualHttpServletRequest or to the @Asynchronous annotation.
-
2. Re: Refreshing Details With a Thread
mwohlf Sep 22, 2009 2:17 PM (in response to ohughes)can I just call
org.jboss.seam.contexts.Lifecycle.beginCall();
to attach the Thread to the seam contexts or is this not so brilliant?
-
3. Re: Refreshing Details With a Thread
ohughes Sep 22, 2009 2:28 PM (in response to ohughes)I've rewritten the thread a little so that it is now a seam component and not a standalone thread:
@Scope(ScopeType.SESSION) @Name("testThreadTesting123") public class TestThread implements Runnable { private boolean keepRunning = true; private int loopCount = 0; private String groupName; /** * */ /*public TestThread(String groupName) { this.groupName = groupName; }*/ @Create public void create() { } @Destroy public void destroy() { } public void setup(String groupName) { this.groupName = groupName; } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { while (keepRunning) { Lifecycle.beginCall(); ConsoleView consoleView = ((ConsoleView) Component.getInstance("consoleView")); consoleView.setTestString("TestString: " + loopCount++); SessionRenderer.render(groupName); Lifecycle.endCall(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } SessionRenderer.removeCurrentSession(groupName); } /** * @param keepRunning the keepRunning to set */ public void setKeepRunning(boolean keepRunning) { this.keepRunning = keepRunning; } }
and to instansiate the thread:
@Name(value = "consoleView") @Scope(ScopeType.PAGE) public class ConsoleView extends HibernateEntityHome<DataSource> { ... /** * @param id */ @RequestParameter public void setMediationFlowId(Integer id) { if (getId() == null) { //setup some things .... TestThread testThread = (TestThread) Component.getInstance("testThreadTesting123"); testThread.setup(getSessionRenderName()); (new Thread(testThread)).start(); } } ... }
Is this what you meant? I'm still getting a NPE for the consoleView object.
I've googled ContextualHttpServletRequest, but can't find anything useful, any pointers?
Thanks.
-
4. Re: Refreshing Details With a Thread
mwohlf Sep 22, 2009 2:57 PM (in response to ohughes)sorry for the noise, I had some success using the
Lifecycle.beginCall();
also see:
http://seamframework.org/Community/UseSeamComponentsFromANonseamClass
(you probably only need to call it once per Thread)I didn't really check your code but maybe your component is not yet created,
maybeComponent.getInstance("testThreadTesting123", true);
does the trick? (sorry just wild guessings here)
-
5. Re: Refreshing Details With a Thread
ohughes Sep 24, 2009 8:52 AM (in response to ohughes)Hmmm, I have tried these approaches but I can't seem to get any of them to work, they always say that the
ConsoleView consoleView = ((ConsoleView) Component.getInstance("consoleView"))
is null.
Does anyone have any sample code where they have a separate thread calling a seam component every n seconds or something similar?
-
6. Re: Refreshing Details With a Thread
kapitanpetko Sep 24, 2009 11:20 AM (in response to ohughes)Use @Asynchronous methods instead of threads. That gives you injection and access to request and application scope. Also much easier :)
HTH
-
7. Re: Refreshing Details With a Thread
ohughes Sep 24, 2009 11:44 AM (in response to ohughes)Thanks Nikolay, I'll investigate further down the @Asynchronous route. Do you know of a good example anywhere? with good sample code?
-
8. Re: Refreshing Details With a Thread
kapitanpetko Sep 24, 2009 11:49 AM (in response to ohughes)Seam manual: 22.2. Asynchronicity.
There are some examples in the Seam distribution (at least seampay and quartz, IIRC).
-
9. Re: Refreshing Details With a Thread
ohughes Sep 24, 2009 1:09 PM (in response to ohughes)Well, I've rewritten a couple of bits, and now I have a class which simply has the @Asynchronous method, and it calls it beautifully, but now for the next problem.
As you see from the code I posted previously, the ConsoleView component is in scope Page, and therefore the Component.getInstance doesn't seem to pick this up, i.e. it always returns me a null. If I change this to be conversation scope, it seems that the Component.getInstance is trying to create a brand new instance of the seam component, and not picking up the one that has been cretaed. Any thoughts or suggestions?
Here is the code for the Asynchronous bit:
@Name("testThreadTesting123") @AutoCreate public class TestThread { private int loopCount = 0; @Create public void create() { } @Destroy public void destroy() { } @Asynchronous public QuartzTriggerHandle testing(@Expiration Date start, @IntervalDuration Long interval) { Lifecycle.beginCall(); ConsoleView consoleView = ((ConsoleView) Component.getInstance("consoleView")); consoleView.setTestString("TestString: " + loopCount++); SessionRenderer.render(consoleView.getSessionRenderName()); Lifecycle.endCall(); return null; } }
And here is the code that instantiates it:
@Name(value = "consoleView") @Scope(ScopeType.PAGE) public class ConsoleView extends NexusEntityHome<DataSource> implements ActionButtonListener { ... @In private TestThread testThreadTesting123; @Override public void create() { super.create(); setup(); SessionRenderer.addCurrentSession(getSessionRenderName()); testThreadTesting123.testing(new Date(), new Long(1000)); } ... }
-
10. Re: Refreshing Details With a Thread
kapitanpetko Sep 25, 2009 3:11 AM (in response to ohughes)
Osian Hughes wrote on Sep 24, 2009 13:09:
As you see from the code I posted previously, the ConsoleView component is in scope Page, and therefore the Component.getInstance doesn't seem to pick this up, i.e. it always returns me a null. If I change this to be conversation scope, it seems that the Component.getInstance is trying to create a brand new instance of the seam component, and not picking up the one that has been cretaed. Any thoughts or suggestions?Well, since this works in a new thread (not the request thread), you don't have access to session/conversation/page contexts. You can
only use application and event contexts.
Here is the code for the Asynchronous bit:First, you do not need to call Lifecycle, that is done for you by Seam. What exactly are you trying to achieve?
If you want to update some page, say every 5 minutes, your best bet is to do your background processing in an
async method, and do polling on your page (with <ajax:poll> or some such.HTH
-
11. Re: Refreshing Details With a Thread
ohughes Sep 25, 2009 10:31 AM (in response to ohughes)Hi Nikolay,
The refreh is exactly what I am trying to acheive, but I am using Icefaces, which uses a push from the server to refresh the page, and not the page requesting, hence why I need to make changes, and then push them to the server from a separate thread (or now the asynchronous call). Therefore I need to access the consoleView component from the Asynchronous call, perform some updates, and then I tell the SessionRenderer (Icefaces push stuff) that changes have occurred, and then the page is updated.
I'll take a look at combining Icefaces and Richfaces and see if this helps, if not, any ideas?
Thanks
-
12. Re: Refreshing Details With a Thread
kapitanpetko Sep 25, 2009 10:38 AM (in response to ohughes)I haven't used Icefaces, so can't help you there really. I don't know how Icefaces push works, but I'm
reasonably sure it needs the access to the request thread to make it work (and you cannot get to it from an
async method). Does it keep an open http connection for push (Comet style)?If all else fails, Icefaces probably has a polling component, just
use it, instead of putting richfaces in the mix. -
13. Re: Refreshing Details With a Thread
ohughes Sep 25, 2009 1:04 PM (in response to ohughes)Hi Nikolay,
It is now finally working, I found an example for Icefaces and Seam (JBoss Seam Integration), which allows me to push chagnes to the page, so now, every second I have the page updated as appropriate.
Here is some sample code if anyone else needs something similar:
@Name(value = "consoleView") @Scope(ScopeType.PAGE) public class ConsoleView extends NexusEntityHome<DataSource> implements ActionButtonListener, Renderable { @In private RenderManager renderManager; private PersistentFacesState state; private IntervalRenderer intervalRenderer; ... @Override public void create() { super.create(); setup(); SessionRenderer.addCurrentSession(getSessionRenderName()); state = PersistentFacesState.getInstance(); intervalRenderer = renderManager.getIntervalRenderer("consoleViewRenderer"); intervalRenderer.setInterval(1000); intervalRenderer.add(this); intervalRenderer.requestRender(); } ... //Method hooked up to the web page public String getDataSourceLabel() { state = PersistentFacesState.getInstance(); performRefresh(); if (getSelectedDataSources().size() == 1) { return getSelectedDataSources().firstElement().getFullDisplayString(); } return getTranslator().get("label.multiple.upstreamsources"); } private void performRefresh() { //Do some stuff SessionRenderer.render(getSessionRenderName()); } ... @Override public PersistentFacesState getState() { return state; } @Override public void renderingException(RenderingException arg0) { if (intervalRenderer != null && intervalRenderer.contains(this)) { intervalRenderer.remove(this); if (intervalRenderer.isEmpty()) { intervalRenderer.requestStop(); } } } }