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