MakeJCacheCDIInterceptorFriendly.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *   http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing,
  13.  * software distributed under the License is distributed on an
  14.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15.  * KIND, either express or implied.  See the License for the
  16.  * specific language governing permissions and limitations
  17.  * under the License.
  18.  */
  19. package org.apache.commons.jcs3.jcache.cdi;

  20. import java.lang.annotation.Annotation;
  21. import java.lang.reflect.Type;
  22. import java.util.Collections;
  23. import java.util.HashSet;
  24. import java.util.Set;
  25. import java.util.concurrent.atomic.AtomicInteger;
  26. import javax.cache.annotation.CachePut;
  27. import javax.cache.annotation.CacheRemove;
  28. import javax.cache.annotation.CacheRemoveAll;
  29. import javax.cache.annotation.CacheResult;
  30. import javax.enterprise.context.ApplicationScoped;
  31. import javax.enterprise.context.spi.CreationalContext;
  32. import javax.enterprise.event.Observes;
  33. import javax.enterprise.inject.Any;
  34. import javax.enterprise.inject.Default;
  35. import javax.enterprise.inject.spi.AfterBeanDiscovery;
  36. import javax.enterprise.inject.spi.AnnotatedType;
  37. import javax.enterprise.inject.spi.Bean;
  38. import javax.enterprise.inject.spi.BeanManager;
  39. import javax.enterprise.inject.spi.BeforeBeanDiscovery;
  40. import javax.enterprise.inject.spi.Extension;
  41. import javax.enterprise.inject.spi.InjectionPoint;
  42. import javax.enterprise.inject.spi.InjectionTarget;
  43. import javax.enterprise.inject.spi.PassivationCapable;
  44. import javax.enterprise.inject.spi.ProcessAnnotatedType;
  45. import javax.enterprise.util.AnnotationLiteral;

  46. import static java.util.Arrays.asList;

  47. // TODO: observe annotated type (or maybe sthg else) to cache data and inject this extension (used as metadata cache)
  48. // to get class model and this way allow to add cache annotation on the fly - == avoid java pure reflection to get metadata
  49. public class MakeJCacheCDIInterceptorFriendly implements Extension
  50. {
  51.     private static final AtomicInteger id = new AtomicInteger();
  52.     private static final boolean USE_ID = !Boolean.getBoolean("org.apache.commons.jcs3.cdi.skip-id");

  53.     private boolean needHelper = true;

  54.     protected void discoverInterceptorBindings(final @Observes BeforeBeanDiscovery beforeBeanDiscoveryEvent,
  55.                                                final BeanManager bm)
  56.     {
  57.         // CDI 1.1 will just pick createAnnotatedType(X) as beans so we'll skip our HelperBean
  58.         // but CDI 1.0 needs our HelperBean + interceptors in beans.xml like:
  59.         /*
  60.         <beans xmlns="http://java.sun.com/xml/ns/javaee"
  61.                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  62.                xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  63.               http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
  64.           <interceptors>
  65.             <class>org.apache.commons.jcs3.jcache.cdi.CacheResultInterceptor</class>
  66.             <class>org.apache.commons.jcs3.jcache.cdi.CacheRemoveAllInterceptor</class>
  67.             <class>org.apache.commons.jcs3.jcache.cdi.CacheRemoveInterceptor</class>
  68.             <class>org.apache.commons.jcs3.jcache.cdi.CachePutInterceptor</class>
  69.           </interceptors>
  70.         </beans>
  71.          */
  72.         bm.createAnnotatedType(CDIJCacheHelper.class);
  73.         for (final Class<?> interceptor : asList(
  74.                 CachePutInterceptor.class, CacheRemoveInterceptor.class,
  75.                 CacheRemoveAllInterceptor.class, CacheResultInterceptor.class)) {
  76.             beforeBeanDiscoveryEvent.addAnnotatedType(bm.createAnnotatedType(interceptor));
  77.         }
  78.         for (final Class<? extends Annotation> interceptor : asList(
  79.                 CachePut.class, CacheRemove.class,
  80.                 CacheRemoveAll.class, CacheResult.class)) {
  81.             beforeBeanDiscoveryEvent.addInterceptorBinding(interceptor);
  82.         }
  83.     }

  84.     protected void addHelper(final @Observes AfterBeanDiscovery afterBeanDiscovery,
  85.                              final BeanManager bm)
  86.     {
  87.         if (!needHelper) {
  88.             return;
  89.         }
  90.         /* CDI >= 1.1 only. Actually we shouldn't go here with CDI 1.1 since we defined the annotated type for the helper
  91.         final AnnotatedType<CDIJCacheHelper> annotatedType = bm.createAnnotatedType(CDIJCacheHelper.class);
  92.         final BeanAttributes<CDIJCacheHelper> beanAttributes = bm.createBeanAttributes(annotatedType);
  93.         final InjectionTarget<CDIJCacheHelper> injectionTarget = bm.createInjectionTarget(annotatedType);
  94.         final Bean<CDIJCacheHelper> bean = bm.createBean(beanAttributes, CDIJCacheHelper.class, new InjectionTargetFactory<CDIJCacheHelper>() {
  95.             @Override
  96.             public InjectionTarget<CDIJCacheHelper> createInjectionTarget(Bean<CDIJCacheHelper> bean) {
  97.                 return injectionTarget;
  98.             }
  99.         });
  100.         */
  101.         final AnnotatedType<CDIJCacheHelper> annotatedType = bm.createAnnotatedType(CDIJCacheHelper.class);
  102.         final InjectionTarget<CDIJCacheHelper> injectionTarget = bm.createInjectionTarget(annotatedType);
  103.         final HelperBean bean = new HelperBean(annotatedType, injectionTarget, findIdSuffix());
  104.         afterBeanDiscovery.addBean(bean);
  105.     }

  106.     protected void vetoScannedCDIJCacheHelperQualifiers(final @Observes ProcessAnnotatedType<CDIJCacheHelper> pat) {
  107.         if (!needHelper) { // already seen, shouldn't really happen,just a protection
  108.             pat.veto();
  109.         }
  110.         needHelper = false;
  111.     }

  112.     // TODO: make it better for ear+cluster case with CDI 1.0
  113.     private static String findIdSuffix() {
  114.         // big disadvantage is all deployments of a cluster needs to be in the exact same order but it works with ears
  115.         if (USE_ID) {
  116.             return "lib" + id.incrementAndGet();
  117.         }
  118.         return "default";
  119.     }

  120.     public static class HelperBean implements Bean<CDIJCacheHelper>, PassivationCapable {
  121.         private final AnnotatedType<CDIJCacheHelper> at;
  122.         private final InjectionTarget<CDIJCacheHelper> it;
  123.         private final HashSet<Annotation> qualifiers;
  124.         private final String id;

  125.         public HelperBean(final AnnotatedType<CDIJCacheHelper> annotatedType,
  126.                           final InjectionTarget<CDIJCacheHelper> injectionTarget,
  127.                           final String id) {
  128.             this.at = annotatedType;
  129.             this.it = injectionTarget;
  130.             this.id =  "JCS#CDIHelper#" + id;

  131.             this.qualifiers = new HashSet<>();
  132.             this.qualifiers.add(new AnnotationLiteral<Default>() {

  133.                 /**
  134.                  *
  135.                  */
  136.                 private static final long serialVersionUID = 3314657767813459983L;});
  137.             this.qualifiers.add(new AnnotationLiteral<Any>() {

  138.                 /**
  139.                  *
  140.                  */
  141.                 private static final long serialVersionUID = 7419841275942488170L;});
  142.         }

  143.         @Override
  144.         public Set<InjectionPoint> getInjectionPoints() {
  145.             return it.getInjectionPoints();
  146.         }

  147.         @Override
  148.         public Class<?> getBeanClass() {
  149.             return at.getJavaClass();
  150.         }

  151.         @Override
  152.         public boolean isNullable() {
  153.             return false;
  154.         }

  155.         @Override
  156.         public Set<Type> getTypes() {
  157.             return at.getTypeClosure();
  158.         }

  159.         @Override
  160.         public Set<Annotation> getQualifiers() {
  161.             return qualifiers;
  162.         }

  163.         @Override
  164.         public Class<? extends Annotation> getScope() {
  165.             return ApplicationScoped.class;
  166.         }

  167.         @Override
  168.         public String getName() {
  169.             return null;
  170.         }

  171.         @Override
  172.         public Set<Class<? extends Annotation>> getStereotypes() {
  173.             return Collections.emptySet();
  174.         }

  175.         @Override
  176.         public boolean isAlternative() {
  177.             return false;
  178.         }

  179.         @Override
  180.         public CDIJCacheHelper create(final CreationalContext<CDIJCacheHelper> context) {
  181.             final CDIJCacheHelper produce = it.produce(context);
  182.             it.inject(produce, context);
  183.             it.postConstruct(produce);
  184.             return produce;
  185.         }

  186.         @Override
  187.         public void destroy(final CDIJCacheHelper instance, final CreationalContext<CDIJCacheHelper> context) {
  188.             it.preDestroy(instance);
  189.             it.dispose(instance);
  190.             context.release();
  191.         }

  192.         @Override
  193.         public String getId() {
  194.             return id;
  195.         }
  196.     }
  197. }