001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2012 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.client.tide.javafx.cdi;
022    
023    import java.util.Set;
024    
025    import javax.enterprise.context.ApplicationScoped;
026    import javax.enterprise.context.spi.CreationalContext;
027    import javax.enterprise.event.Observes;
028    import javax.enterprise.inject.Produces;
029    import javax.enterprise.inject.spi.AfterBeanDiscovery;
030    import javax.enterprise.inject.spi.AnnotatedMember;
031    import javax.enterprise.inject.spi.AnnotatedType;
032    import javax.enterprise.inject.spi.Bean;
033    import javax.enterprise.inject.spi.BeanManager;
034    import javax.enterprise.inject.spi.BeforeBeanDiscovery;
035    import javax.enterprise.inject.spi.Extension;
036    import javax.enterprise.inject.spi.InjectionPoint;
037    import javax.enterprise.inject.spi.InjectionTarget;
038    import javax.enterprise.inject.spi.ProcessInjectionTarget;
039    import javax.enterprise.inject.spi.ProcessProducer;
040    import javax.enterprise.inject.spi.Producer;
041    import javax.inject.Inject;
042    
043    import org.granite.client.tide.Context;
044    import org.granite.client.tide.ContextAware;
045    import org.granite.client.tide.EventBus;
046    import org.granite.client.tide.NameAware;
047    import org.granite.client.tide.Platform;
048    import org.granite.client.tide.PlatformConfigurable;
049    import org.granite.client.tide.cdi.CDIContextManager;
050    import org.granite.client.tide.cdi.CDIEventBus;
051    import org.granite.client.tide.cdi.ViewContext;
052    import org.granite.client.tide.data.EntityManager;
053    import org.granite.client.tide.javafx.JavaFXDataManager;
054    import org.granite.client.tide.javafx.JavaFXPlatform;
055    import org.granite.logging.Logger;
056    
057    /**
058     * @author William DRAI
059     */
060    public class JavaFXTideClientExtension implements Extension {
061            
062            private static final Logger log = Logger.getLogger(JavaFXTideClientExtension.class);
063            
064            private Platform platform = new JavaFXPlatform();
065            
066            
067            public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event, BeanManager beanManager) {
068                    log.debug("Register internal Tide beans");
069                    event.addAnnotatedType(beanManager.createAnnotatedType(JavaFXPlatform.class));
070                    event.addAnnotatedType(beanManager.createAnnotatedType(CDIEventBus.class));
071                    event.addAnnotatedType(beanManager.createAnnotatedType(JavaFXCDIContextManager.class));
072            }
073            
074            public void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {
075                    log.debug("Register internal Tide scopes");
076                    event.addContext(new ViewContext());
077            }
078            
079            public void processProducer(@Observes ProcessProducer<Object, Object> event, BeanManager beanManager) {
080                    event.setProducer(new ProducerWrapper<Object>(platform, beanManager, event.getProducer(), event.getAnnotatedMember()));
081            }
082            
083            public void processInjectionTarget(@Observes ProcessInjectionTarget<Object> event, BeanManager beanManager) {
084                    event.setInjectionTarget(new InjectionTargetWrapper<Object>(platform, beanManager, event.getInjectionTarget(), event.getAnnotatedType()));
085            }
086            
087            
088            @ApplicationScoped
089            public static class JavaFXCDIContextManager extends CDIContextManager {
090                    
091                    protected JavaFXCDIContextManager() {
092                            super();
093                            // CDI proxying...
094                    }
095                    
096                    @Inject
097                    public JavaFXCDIContextManager(Platform platform, EventBus eventBus) {
098                            super(platform, eventBus);
099                    }
100                    
101                    @Produces
102                    public Context getContext() {
103                            return getContext(null);
104                    }
105                    
106                    @Produces
107                    public EntityManager getEntityManager() {
108                            return getContext(null).getEntityManager();
109                    }
110                    
111                    @Produces
112                    public JavaFXDataManager getDataManager() {
113                            return (JavaFXDataManager)super.getDataManager();
114                    }
115            }
116            
117            public static class ProducerWrapper<T> implements Producer<T> {
118                    
119                    private Platform platform;
120                    private BeanManager beanManager;
121                    private Producer<T> producer;
122                    private AnnotatedMember<T> annotatedMember;
123                    
124                    public ProducerWrapper(Platform platform, BeanManager beanManager, Producer<T> producer, AnnotatedMember<T> annotatedMember) {
125                            this.platform = platform;
126                            this.beanManager = beanManager;
127                            this.producer = producer;
128                            this.annotatedMember = annotatedMember;
129                    }
130                    
131                    @Override
132                    public void dispose(T instance) {
133                            producer.dispose(instance);
134                    }
135    
136                    @Override
137                    public Set<InjectionPoint> getInjectionPoints() {
138                            return producer.getInjectionPoints();
139                    }
140    
141                    @Override
142                    public T produce(CreationalContext<T> cc) {
143                            T instance = producer.produce(cc);
144                            
145                            if (instance instanceof NameAware) {
146                                    Set<Bean<?>> beans = beanManager.getBeans(annotatedMember.getBaseType());
147                                    if (beans.size() == 1)
148                                            ((NameAware)instance).setName(beans.iterator().next().getName());
149                            }
150                            
151                            if (instance instanceof ContextAware) {
152                                    Set<Bean<?>> beans = beanManager.getBeans(Context.class);
153                                    if (beans.size() == 1) {
154                                            Bean<?> bean = beans.iterator().next();
155                                            CreationalContext<?> ccc = beanManager.createCreationalContext(bean);
156                                            ((ContextAware)instance).setContext((Context)beanManager.getReference(bean, Context.class, ccc));
157                                    }
158                            }
159                            
160                            if (instance != null && instance.getClass().isAnnotationPresent(PlatformConfigurable.class))
161                                    platform.configure(instance);
162                            
163                            return instance;
164                    }
165            }
166            
167            public static class InjectionTargetWrapper<T> implements InjectionTarget<T> {
168                    
169                    private Platform platform;
170                    private BeanManager beanManager;
171                    private InjectionTarget<T> injectionTarget;
172                    private AnnotatedType<T> annotatedType;
173                    
174                    public InjectionTargetWrapper(Platform platform, BeanManager beanManager, InjectionTarget<T> injectionTarget, AnnotatedType<T> annotatedType) {
175                            this.platform = platform;
176                            this.beanManager = beanManager;
177                            this.injectionTarget = injectionTarget;
178                            this.annotatedType = annotatedType;
179                    }
180    
181                    @Override
182                    public void dispose(T instance) {
183                            injectionTarget.dispose(instance);
184                    }
185                    
186                    @Override
187                    public Set<InjectionPoint> getInjectionPoints() {
188                            return injectionTarget.getInjectionPoints();
189                    }
190    
191                    @Override
192                    public void inject(T instance, CreationalContext<T> cc) {
193                            injectionTarget.inject(instance, cc);
194                    }
195    
196                    @Override
197                    public T produce(CreationalContext<T> cc) {
198                            return injectionTarget.produce(cc);
199                    }
200    
201                    @Override
202                    public void postConstruct(T instance) {
203                            if (instance instanceof NameAware) {
204                                    Set<Bean<?>> beans = beanManager.getBeans(annotatedType.getBaseType());
205                                    if (beans.size() == 1)
206                                            ((NameAware)instance).setName(beans.iterator().next().getName());
207                            }
208                            
209                            if (instance instanceof ContextAware) {
210                                    Set<Bean<?>> beans = beanManager.getBeans(Context.class);
211                                    if (beans.size() == 1) {
212                                            Bean<?> bean = beans.iterator().next();
213                                            CreationalContext<?> ccc = beanManager.createCreationalContext(bean);
214                                            ((ContextAware)instance).setContext((Context)beanManager.getReference(bean, Context.class, ccc));
215                                    }
216                            }
217                            
218                            if (instance != null && instance.getClass().isAnnotationPresent(PlatformConfigurable.class))
219                                    platform.configure(instance);
220                            
221                            injectionTarget.postConstruct(instance);
222                    }
223    
224                    @Override
225                    public void preDestroy(T instance) {
226                            injectionTarget.preDestroy(instance);
227                    }
228            }
229    }