As I wrote before, PageAttached is invoked on all pages somehow related to request (e.g. if some component uses @InjectPage to refer some other page), not only on rendered page. I have not really used PageAttached in the production code myself, so it is only speculations, but maybe you could detect which components are from active page, by checking the active page from RequestGlobal and the page name containing the component via ComponentResources. For debugging purposes, you can also get component's ID from ComponentResources.getCompleteId() - it might help you understand on what components pageAttached() is invoked.
Regarding, Heartbeat, you can check how standard Tapestry's Label and Error components use it. They are quite simple, and just modify a single attribute,on a previously created Element, but potentially you can create any DOM tree you want. Of course, it would require much more work then just using normal Tapestry templates, and probably it would prevent using nested components. Depending on complexity of the project and time you can spend, I would recommend considering the following questions in this order: - Can you make remote invocations somehow faster, e.g. by caching/preloading some data? - Can you put slow components either in ProgressiveDisplay or separate IFRAMEs, so initial page will appear faster? If you track users sessions, you might even initiate asynchronous calls on the main page load, and retrieve results in ProgressiveDisplay from the session. - Can you initiate remote calls in page's onActivate() and pass Future/Token object to components as parameters? Probably it would require some duplication in code, but it is a simple and easy solution. - If your slow components are quite simple (e.g. just display a single text/number value that is just slow to compute or retrieve), use Heartbeat. But if they are complicated and/or use subcomponents, Heartbeat-solution probably would be to cumbersome. If you are using Tapestry 5.4, try PartialTemplateRenderer service, it might help you to generate partial DOM from component body. - Try pageAttached() approach, but it does not guarantee success, and they are many corner cases. - Add your own prepareData() mechanism. I think it is possible, but requires a lot of Tapestry knowledge, and maybe accessing internal Tapestry API. Best regards, Cezary On Tue, Apr 14, 2015 at 9:04 PM, Тимур Бухараев <bukhar...@gmail.com> wrote: > Yes, i tried PageAttached. I put logs to see call sequences. PageAttached > works fine for page class, but i see many chaotic calls per component. I > expect one call per request per component, but see there are many calls per > component. I dont know why. > > Heartbeat is really interesting option. Thank you for idea. The next my > question is: how update template with actual content in deffered commands? > > On Tue, Apr 14, 2015 at 9:05 PM, Cezary Biernacki <cezary...@gmail.com> > wrote: > > > Hi Тимур, > > Have you tried putting your asynchronous in pageAttached() methods (also > > see @PageAttached annotation) in your components? > > > > https://tapestry.apache.org/page-life-cycle.html > > > > However pageAttached is invoked on all pages that are somehow involved in > > the request processing (e.g. they are referenced via PageLink component) > > and also for requests which are not rendered, so you would need some > extra > > checks to prevent unintended remote service calls. > > > > PageAttached is deprecated in Tapestry 5.3, but it seems to be back and > > working in 5.4. > > > > > > > http://tapestry.apache.org/5.3/apidocs/org/apache/tapestry5/annotations/PageAttached.html > > > > > http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/annotations/PageAttached.html > > > > > > Another option is to use Heartbeat environmental service / > > @HeartbeatDeferred annotation. In this case the component during normal > > rendering just prepares some static template as Tapestry DOM, and invokes > > asynchronous remote call, then on deferred call update the template with > > actual content. > > > > > > Best regards, > > Cezary > > > > > > On Tue, Apr 14, 2015 at 4:08 PM, Тимур Бухараев <bukhar...@gmail.com> > > wrote: > > > > > I don't know how to solve my problem with Future. If you know, explain > > > please. > > > > > > ProgressiveDisplay is a solution, but has some disadvantages. > > > > > > Now about moving data fetch logic. > > > > > > The problem is components are independent. Page class doesn't know > about > > > Component classes, component classes don't know about page and other > > > components. They just embedded in a single tml document. So designer > > could > > > move component to other place, and it still works. Each component > fetches > > > his own remote data independently. I can cache this data in service, if > > > some components need same data, so the second component get cached > data. > > > But component is the only place who knows, what data it needs. For > > example, > > > component displaying user profile. It needs user profile data, and it > > > fetches it. So component is the only thing who knows it need profile > > data. > > > But i can embed it in any tml in any place. > > > > > > On Tue, Apr 14, 2015 at 4:27 PM, Thiago H de Paula Figueiredo < > > > thiag...@gmail.com> wrote: > > > > > > > On Tue, 14 Apr 2015 09:22:36 -0300, Тимур Бухараев < > > bukhar...@gmail.com> > > > > wrote: > > > > > > > > sorry, some mistake in sequence > > > >> > > > >> it should be: > > > >> component1.setupRender(); > > > >> other component1 rendering > > > >> component2.setupRender(); > > > >> other component2 rendering > > > >> > > > > > > > > If you think Future is not the way to go (and that's what I'd use > and I > > > > think it covers your problem from in the description you gave) and > > > neither > > > > ProgressiveDisplay is (which is a good other solution), why don't you > > > move > > > > the data fetch logic for all components in a single place > (preferably a > > > > service, maybe the page) so you can properly parallelize it and the > > > > components themselves just receive the data instead of fetching it? > > > > > > > > > > > > > > > >> On Tue, Apr 14, 2015 at 3:17 PM, Тимур Бухараев < > bukhar...@gmail.com> > > > >> wrote: > > > >> > > > >> Hello, > > > >>> > > > >>> Future would not helps, because components renders one after one. > > > >>> For example page contains component1 and component2. > > > >>> > > > >>> The render sequence is next: > > > >>> > > > >>> component1.setupRender(); > > > >>> other component1 rendering > > > >>> component1.setupRender(); > > > >>> other component2 rendering > > > >>> > > > >>> So if i create Future in setupRender and get result, i get delay1 > in > > > >>> rendering component1, and delay2 in rendering component2. Overall > > delay > > > >>> would be delay1+delay2. > > > >>> If page is complex and contains many independent components which > > call > > > >>> many remote services, overall delay could be very much. > > > >>> > > > >>> > > > >>> Thank you and Chris for ProgressiveDisplay recommending, i'll look > > it. > > > >>> > > > >>> On Tue, Apr 14, 2015 at 3:00 PM, Dmitry Gusev < > > dmitry.gu...@gmail.com> > > > >>> wrote: > > > >>> > > > >>> Hi, > > > >>>> > > > >>>> could you create a Future in your setupRender and use actual > results > > > w/ > > > >>>> Future.get() during the rendering? > > > >>>> > > > >>>> As Chris said I'd also recommend you looking at the > > ProgressiveDisplay > > > >>>> component. > > > >>>> > > > >>>> > > > >>>> > > > >>>> On Tue, Apr 14, 2015 at 2:56 PM, Тимур Бухараев < > > bukhar...@gmail.com> > > > >>>> wrote: > > > >>>> > > > >>>> > I can't call both in setupRender, because i need one blocking > wait > > > to > > > >>>> > receive all requests in parallel. > > > >>>> > > > > >>>> > Steps: > > > >>>> > 1. prepareData(), all components send their request for data, > > > remember > > > >>>> all > > > >>>> > requests. > > > >>>> > 2. setupRender(), all components gets data from tokens. > getData() > > > >>>> could > > > >>>> be > > > >>>> > like this: > > > >>>> > Response getData() { > > > >>>> > while ( !allRequestsAreRecieved() ) { > > > >>>> > Thread.sleep( 10 ); > > > >>>> > } > > > >>>> > return data; > > > >>>> > } > > > >>>> > > > > >>>> > Now, we if we need 3 data: data1, data2, data3, we dont wait on > > > >>>> blocking > > > >>>> > calls 3 times one after one. We do one blocking call. So overall > > > delay > > > >>>> > would be max( delay1. delay2, delay3), not delay1 + delay2 + > > delay3 > > > >>>> > > > > >>>> > On Tue, Apr 14, 2015 at 2:39 PM, Chris Poulsen < > > > >>>> mailingl...@nesluop.dk> > > > >>>> > wrote: > > > >>>> > > > > >>>> > > Or maybe you can use progressive display? > > > >>>> > > > > > >>>> > > > > > >>>> > > > > >>>> http://jumpstart.doublenegative.com.au/jumpstart7/examples/ajax/ > > > >>>> progressivedisplayvariations > > > >>>> > > > > > >>>> > > On Tue, Apr 14, 2015 at 1:36 PM, Chris Poulsen < > > > >>>> mailingl...@nesluop.dk> > > > >>>> > > wrote: > > > >>>> > > > > > >>>> > > > If your prepareData() is non-blocking, why not just call it > > > right > > > >>>> > before > > > >>>> > > > you do the token.getData() ? (both in setupRender() ) > > > >>>> > > > > > > >>>> > > > On Tue, Apr 14, 2015 at 1:03 PM, Тимур Бухараев < > > > >>>> bukhar...@gmail.com> > > > >>>> > > > wrote: > > > >>>> > > > > > > >>>> > > >> Hi, > > > >>>> > > >> > > > >>>> > > >> My pages consist page class and several components inside. > > > >>>> > > >> > > > >>>> > > >> Page and its components needs some information from remote > > > >>>> services. I > > > >>>> > > get > > > >>>> > > >> this information with blocking calls in setupRender(). For > > > >>>> example, > > > >>>> > if i > > > >>>> > > >> need user's profile data, i get it like this: > > > >>>> > > >> > > > >>>> > > >> setupRender() { > > > >>>> > > >> profileData = loadProfileDate(); // blocking call, waiting > > for > > > >>>> the > > > >>>> > > >> response > > > >>>> > > >> } > > > >>>> > > >> > > > >>>> > > >> And now i can use profileData in render to show some > > > information. > > > >>>> > > >> > > > >>>> > > >> The problem is page and components need many remote data, > so > > > >>>> there > > > >>>> are > > > >>>> > > >> many > > > >>>> > > >> serial requests to remote services. It harms latency, > because > > > >>>> overall > > > >>>> > > >> latency is sum of serial requests delays. > > > >>>> > > >> > > > >>>> > > >> I have idea to improve latency, sending requests in > > parallel. I > > > >>>> want > > > >>>> > > make > > > >>>> > > >> non blocking function sendRequest, which returns me token. > > All > > > >>>> > > components > > > >>>> > > >> call non blocking sendRequest for remote data, then i'll > wait > > > in > > > >>>> > > blocking > > > >>>> > > >> call waitResponses(), which wait for all responses.Then > > > component > > > >>>> get > > > >>>> > > >> their > > > >>>> > > >> data from token. > > > >>>> > > >> > > > >>>> > > >> Some code for illustration: > > > >>>> > > >> > > > >>>> > > >> MyComponent { > > > >>>> > > >> @Inject > > > >>>> > > >> private RemoteService remoteService; > > > >>>> > > >> > > > >>>> > > >> private Token<Response> token; > > > >>>> > > >> } > > > >>>> > > >> > > > >>>> > > >> void prepareData() { > > > >>>> > > >> token = remoteService.sendRequest(); // non blocking > call > > > >>>> > > >> } > > > >>>> > > >> > > > >>>> > > >> void setupRender() { > > > >>>> > > >> Response response = token.getData(); // first call is > > > >>>> blocking, > > > >>>> > wait > > > >>>> > > >> for all responses, other calls just return data; > > > >>>> > > >> } > > > >>>> > > >> > > > >>>> > > >> Why i did not just realize my idea and write this post? > > > >>>> > > >> > > > >>>> > > >> Because i need two separate phases: first for send request, > > and > > > >>>> second > > > >>>> > > for > > > >>>> > > >> prepare rendering. All componets should send in first > phase, > > > and > > > >>>> after > > > >>>> > > get > > > >>>> > > >> data in second. > > > >>>> > > >> > > > >>>> > > >> Tapestry have setupRender and beginRender, but they have > > > another > > > >>>> > order. > > > >>>> > > It > > > >>>> > > >> call setupRender and beginRender for first component, and > > then > > > - > > > >>>> for > > > >>>> > > >> second. But i need phase 1 calls for all components, then > > > phase 2 > > > >>>> call > > > >>>> > > for > > > >>>> > > >> all components. > > > >>>> > > >> > > > >>>> > > >> And now my question is: is there any way in Tapestry to > > create > > > >>>> this > > > >>>> > > >> phases? > > > >>>> > > >> Thank you for your attention, sorry for my English. > > > >>>> > > >> > > > >>>> > > > > > > >>>> > > > > > > >>>> > > > > > >>>> > > > > >>>> > > > >>>> > > > >>>> > > > >>>> -- > > > >>>> Dmitry Gusev > > > >>>> > > > >>>> AnjLab Team > > > >>>> http://anjlab.com > > > >>>> > > > >>>> > > > >>> > > > >>> > > > > > > > > -- > > > > Thiago H. de Paula Figueiredo > > > > Tapestry, Java and Hibernate consultant and developer > > > > http://machina.com.br > > > > > > > > --------------------------------------------------------------------- > > > > To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org > > > > For additional commands, e-mail: users-h...@tapestry.apache.org > > > > > > > > > > > > > >