2

I have found the technique in the answer below very useful for transparently managing the created and updated timestamp for entities:

hard time setting autogenerated time with hibernate JPA annotations

I am wondering if there is something similar for recording the create and update user for the entity?

@PreUpdate
@PrePersist
public void updateAudit() {
    lastModifiedDate = new Date();
    lastModifiedUser = ??;
    if (dateCreated==null) {
      dateCreated = new Date();
      userCreated = ??;
    }
}

While new Date() in the example provides the current time, I am having trouble finding a location in which the user id could be stored (at logon time) which is accessible from a @PrePersist annotated method on an entity.

Injecting a @LoggedInUser with a @Produces method would be ideal but my entities are created by new() rather than by injection so are not managed.

I'm pretty new to this so I hope I'm missing something obvious. Thanks.

[edit] Answer below from prunge led to code (abridged)

@MappedSuperclass
public abstract class BaseEntity implements Serializable, Comparable<BaseEntity> {

    @Version
    private Timestamp updatedTimestamp;

    private static ThreadLocal<Long> threadCurrentUserId = new ThreadLocal<Long>();

    /* Called from entry point like servlet 
    */
    public static void setLoggedInUser(BaseEntity user) {
        if (user!=null) threadCurrentUserId.set(user.getId());
    }

    @PrePersist
    @PreUpdate
    protected void onCreateOrUpdate() {
         //Note we don't have to update updatedTimestamp    since the @Version annotation does it for us
         if(createdTimestamp==null) createdTimestamp = new Timestamp(new Date().getTime());;

         lastUpdatedByUserId = threadCurrentUserId.get();
         if(createdByUserId==null)  createdByUserId = lastUpdatedByUserId;
    }
Community
  • 1
  • 1
Jonathan
  • 403
  • 3
  • 13
  • What user name are you looking to capture? Is this a: web app? fat client? What, if any, security framework are you using? – MarkOfHall Oct 20 '11 at 02:48

2 Answers2

1

If it's a webapp, you could use a ThreadLocal for storing the current user.

  • Set the ThreadLocal value in a servlet filter, reading the user from servlet request.
  • Read the ThreadLocal value from your JPA entities.
  • Clear the value on the trip back through the filter.
prunge
  • 22,460
  • 3
  • 73
  • 80
0

You can manually inject CDI dependencies using a custom CDI Injector, I think something along the lines of:

@Inject
private BeanManager beanManager;    

...

Entity entity = new Entity();

AnnotatedType<?> type = beanManager.createAnnotatedType(class);

InjectionTarget target = beanManager.createInjectionTarget(type);
CreationalContext context = beanManager.createCreationalContext(null);

target.inject(entity, context);

Note that the entity will not become a CDI managed bean but will get all its dependencies injected (and these will be managed by cdi).

Having said that, there is probably a better method to do it depending on the web/security frameworks you're using.

brcosta
  • 459
  • 4
  • 6