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     */
022    package org.granite.tide.cdi;
023    
024    import java.io.Serializable;
025    import java.lang.annotation.Annotation;
026    import java.lang.reflect.ParameterizedType;
027    import java.lang.reflect.Type;
028    import java.util.HashMap;
029    import java.util.HashSet;
030    import java.util.Map;
031    import java.util.Set;
032    
033    import javax.enterprise.context.RequestScoped;
034    import javax.enterprise.event.Observes;
035    import javax.enterprise.inject.spi.AfterBeanDiscovery;
036    import javax.enterprise.inject.spi.AfterDeploymentValidation;
037    import javax.enterprise.inject.spi.AnnotatedConstructor;
038    import javax.enterprise.inject.spi.AnnotatedField;
039    import javax.enterprise.inject.spi.AnnotatedMethod;
040    import javax.enterprise.inject.spi.AnnotatedType;
041    import javax.enterprise.inject.spi.Bean;
042    import javax.enterprise.inject.spi.BeanManager;
043    import javax.enterprise.inject.spi.Extension;
044    import javax.enterprise.inject.spi.ProcessAnnotatedType;
045    import javax.enterprise.inject.spi.ProcessBean;
046    import javax.enterprise.inject.spi.ProcessProducerField;
047    import javax.enterprise.inject.spi.ProcessProducerMethod;
048    import javax.enterprise.util.AnnotationLiteral;
049    import javax.inject.Inject;
050    import javax.inject.Named;
051    
052    import org.granite.logging.Logger;
053    import org.granite.messaging.amf.io.util.externalizer.annotation.ExternalizedBean;
054    import org.granite.messaging.service.annotations.RemoteDestination;
055    import org.granite.tide.annotations.TideEnabled;
056    
057    
058    /**
059     * @author William DRAI
060     */
061    public 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    }