cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Michael Gentry <mgen...@masslight.net>
Subject Re: How to link to user record who made changes in audit trail
Date Tue, 05 Aug 2014 13:14:25 GMT
Hi Tim,

I noticed a while back that the links on the Tapestry Security site were
broken, but fortunately the code is all on GitHub now, so you can browse it
easily:

https://github.com/tynamo/tapestry-security

mrg



On Mon, Aug 4, 2014 at 6:33 PM, D Tim Cummings <tim@triptera.com.au> wrote:

> Thanks Robert and Andrus for your help. I will definitely look at
> Dispatcher and tapestry-security. I had started to look at
> tapestry-security before but all the links to sample code were broken.
>
> And thanks to Michael explaining why my POST was generating 2 threads.
>
> Cheers
>
> Tim
>
>
> On 5 Aug 2014, at 0:09, Robert Zeigler <robert.zeigler@roxanemy.com>
> wrote:
>
> > 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 <andrus@objectstyle.org>
> 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 <tim@triptera.com.au>
> 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 <andrus@objectstyle.org>
> 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 <tim@triptera.com.au>
> 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 <andrus@objectstyle.org>
> 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 <tim@triptera.com.au>
> 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));
> >>>>>>> }
> >>>>>>>
> >>>>>>> }
> >>
>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message