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