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.lazy;
022    
023    import java.io.Serializable;
024    import java.util.HashSet;
025    import java.util.Iterator;
026    import java.util.Set;
027    
028    import javax.el.ELResolver;
029    import javax.enterprise.context.ConversationScoped;
030    import javax.enterprise.inject.Any;
031    import javax.enterprise.inject.Instance;
032    import javax.enterprise.inject.spi.BeanManager;
033    import javax.inject.Inject;
034    import javax.naming.InitialContext;
035    import javax.persistence.EntityManager;
036    import javax.persistence.EntityManagerFactory;
037    
038    import org.granite.logging.Logger;
039    import org.granite.tide.TidePersistenceManager;
040    import org.granite.tide.cdi.PersistenceConfiguration;
041    import org.granite.tide.data.DataMergeContext;
042    import org.granite.tide.data.JPAPersistenceManager;
043    
044    
045    @ConversationScoped
046    public class CDIInitializer implements Serializable {
047    
048        private static final long serialVersionUID = 1L;
049        
050        private static final Logger log = Logger.getLogger(CDIInitializer.class);
051        
052        private TidePersistenceManager pm = null;
053        
054        private Set<Object> loadedEntities = new HashSet<Object>();
055        
056        @Inject
057        private BeanManager manager;
058        
059        @Inject @Any
060        private Instance<TidePersistenceManager> persistenceManagers;
061        
062        @Inject @Any
063        private Instance<EntityManager> entityManagers;
064        
065        @Inject
066        private PersistenceConfiguration persistenceConfiguration;
067        
068        
069        /**
070         * Initiliazes the property for the passed in entity. It is attached to an associated context
071         * and then the property is accessed.
072         * @return Returns result from initializing the property.   
073         */
074        public Object lazyInitialize(Object entity, String[] propertyNames) {
075                if (entity instanceof String) {
076                String expression = "${" + entity + "}";
077                ELResolver elResolver = manager.getELResolver();
078                entity = elResolver.getValue(null, expression, null);
079                }
080                
081                    if (pm == null) {
082                        pm = getPersistenceManager();
083                            if (pm == null)
084                                throw new RuntimeException("TideInitializer is null, Entities with Lazy relationships have to be retrieved in a conversation");
085                    }       
086                    
087                    return pm.attachEntity(entity, propertyNames);
088            }
089            
090            
091            /**
092             * Try to determine what type of persistence the application is using. 
093             * If the EntityManager is stored under entityManager or if the Hibernate session is 
094             * stored under session. Then the context will be found and used. This is only called if a 
095             * ITidePersistenceManager is not found, probably because the query was not run in a conversation.
096             * @return The appropriate manager for the persistence context being used, if it can be determined
097             * otherwise a null is returned. 
098             */  
099            public TidePersistenceManager getPersistenceManager() {
100                    try {
101                            if (persistenceManagers != null && !persistenceManagers.isUnsatisfied()) {
102                                    if (persistenceManagers.isAmbiguous()) {
103                                            log.error("The application defines more than one TidePersistenceManager, please define only one to be used for Tide lazy loading");
104                                            return null;
105                                    }
106                                    return persistenceManagers.get();
107                            }
108                            InitialContext ic = new InitialContext();
109                            if (persistenceConfiguration.getEntityManagerFactoryJndiName() != null) {
110                                    EntityManagerFactory emf = (EntityManagerFactory)ic.lookup(persistenceConfiguration.getEntityManagerFactoryJndiName());
111                                    return new JPAPersistenceManager(emf);
112                            }
113                            else if (persistenceConfiguration.getEntityManagerJndiName() != null) {
114                                    EntityManager em = (EntityManager)ic.lookup(persistenceConfiguration.getEntityManagerJndiName());
115                                    return new JPAPersistenceManager(em);
116                            }
117                            else if (entityManagers != null) {
118                                    // Try with injected EntityManager defined as Resource
119                                    Iterator<EntityManager> iem = entityManagers.iterator();
120                                    EntityManager em = iem.hasNext() ? iem.next() : null;
121                                    if (em == null || iem.hasNext()) {
122                                            log.error("The application defines zero or more than one Persistence Unit, please define which one should be used for lazy loading in entity-manager-jndi-name");
123                                            return null;
124                                    }
125                                    return new JPAPersistenceManager(em);
126                            }
127                    }
128                    catch (Exception e) {
129                            log.error("Could not get EntityManager", e);
130                    }
131                    return null;
132            }
133            
134        
135        public void restoreLoadedEntities() {
136            DataMergeContext.restoreLoadedEntities(loadedEntities);
137        }
138        
139        public void saveLoadedEntities() {
140            for (Object entity : DataMergeContext.getLoadedEntities())
141                    loadedEntities.add(entity);
142        }
143    }
144