2011-11-21 62 views
0

我試圖截取Seam 3項目中的方法persistupdatejavax.persistence.EntityManager如何用Seam 3攔截EntityManager的方法?

在我試圖創建的微型框架的前一版本(Seam 2)中,我使用org.hibernate.Interceptor的實現並在persistence.xml中聲明瞭它。

但我想更多的東西「CDI樣」現在我們正處在一個JEE6環境。

我想要在進入EntityManager.persist呼叫之前引發事件@BeforeTrackablePersist。用同樣的方法,我想事件@BeforeTrackableUpdate進入一個EntityManager.merge調用之前拋出。 Trackable是我的一些Entity可以實現的接口,以在持久或合併之前被攔截。

我使用Seam 3(3.1.0.Beta3)擴展持久性管理:

public class EntityManagerHandler { 
    @SuppressWarnings("unused") 
    @ExtensionManaged 
    @Produces 
    @PersistenceUnit 
    private EntityManagerFactory entityManagerFactory; 
} 

所以我做了一個javax.enterprise.inject.spi.Extension,並tryied很多方法可以做到這一點:

public class TrackableExtension implements Extension { 

    @Inject @BeforeTrackablePersisted 
    private Event<Trackable> beforeTrackablePersistedEvent; 

    @Inject @BeforeTrackableMerged 
    private Event<Trackable> beforeTrackableMergedEvent; 

    @SuppressWarnings("unchecked") 
    public void processEntityManagerTarget(@Observes final ProcessInjectionTarget<EntityManager> event) { 
     final InjectionTarget<EntityManager> injectionTarget = event.getInjectionTarget(); 
     final InjectionTarget<EntityManager> injectionTargetProxy = (InjectionTarget<EntityManager>) Proxy.newProxyInstance(event.getClass().getClassLoader(), new Class[] {InjectionTarget.class}, new InvocationHandler() { 
      @Override 
      public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 
       if ("produce".equals(method.getName())) { 
        final CreationalContext<EntityManager> ctx = (CreationalContext<EntityManager>) args[0]; 
        final EntityManager entityManager = decorateEntityManager(injectionTarget, ctx); 
        return entityManager; 
       } else { 
        return method.invoke(injectionTarget, args); 
       } 
      } 
     }); 
     event.setInjectionTarget(injectionTargetProxy); 
    } 

    public void processEntityManagerType(@Observes final ProcessAnnotatedType<EntityManager> event) { 
     final AnnotatedType<EntityManager> type = event.getAnnotatedType(); 
     final AnnotatedTypeBuilder<EntityManager> builder = new AnnotatedTypeBuilder<EntityManager>().readFromType(type); 

     for (final AnnotatedMethod<? super EntityManager> method : type.getMethods()) { 
      final String name = method.getJavaMember().getName(); 
      if (StringUtils.equals(name, "persist") || StringUtils.equals(name, "merge")) { 
       builder.addToMethod(method, TrackableInterceptorBindingLiteral.INSTANCE); 
      } 
     } 

     event.setAnnotatedType(builder.create()); 
    } 

    public void processEntityManagerBean(@Observes final ProcessBean<EntityManager> event) { 
     final AnnotatedType<EntityManager> annotatedType = (AnnotatedType<EntityManager>)event.getAnnotated(); 
//  not even called 
    } 

    public void processEntityManager(@Observes final ProcessProducer<?, EntityManager> processProducer) { 
     processProducer.setProducer(decorate(processProducer.getProducer())); 
    } 

    private Producer<EntityManager> decorate(final Producer<EntityManager> producer) { 
     return new Producer<EntityManager>() { 
      @Override 
      public EntityManager produce(final CreationalContext<EntityManager> ctx) { 
       return decorateEntityManager(producer, ctx); 
      } 
      @Override 
      public Set<InjectionPoint> getInjectionPoints() { 
       return producer.getInjectionPoints(); 
      } 
      @Override 
      public void dispose(final EntityManager instance) { 
       producer.dispose(instance); 
      } 
     }; 
    } 

    private EntityManager decorateEntityManager(final Producer<EntityManager> producer, final CreationalContext<EntityManager> ctx) { 
     final EntityManager entityManager = producer.produce(ctx); 
     return (EntityManager) Proxy.newProxyInstance(entityManager.getClass().getClassLoader(), new Class[] {EntityManager.class}, new InvocationHandler() { 
      @Override 
      public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 
       final String methodName = method.getName(); 
       if (StringUtils.equals(methodName, "persist")) { 
        fireEventIfTrackable(beforeTrackablePersistedEvent, args[0]); 
       } else if (StringUtils.equals(methodName, "merge")) { 
        fireEventIfTrackable(beforeTrackableMergedEvent, args[0]); 
       } 
       return method.invoke(entityManager, args); 
      } 

      private void fireEventIfTrackable(final Event<Trackable> event, final Object entity) { 
       if (entity instanceof Trackable) { 
        event.fire(Reflections.<Trackable>cast(entity)); 
       } 
      } 
     }); 
    } 
} 

在所有這些觀察者方法中,僅調用第二個(processEntityManagerType(@Observes ProcessAnnotatedType<EntityManager>))!即使與結合除了方法persistmerge,我的攔截器不會被調用(我當然在beans.xml正確的線啓用,並啓用我的分機與services/javax.enterprise.inject.spi.Extension文件)。

東西我想簡單的用CDI似乎終於要被實際真的很難......或許接縫3做一些東西,阻止這種代碼正確執行...

沒有人知道如何處理?

+0

我在Seam Persistence模塊中打開了一個功能請求:https://issues.jboss.org/browse/SEAMPERSIST-75 –

回答

0

至於最後我對煤層持久性的小補丁SEAMPERSIST-75應用,將有可能在理論上做到這一點通過擴展org.jboss.seam.persistence.HibernatePersistenceProvider和覆蓋的方法proxyEntityManager(EntityManager)

1

我認爲你正在做這方面比它需要的是一個有點困難。首先,JPA和CDI集成在Java EE 6中並不是很好,但我們非常希望Java EE 7和JPA 2.1的變化。

你想要做的是爲EntityManager創建你自己的生產者,它將委託給一個EntityManager的實際實例,但是當你調用你感興趣的方法時也會觸發你自己的事件。在Seam持久性源代碼中看到可以完成的一種方式。

+0

實際上,通過查看'org.jboss.seam.persistence.ManagedPersistenceContextExtension'我有點害怕。它構建了一個'EntityManager'用'ManagedPersistenceContextBeanLifecycle'其處理大約'EntityManager'(交易,擴展持久化上下文......)這麼多的事情,我覺得我自己的製片它將使用注射'EntityManagerFactory'不會有同樣的行爲和特點與Seam持久性擴展創建的'EntityManager' ... –

+0

呀,這不是一件容易的事很遺憾。 – LightGuard