/* GRANITE DATA SERVICES Copyright (C) 2012 GRANITE DATA SERVICES S.A.S. This file is part of Granite Data Services. Granite Data Services is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, see <http://www.gnu.org/licenses/>. */ package org.granite.client.tide.javafx.cdi; import java.util.Set; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.event.Observes; import javax.enterprise.inject.Produces; import javax.enterprise.inject.spi.AfterBeanDiscovery; import javax.enterprise.inject.spi.AnnotatedMember; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.BeforeBeanDiscovery; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.InjectionPoint; import javax.enterprise.inject.spi.InjectionTarget; import javax.enterprise.inject.spi.ProcessInjectionTarget; import javax.enterprise.inject.spi.ProcessProducer; import javax.enterprise.inject.spi.Producer; import javax.inject.Inject; import javax.validation.TraversableResolver; import org.granite.client.tide.Application; import org.granite.client.tide.ApplicationConfigurable; import org.granite.client.tide.Context; import org.granite.client.tide.ContextAware; import org.granite.client.tide.EventBus; import org.granite.client.tide.NameAware; import org.granite.client.tide.cdi.CDIContextManager; import org.granite.client.tide.cdi.CDIEventBus; import org.granite.client.tide.cdi.ViewContext; import org.granite.client.tide.data.EntityManager; import org.granite.client.tide.javafx.JavaFXApplication; import org.granite.client.tide.javafx.JavaFXDataManager; import org.granite.client.validation.NotifyingValidatorFactory; import org.granite.logging.Logger; /** * @author William DRAI */ public class JavaFXTideClientExtension implements Extension { private static final Logger log = Logger.getLogger(JavaFXTideClientExtension.class); private Application application = new JavaFXApplication(); public JavaFXTideClientExtension() { } public JavaFXTideClientExtension(Application application) { this.application = application; } public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event, BeanManager beanManager) { log.debug("Register internal Tide beans"); event.addAnnotatedType(beanManager.createAnnotatedType(JavaFXApplication.class)); event.addAnnotatedType(beanManager.createAnnotatedType(CDIEventBus.class)); event.addAnnotatedType(beanManager.createAnnotatedType(JavaFXCDIContextManager.class)); try { event.addAnnotatedType(beanManager.createAnnotatedType(JavaFXValidation.class)); } catch (Exception e) { // Bean validation not present } } public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager beanManager) { log.debug("Register internal Tide scopes"); event.addContext(new ViewContext()); } public void processProducer(@Observes ProcessProducer<Object, Object> event, BeanManager beanManager) { event.setProducer(new ProducerWrapper<Object>(application, beanManager, event.getProducer(), event.getAnnotatedMember())); } public void processInjectionTarget(@Observes ProcessInjectionTarget<Object> event, BeanManager beanManager) { event.setInjectionTarget(new InjectionTargetWrapper<Object>(application, beanManager, event.getInjectionTarget(), event.getAnnotatedType())); } @ApplicationScoped public static class JavaFXCDIContextManager extends CDIContextManager { protected JavaFXCDIContextManager() { super(); // CDI proxying... } @Inject public JavaFXCDIContextManager(Application application, EventBus eventBus) { super(application, eventBus); } @Produces public Context getContext() { return getContext(null); } @Produces public EntityManager getEntityManager() { return getContext(null).getEntityManager(); } @Produces public JavaFXDataManager getDataManager() { return (JavaFXDataManager)super.getDataManager(); } } @ApplicationScoped public static class JavaFXValidation { private Context context; protected JavaFXValidation() { super(); // CDI proxying... } @Inject public JavaFXValidation(Context context) { this.context = context; } @Produces public TraversableResolver getTraversableResolver() { return (TraversableResolver)context.getInitialBeans().get("traversableResolver"); } @Produces public NotifyingValidatorFactory getValidatorFactory() { return (NotifyingValidatorFactory)context.getInitialBeans().get("validatorFactory"); } } public static class ProducerWrapper<T> implements Producer<T> { private Application application; private BeanManager beanManager; private Producer<T> producer; private AnnotatedMember<T> annotatedMember; public ProducerWrapper(Application application, BeanManager beanManager, Producer<T> producer, AnnotatedMember<T> annotatedMember) { this.application = application; this.beanManager = beanManager; this.producer = producer; this.annotatedMember = annotatedMember; } @Override public void dispose(T instance) { producer.dispose(instance); } @Override public Set<InjectionPoint> getInjectionPoints() { return producer.getInjectionPoints(); } @Override public T produce(CreationalContext<T> cc) { T instance = producer.produce(cc); if (instance instanceof NameAware) { Set<Bean<?>> beans = beanManager.getBeans(annotatedMember.getBaseType()); if (beans.size() == 1) ((NameAware)instance).setName(beans.iterator().next().getName()); } if (instance instanceof ContextAware) { Set<Bean<?>> beans = beanManager.getBeans(Context.class); if (beans.size() == 1) { Bean<?> bean = beans.iterator().next(); CreationalContext<?> ccc = beanManager.createCreationalContext(bean); ((ContextAware)instance).setContext((Context)beanManager.getReference(bean, Context.class, ccc)); } } if (instance != null && instance.getClass().isAnnotationPresent(ApplicationConfigurable.class)) application.configure(instance); return instance; } } public static class InjectionTargetWrapper<T> implements InjectionTarget<T> { private Application application; private BeanManager beanManager; private InjectionTarget<T> injectionTarget; private AnnotatedType<T> annotatedType; public InjectionTargetWrapper(Application application, BeanManager beanManager, InjectionTarget<T> injectionTarget, AnnotatedType<T> annotatedType) { this.application = application; this.beanManager = beanManager; this.injectionTarget = injectionTarget; this.annotatedType = annotatedType; } @Override public void dispose(T instance) { injectionTarget.dispose(instance); } @Override public Set<InjectionPoint> getInjectionPoints() { return injectionTarget.getInjectionPoints(); } @Override public void inject(T instance, CreationalContext<T> cc) { injectionTarget.inject(instance, cc); } @Override public T produce(CreationalContext<T> cc) { return injectionTarget.produce(cc); } @Override public void postConstruct(T instance) { if (instance instanceof NameAware) { Set<Bean<?>> beans = beanManager.getBeans(annotatedType.getBaseType()); if (beans.size() == 1) ((NameAware)instance).setName(beans.iterator().next().getName()); } if (instance instanceof ContextAware) { Set<Bean<?>> beans = beanManager.getBeans(Context.class); if (beans.size() == 1) { Bean<?> bean = beans.iterator().next(); CreationalContext<?> ccc = beanManager.createCreationalContext(bean); ((ContextAware)instance).setContext((Context)beanManager.getReference(bean, Context.class, ccc)); } } if (instance != null && instance.getClass().isAnnotationPresent(ApplicationConfigurable.class)) application.configure(instance); injectionTarget.postConstruct(instance); } @Override public void preDestroy(T instance) { injectionTarget.preDestroy(instance); } } }