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 }