001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * Granite Data Services is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * Granite Data Services is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 015 * General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 020 * USA, or see <http://www.gnu.org/licenses/>. 021 */ 022package org.granite.tide.cdi; 023 024import java.io.Serializable; 025import java.lang.annotation.Annotation; 026import java.lang.reflect.ParameterizedType; 027import java.lang.reflect.Type; 028import java.util.HashMap; 029import java.util.HashSet; 030import java.util.Map; 031import java.util.Set; 032 033import javax.enterprise.context.RequestScoped; 034import javax.enterprise.event.Observes; 035import javax.enterprise.inject.spi.AfterBeanDiscovery; 036import javax.enterprise.inject.spi.AfterDeploymentValidation; 037import javax.enterprise.inject.spi.AnnotatedConstructor; 038import javax.enterprise.inject.spi.AnnotatedField; 039import javax.enterprise.inject.spi.AnnotatedMethod; 040import javax.enterprise.inject.spi.AnnotatedType; 041import javax.enterprise.inject.spi.Bean; 042import javax.enterprise.inject.spi.BeanManager; 043import javax.enterprise.inject.spi.Extension; 044import javax.enterprise.inject.spi.ProcessAnnotatedType; 045import javax.enterprise.inject.spi.ProcessBean; 046import javax.enterprise.inject.spi.ProcessProducerField; 047import javax.enterprise.inject.spi.ProcessProducerMethod; 048import javax.enterprise.util.AnnotationLiteral; 049import javax.inject.Inject; 050import javax.inject.Named; 051 052import org.granite.logging.Logger; 053import org.granite.messaging.amf.io.util.externalizer.annotation.ExternalizedBean; 054import org.granite.messaging.service.annotations.RemoteDestination; 055import org.granite.tide.annotations.TideEnabled; 056 057 058/** 059 * @author William DRAI 060 */ 061public class TideExtension implements Extension { 062 063 private static final Logger log = Logger.getLogger(TideExtension.class); 064 065 066 @Inject 067 BeanManager manager; 068 069 private Bean<?> tideInstrumentedBeans = null; 070 private Map<Type, Bean<?>> instrumentedBeans = new HashMap<Type, Bean<?>>(); 071 private Map<Object, Type> producedBeans = new HashMap<Object, Type>(); 072 073 074 public <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> event) { 075 AnnotatedType<X> annotatedType = event.getAnnotatedType(); 076 077 boolean tideComponent = false; 078 boolean tideBean = false; 079 for (Type type : annotatedType.getTypeClosure()) { 080 if (type instanceof ParameterizedType) 081 type = ((ParameterizedType)type).getRawType(); 082 if (type instanceof Class<?> 083 && (((Class<?>)type).isAnnotationPresent(RemoteDestination.class) 084 || ((Class<?>)type).isAnnotationPresent(TideEnabled.class) 085 || ((Class<?>)type).isAnnotationPresent(Named.class) 086 || ((Class<?>)type).isAnnotationPresent(RequestScoped.class))) { 087 tideComponent = true; 088 break; 089 } 090 if (type instanceof Class<?> 091 && ((Serializable.class.isAssignableFrom((Class<?>)type) && ((Class<?>)type).isAnnotationPresent(Named.class)) 092 || ((Class<?>)type).isAnnotationPresent(ExternalizedBean.class))) { 093 tideBean = true; 094 break; 095 } 096 } 097 098 if (tideComponent || tideBean) 099 event.setAnnotatedType(new TideAnnotatedType<X>(annotatedType, tideComponent, tideBean)); 100 } 101 102 public <X> void processBean(@Observes ProcessBean<X> event) { 103 if (event.getAnnotated().isAnnotationPresent(TideComponent.class) || event.getAnnotated().isAnnotationPresent(TideBean.class)) { 104 instrumentedBeans.put(event.getAnnotated().getBaseType(), event.getBean()); 105 log.info("Instrumented Tide component %s", event.getBean().toString()); 106 } 107 108 Bean<?> bean = event.getBean(); 109 if (event instanceof ProcessProducerMethod<?, ?>) { 110 Type type = ((ProcessProducerMethod<?, ?>)event).getAnnotatedProducerMethod().getDeclaringType().getBaseType(); 111 producedBeans.put(((ProcessProducerMethod<?, ?>)event).getAnnotatedProducerMethod().getBaseType(), type); 112 if (bean.getName() != null) 113 producedBeans.put(bean.getName(), type); 114 } 115 else if (event instanceof ProcessProducerField<?, ?>) { 116 Type type = ((ProcessProducerField<?, ?>)event).getAnnotatedProducerField().getDeclaringType().getBaseType(); 117 producedBeans.put(((ProcessProducerField<?, ?>)event).getAnnotatedProducerField().getBaseType(), type); 118 if (bean.getName() != null) 119 producedBeans.put(bean.getName(), type); 120 } 121 122 if (event.getBean().getBeanClass().equals(TideInstrumentedBeans.class)) 123 tideInstrumentedBeans = event.getBean(); 124 } 125 126 public void processAfterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager manager) { 127 } 128 129 public void processAfterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager manager) { 130 if (tideInstrumentedBeans == null) 131 return; 132 TideInstrumentedBeans ib = (TideInstrumentedBeans)manager.getReference(tideInstrumentedBeans, TideInstrumentedBeans.class, 133 manager.createCreationalContext(tideInstrumentedBeans)); 134 ib.setBeans(instrumentedBeans); 135 ib.setProducedBeans(producedBeans); 136 } 137 138 139 140 @SuppressWarnings("serial") 141 public static class TideAnnotatedType<T> implements AnnotatedType<T> { 142 143 private final AnnotatedType<T> annotatedType; 144 private final Annotation componentQualifier = new AnnotationLiteral<TideComponent>() {}; 145 private final Annotation beanQualifier = new AnnotationLiteral<TideBean>() {}; 146 private final Set<Annotation> annotations; 147 148 149 public TideAnnotatedType(AnnotatedType<T> annotatedType, boolean component, boolean bean) { 150 this.annotatedType = annotatedType; 151 annotations = new HashSet<Annotation>(annotatedType.getAnnotations()); 152 if (component) 153 annotations.add(componentQualifier); 154 if (bean) 155 annotations.add(beanQualifier); 156 } 157 158 public Set<AnnotatedConstructor<T>> getConstructors() { 159 return annotatedType.getConstructors(); 160 } 161 162 public Set<AnnotatedField<? super T>> getFields() { 163 return annotatedType.getFields(); 164 } 165 166 public Class<T> getJavaClass() { 167 return annotatedType.getJavaClass(); 168 } 169 170 public Set<AnnotatedMethod<? super T>> getMethods() { 171 return annotatedType.getMethods(); 172 } 173 174 @SuppressWarnings("unchecked") 175 public <X extends Annotation> X getAnnotation(Class<X> annotationClass) { 176 if (annotationClass.equals(TideComponent.class)) 177 return (X)componentQualifier; 178 if (annotationClass.equals(TideBean.class)) 179 return (X)beanQualifier; 180 return annotatedType.getAnnotation(annotationClass); 181 } 182 183 public Set<Annotation> getAnnotations() { 184 return annotations; 185 } 186 187 public Type getBaseType() { 188 return annotatedType.getBaseType(); 189 } 190 191 public Set<Type> getTypeClosure() { 192 return annotatedType.getTypeClosure(); 193 } 194 195 public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { 196 if (annotationClass.equals(TideComponent.class) && annotations.contains(componentQualifier)) 197 return true; 198 if (annotationClass.equals(TideBean.class) && annotations.contains(beanQualifier)) 199 return true; 200 return annotatedType.isAnnotationPresent(annotationClass); 201 } 202 } 203}