/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.tide.cdi;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessBean;
import javax.enterprise.inject.spi.ProcessProducerField;
import javax.enterprise.inject.spi.ProcessProducerMethod;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject;
import javax.inject.Named;
import org.granite.logging.Logger;
import org.granite.messaging.amf.io.util.externalizer.annotation.ExternalizedBean;
import org.granite.messaging.service.annotations.RemoteDestination;
import org.granite.tide.annotations.TideEnabled;
/**
* @author William DRAI
*/
public class TideExtension implements Extension {
private static final Logger log = Logger.getLogger(TideExtension.class);
@Inject
BeanManager manager;
private Bean<?> tideInstrumentedBeans = null;
private Map<Type, Bean<?>> instrumentedBeans = new HashMap<Type, Bean<?>>();
private Map<Object, Type> producedBeans = new HashMap<Object, Type>();
public <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> event) {
AnnotatedType<X> annotatedType = event.getAnnotatedType();
boolean tideComponent = false;
boolean tideBean = false;
for (Type type : annotatedType.getTypeClosure()) {
if (type instanceof ParameterizedType)
type = ((ParameterizedType)type).getRawType();
if (type instanceof Class<?>
&& (((Class<?>)type).isAnnotationPresent(RemoteDestination.class)
|| ((Class<?>)type).isAnnotationPresent(TideEnabled.class)
|| ((Class<?>)type).isAnnotationPresent(Named.class)
|| ((Class<?>)type).isAnnotationPresent(RequestScoped.class))) {
tideComponent = true;
break;
}
if (type instanceof Class<?>
&& ((Serializable.class.isAssignableFrom((Class<?>)type) && ((Class<?>)type).isAnnotationPresent(Named.class))
|| ((Class<?>)type).isAnnotationPresent(ExternalizedBean.class))) {
tideBean = true;
break;
}
}
if (tideComponent || tideBean)
event.setAnnotatedType(new TideAnnotatedType<X>(annotatedType, tideComponent, tideBean));
}
public <X> void processBean(@Observes ProcessBean<X> event) {
if (event.getAnnotated().isAnnotationPresent(TideComponent.class) || event.getAnnotated().isAnnotationPresent(TideBean.class)) {
instrumentedBeans.put(event.getAnnotated().getBaseType(), event.getBean());
log.info("Instrumented Tide component %s", event.getBean().toString());
}
Bean<?> bean = event.getBean();
if (event instanceof ProcessProducerMethod<?, ?>) {
Type type = ((ProcessProducerMethod<?, ?>)event).getAnnotatedProducerMethod().getDeclaringType().getBaseType();
producedBeans.put(((ProcessProducerMethod<?, ?>)event).getAnnotatedProducerMethod().getBaseType(), type);
if (bean.getName() != null)
producedBeans.put(bean.getName(), type);
}
else if (event instanceof ProcessProducerField<?, ?>) {
Type type = ((ProcessProducerField<?, ?>)event).getAnnotatedProducerField().getDeclaringType().getBaseType();
producedBeans.put(((ProcessProducerField<?, ?>)event).getAnnotatedProducerField().getBaseType(), type);
if (bean.getName() != null)
producedBeans.put(bean.getName(), type);
}
if (event.getBean().getBeanClass().equals(TideInstrumentedBeans.class))
tideInstrumentedBeans = event.getBean();
}
public void processAfterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager manager) {
}
public void processAfterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager manager) {
if (tideInstrumentedBeans == null)
return;
TideInstrumentedBeans ib = (TideInstrumentedBeans)manager.getReference(tideInstrumentedBeans, TideInstrumentedBeans.class,
manager.createCreationalContext(tideInstrumentedBeans));
ib.setBeans(instrumentedBeans);
ib.setProducedBeans(producedBeans);
}
@SuppressWarnings("serial")
public static class TideAnnotatedType<T> implements AnnotatedType<T> {
private final AnnotatedType<T> annotatedType;
private final Annotation componentQualifier = new AnnotationLiteral<TideComponent>() {};
private final Annotation beanQualifier = new AnnotationLiteral<TideBean>() {};
private final Set<Annotation> annotations;
public TideAnnotatedType(AnnotatedType<T> annotatedType, boolean component, boolean bean) {
this.annotatedType = annotatedType;
annotations = new HashSet<Annotation>(annotatedType.getAnnotations());
if (component)
annotations.add(componentQualifier);
if (bean)
annotations.add(beanQualifier);
}
public Set<AnnotatedConstructor<T>> getConstructors() {
return annotatedType.getConstructors();
}
public Set<AnnotatedField<? super T>> getFields() {
return annotatedType.getFields();
}
public Class<T> getJavaClass() {
return annotatedType.getJavaClass();
}
public Set<AnnotatedMethod<? super T>> getMethods() {
return annotatedType.getMethods();
}
@SuppressWarnings("unchecked")
public <X extends Annotation> X getAnnotation(Class<X> annotationClass) {
if (annotationClass.equals(TideComponent.class))
return (X)componentQualifier;
if (annotationClass.equals(TideBean.class))
return (X)beanQualifier;
return annotatedType.getAnnotation(annotationClass);
}
public Set<Annotation> getAnnotations() {
return annotations;
}
public Type getBaseType() {
return annotatedType.getBaseType();
}
public Set<Type> getTypeClosure() {
return annotatedType.getTypeClosure();
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
if (annotationClass.equals(TideComponent.class) && annotations.contains(componentQualifier))
return true;
if (annotationClass.equals(TideBean.class) && annotations.contains(beanQualifier))
return true;
return annotatedType.isAnnotationPresent(annotationClass);
}
}
}