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 transient 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.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");
123 return null;
124 }
125 return new JPAPersistenceManager(em);
126 }
127 }
128 catch (Exception e) {
129 log.error(e, "Could not get EntityManager");
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