ASOs are specified in terms of implementation classes, not interfaces. That makes it more awkward and error prone to create a proxy for them (you have to create a subclass and hit all the non-private methods and make them delegate, and there can be issues concerning constructors that get in the way).
I'd prefer to find a solution, if necessary, that wrapped around all the code paths that could be accessing a shared resource such as an ASO. One coarse lock, not many small (and potentially deadlocking) ones. On Wed, Jul 9, 2008 at 3:10 PM, Martijn Brinkers <[EMAIL PROTECTED]> wrote: > >> So it does seem to me that if you are using Ajax techniques and thus >> explicitly asynchronous access to the application, you should be >> mindful of this. We could bounce around some ideas as to how the >> framework could assist: perhaps a per-session/per-page lock? > > A per-session/per-page lock still allows concurrent access to ASO's I > guess? > I think that making any 'globally' accessible objects (ie Persisted > objects, ASO's...?) thread safe is the safest choice but I'm not sure if > that works for everyone. Would it be possible to automatically create a > thread safe wrapper (proxy) for a Persisted object (and ASO) that only > allows single threaded access to that object? Trigger the auto wrapper > when a specific annotation is added to the persisted object like > @ThreadSafe (or something like that). You can then choose to make the > object thread safe by yourself or let Tapestry make a thread safe > wrapper for you. > > Martijn > > On Wed, 2008-07-09 at 14:48 -0700, Howard Lewis Ship wrote: >> Does raise an interesting point. >> >> In a traditional page app, you would rarely have request overlap. It >> was possible (a wildly clicking user, perhaps). Often the main page >> would be one request, followed by a series of overlapping requests to >> retrieve static assets. >> >> It would be possible to add a filter to the page and component event >> request chains that would single-thread requests for any specific >> session. >> >> That would raise some additional problems; for example, an earlier >> user ran afoul of Tapestry's existing code (that single threads the >> system periodically, to check to see if any resources on the file >> system changed). They had a window where process of one request would >> "loop back" as a new request and thus two threads could end up >> deadlocked. >> >> So it does seem to me that if you are using Ajax techniques and thus >> explicitly asynchronous access to the application, you should be >> mindful of this. We could bounce around some ideas as to how the >> framework could assist: perhaps a per-session/per-page lock? >> >> On Wed, Jul 9, 2008 at 2:36 PM, Martijn Brinkers <[EMAIL PROTECTED]> wrote: >> > On one page I use a persistent Hashmap. The page contains an actionLink >> > with a click event handler. The onclick event is activated with a delay >> > using setTimeout. When the event is fired another actionLink is >> > activated. Now what happens is that during the handling of the first >> > actionLink the second actionLink is activated and this results in a >> > ConcurrentModificationException on the Hashmap. I can solve it by using >> > a multithread safe Hashmap but I want to understand under what >> > circumstances you need to be carefull for multi threaded activation >> > (with Tapestry 5 that is). Should a Persisted variable always be >> > multithread safe? I think so but what other Tapestry related items >> > should be multithread safe as well? >> > >> > Martijn >> > >> > Stack trace: >> > >> > java.util.ConcurrentModificationException >> > Stack trace >> > * java.util.HashMap >> > $HashIterator.nextEntry(HashMap.java:793) >> > * java.util.HashMap$KeyIterator.next(HashMap.java:828) >> > * >> > mitm.mimesecure.web.components.CertificateStoreGrid.downloadSelected(CertificateStoreGrid.java:76) >> > * >> > mitm.mimesecure.web.components.CertificateStoreGrid.dispatchComponentEvent(CertificateStoreGrid.java) >> > * >> > org.apache.tapestry5.internal.structure.ComponentPageElementImpl.dispatchEvent(ComponentPageElementImpl.java:864) >> > * >> > org.apache.tapestry5.internal.structure.ComponentPageElementImpl.triggerContextEvent(ComponentPageElementImpl.java:1025) >> > * >> > org.apache.tapestry5.internal.services.ComponentEventRequestHandlerImpl.handle(ComponentEventRequestHandlerImpl.java:67) >> > * >> > org.apache.tapestry5.internal.services.ImmediateActionRenderResponseFilter.handle(ImmediateActionRenderResponseFilter.java:42) >> > * >> > org.apache.tapestry5.internal.services.AjaxFilter.handle(AjaxFilter.java:42) >> > * org.apache.tapestry5.services.TapestryModule >> > $37.handle(TapestryModule.java:1987) >> > * >> > org.apache.tapestry5.internal.services.ComponentEventDispatcher.dispatch(ComponentEventDispatcher.java:135) >> > * org.apache.tapestry5.services.TapestryModule >> > $12.service(TapestryModule.java:938) >> > * >> > org.apache.tapestry5.internal.services.LocalizationFilter.service(LocalizationFilter.java:42) >> > * org.apache.tapestry5.services.TapestryModule >> > $2.service(TapestryModule.java:586) >> > * >> > org.apache.tapestry5.internal.services.RequestErrorFilter.service(RequestErrorFilter.java:26) >> > * >> > org.apache.tapestry5.internal.services.StaticFilesFilter.service(StaticFilesFilter.java:79) >> > * >> > org.apache.tapestry5.internal.services.CheckForUpdatesFilter$2.invoke(CheckForUpdatesFilter.java:93) >> > * >> > org.apache.tapestry5.internal.services.CheckForUpdatesFilter$2.invoke(CheckForUpdatesFilter.java:84) >> > * >> > org.apache.tapestry5.ioc.internal.util.ConcurrentBarrier.withRead(ConcurrentBarrier.java:75) >> > * >> > org.apache.tapestry5.internal.services.CheckForUpdatesFilter.service(CheckForUpdatesFilter.java:106) >> > * org.apache.tapestry5.services.TapestryModule >> > $11.service(TapestryModule.java:918) >> > * >> > org.apache.tapestry5.upload.internal.services.MultipartServletRequestFilter.service(MultipartServletRequestFilter.java:44) >> > * >> > org.apache.tapestry5.internal.services.IgnoredPathsFilter.service(IgnoredPathsFilter.java:62) >> > * >> > org.apache.tapestry5.TapestryFilter.doFilter(TapestryFilter.java:168) >> > * org.mortbay.jetty.servlet.ServletHandler >> > $CachedChain.doFilter(ServletHandler.java:1084) >> > * >> > org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360) >> > * >> > org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) >> > * >> > org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181) >> > * >> > org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726) >> > * >> > org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405) >> > * >> > org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) >> > * org.mortbay.jetty.Server.handle(Server.java:324) >> > * >> > org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505) >> > * org.mortbay.jetty.HttpConnection >> > $RequestHandler.headerComplete(HttpConnection.java:828) >> > * org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514) >> > * >> > org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211) >> > * >> > org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380) >> > * >> > org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395) >> > * org.mortbay.thread.BoundedThreadPool >> > $PoolThread.run(BoundedThreadPool.java:450) >> > >> > >> > --------------------------------------------------------------------- >> > To unsubscribe, e-mail: [EMAIL PROTECTED] >> > For additional commands, e-mail: [EMAIL PROTECTED] >> > >> > >> >> >> > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > -- Howard M. Lewis Ship Creator Apache Tapestry and Apache HiveMind --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]