Dispatcher is a great place for security code, as long as you don't have 
application components that live outside tapestry which also need the security 
constraints. 

You might consider looking into the tapestry-security module from the tynamo 
project, which integrates shiro.  A little time reading the docs will likely 
save you a lot if coding time. 

Robert

GATAATGCTATTTCTTTAATTTTCGAA

> On Aug 4, 2014, at 9:02 AM, Andrus Adamchik <[email protected]> wrote:
> 
> Yeah, I guess you’ll need to debug your ’setupRender’. 
> 
> I usually implement any security-related code in a servlet Filter that wraps 
> around Tapestry filter (and intercepts all pages). This creates some 
> inconvenience, as I can’t use injection outside Tapestry, but otherwise I can 
> be 100% sure that security code is always executed. 
> 
> Perhaps you can do something similar using a custom T5 dispatcher: 
> http://wiki.apache.org/tapestry/Tapestry5HowToCreateADispatcher
> 
> Andrus
> 
>> On Aug 4, 2014, at 4:23 PM, D Tim Cummings <[email protected]> wrote:
>> 
>> Thanks Andrus. I guess this is becoming a Tapestry question now. I tried 
>> calling setTheUserId in setupRender() and clearing it in cleanupRender() but 
>> AuditListener is running in a different thread to these two methods.
>> 
>> The following is logging from a single click of the "save" button when a new 
>> record is being created. There are 2 threads being used and 
>> AuditListener.doPrePersist is called in a different thread and prior to 
>> setupRender().
>> 
>> 2014-08-04 23:19:27,376 INFO  
>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] doPrePersist() Thread 
>> qtp1880825967-22 au.com.tramanco.chekway.cayenne.TblPerson
>> 2014-08-04 23:19:27,376 INFO  
>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] getTheUser() Thread 
>> qtp1880825967-22 idUser == null 
>> 2014-08-04 23:19:27,376 INFO  
>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] doPrePersist() Thread 
>> qtp1880825967-22 au.com.tramanco.chekway.cayenne.TblPerson
>> 2014-08-04 23:19:27,376 INFO  
>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] getTheUser() Thread 
>> qtp1880825967-22 idUser == null 
>> 2014-08-04 23:19:27,414 INFO  [au.com.tramanco.chekway.base.TmcssComponent] 
>> setupRender() qtp1880825967-21
>> 2014-08-04 23:19:27,414 INFO  
>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 21 
>> qtp1880825967-21 setTheUserId 200
>> 2014-08-04 23:19:27,448 INFO  [au.com.tramanco.chekway.base.TmcssComponent] 
>> cleanupRender() qtp1880825967-21
>> 2014-08-04 23:19:27,448 INFO  
>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 21 
>> qtp1880825967-21 setTheUserId null
>> 
>> Tim
>> 
>> On 4 Aug 2014, at 16:04, Andrus Adamchik <[email protected]> wrote:
>> 
>>>> Maybe the request is running in a different thread each time.
>>> 
>>> Of course. Jetty has a thread pool and each requests gets an available 
>>> thread from the pool semi-randomly. Note that qtp1248572294-23 and 
>>> qtp1248572294-19 are also Jetty threads, so they are called within a 
>>> request. So make sure you call ‘setTheUserId’ in every single request (and 
>>> reset it to null at the end of that request).
>>> 
>>> Andrus
>>> 
>>>> On Aug 2, 2014, at 2:48 AM, D Tim Cummings <[email protected]> wrote:
>>>> 
>>>> Hi Andrus
>>>> 
>>>> Thanks for your help. Here are logs with thread names as well. I logged in 
>>>> in Thread 24 and created 5 new records. AuditListener is running in 
>>>> different threads. I am running this in Eclipse 4.3.2 with the RunJettyRun 
>>>> plugin running Jetty 8.1.2. Log statement is 
>>>> 
>>>> logger.info("Thread " + t.getId() + " " + t.getName() + " Looking for 
>>>> TblPerson " + idUser); 
>>>> //where t = Thread.currentThread()
>>>> 
>>>> 2014-08-02 09:37:30,563 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 setTheUserId 220
>>>> 2014-08-02 09:38:14,064 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 2014-08-02 09:38:14,064 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 2014-08-02 09:38:14,064 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 2014-08-02 09:38:14,065 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 2014-08-02 09:38:31,045 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:38:31,045 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:38:31,045 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:38:31,046 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:38:57,932 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 19 
>>>> qtp1248572294-19 idUser == null 
>>>> 2014-08-02 09:38:57,932 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 19 
>>>> qtp1248572294-19 idUser == null 
>>>> 2014-08-02 09:38:57,932 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 19 
>>>> qtp1248572294-19 idUser == null 
>>>> 2014-08-02 09:38:57,933 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 19 
>>>> qtp1248572294-19 idUser == null 
>>>> 2014-08-02 09:39:16,048 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:39:16,048 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:39:16,048 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:39:16,048 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 23 
>>>> qtp1248572294-23 idUser == null 
>>>> 2014-08-02 09:39:41,670 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 2014-08-02 09:39:41,670 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 2014-08-02 09:39:41,670 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 2014-08-02 09:39:41,670 INFO  
>>>> [au.com.tramanco.chekway.cayenne.audit.AuditListener] Thread 24 
>>>> qtp1248572294-24 Looking for TblPerson 220
>>>> 
>>>> Maybe the request is running in a different thread each time. I will do 
>>>> some more checking.
>>>> 
>>>> Tim
>>>> 
>>>> 
>>>>> On 1 Aug 2014, at 23:22, Andrus Adamchik <[email protected]> wrote:
>>>>> 
>>>>> Hi Tim,
>>>>> 
>>>>> Yes you are going in the right direction with AuditableProcessor. 
>>>>> 
>>>>>> If I save the user in a ThreadLocal in the data channel filter object, I 
>>>>>> get a different user each time (often blank) because the data channel 
>>>>>> filter seem to run in its own thread which changes each time.
>>>>> 
>>>>> This seems suspect. In a typical web app, all processing happens in 
>>>>> request thread. Cayenne listeners are processed in the same thread as 
>>>>> ObjectContext commit, which is normally your request thread. Could you 
>>>>> possibly print thread names from within setTheUserId and doPrePersist 
>>>>> methods ? Maybe that will give you a hint. Request threads in Tomcat and 
>>>>> Jetty have easily identifiable names.
>>>>> 
>>>>> Andrus
>>>>> 
>>>>> 
>>>>>> On Jul 20, 2014, at 2:23 AM, D Tim Cummings <[email protected]> wrote:
>>>>>> 
>>>>>> Hi all
>>>>>> 
>>>>>> I want to set up a simple audit trail which basically links who was the 
>>>>>> person to create a record to that record. I am using Cayenne 3.2M1 and 
>>>>>> Tapestry 5.3.7. I figure I need to set up a data channel filter to catch 
>>>>>> changes to that record and then save a link to the user who made the 
>>>>>> change. 
>>>>>> 
>>>>>> The problem is, if I save the user in the data channel filter object 
>>>>>> when someone logs in, then all created records link to the last logged 
>>>>>> in user. 
>>>>>> 
>>>>>> If I save the user in a ThreadLocal in the data channel filter object, I 
>>>>>> get a different user each time (often blank) because the data channel 
>>>>>> filter seem to run in its own thread which changes each time.
>>>>>> 
>>>>>> I have been watching the excellent and now freely available podcast by 
>>>>>> Andrus Adamchik presented to WebObjects developers "Advanced Apache 
>>>>>> Cayenne" where he talks about lifecycle events, (callbacks, listeners), 
>>>>>> caching, data channel filters, clustering, in cayenne 3.2M1.
>>>>>> https://itunes.apple.com/podcast/webobjects-podcasts/id270165303?mt=2#
>>>>>> In Andrus's sample code he uses AuditableProcessor, but I couldn't think 
>>>>>> how to use it to solve this problem.
>>>>>> 
>>>>>> Here is a copy of my listener/data channel filter with the ThreadLocal 
>>>>>> code.
>>>>>> 
>>>>>> Thanks 
>>>>>> 
>>>>>> Tim
>>>>>> 
>>>>>> 
>>>>>> public class AuditListener implements DataChannelFilter {
>>>>>> 
>>>>>> private static final Logger logger = 
>>>>>> LoggerFactory.getLogger(AuditListener.class);
>>>>>> 
>>>>>> private ThreadLocal<Integer> tlUserId;
>>>>>> 
>>>>>> @PrePersist(entityAnnotations=TagCreateCancel.class)
>>>>>> void doPrePersist(DataObject object) {
>>>>>> if ( object instanceof AuditableCreateCancel ) {
>>>>>>   AuditableCreateCancel acc = (AuditableCreateCancel) object;
>>>>>>   TblPerson user = getTheUser(object.getObjectContext());
>>>>>>   acc.setTblPersonCreate(user);
>>>>>> }
>>>>>> }
>>>>>> 
>>>>>> private TblPerson getTheUser(ObjectContext oc) {
>>>>>> Thread t = Thread.currentThread();
>>>>>> Integer idUser = tlUserId.get();
>>>>>> if ( idUser == null ) {
>>>>>>   logger.info("Thread " + t.getId() + " idUser == null ");
>>>>>>   return null;
>>>>>> }
>>>>>> logger.info("Thread " + t.getId() + " Looking for TblPerson " + idUser);
>>>>>> TblPerson p = Cayenne.objectForPK(oc, TblPerson.class, 
>>>>>> idUser.intValue());
>>>>>> return p;
>>>>>> }
>>>>>> 
>>>>>> @Override
>>>>>> public void init(DataChannel channel) {
>>>>>> tlUserId = new ThreadLocal<Integer>();
>>>>>> }
>>>>>> 
>>>>>> @Override
>>>>>> public QueryResponse onQuery(ObjectContext originatingContext, Query 
>>>>>> query, DataChannelFilterChain filterChain) {
>>>>>> return filterChain.onQuery(originatingContext, query);
>>>>>> }
>>>>>> 
>>>>>> @Override
>>>>>> public GraphDiff onSync(ObjectContext originatingContext, GraphDiff 
>>>>>> changes, int syncType, DataChannelFilterChain filterChain) {
>>>>>> try {
>>>>>>   return filterChain.onSync(originatingContext, changes, syncType);
>>>>>> } finally {
>>>>>>   //
>>>>>> }
>>>>>> }
>>>>>> 
>>>>>> public void setTheUserId(int idUser) {
>>>>>> Thread t = Thread.currentThread();
>>>>>> logger.info("Thread " + t.getId() + " setTheUserId " + idUser);
>>>>>> tlUserId.set(Integer.valueOf(idUser));
>>>>>> }
>>>>>> 
>>>>>> }
> 

Reply via email to