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 }