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 */
022 package org.granite.tide.seam.lazy;
023
024 import static org.jboss.seam.annotations.Install.FRAMEWORK;
025
026 import java.io.Serializable;
027 import java.util.HashSet;
028 import java.util.Set;
029
030 import javax.persistence.EntityManager;
031
032 import org.granite.tide.TidePersistenceManager;
033 import org.granite.tide.data.DataMergeContext;
034 import org.jboss.seam.Component;
035 import org.jboss.seam.ScopeType;
036 import org.jboss.seam.annotations.Install;
037 import org.jboss.seam.annotations.Logger;
038 import org.jboss.seam.annotations.Name;
039 import org.jboss.seam.annotations.Scope;
040 import org.jboss.seam.annotations.Transactional;
041 import org.jboss.seam.annotations.intercept.BypassInterceptors;
042 import org.jboss.seam.core.Expressions;
043 import org.jboss.seam.log.Log;
044
045 /**
046 * Initializes a request for a passed in entity and a lazy property.
047
048 * @author CIngram,VDanda
049 */
050 @Name("org.granite.tide.seam.seamInitializer")
051 @Scope(ScopeType.CONVERSATION)
052 @Install(precedence=FRAMEWORK)
053 @BypassInterceptors
054 public class SeamInitializer implements Serializable {
055
056 private static final long serialVersionUID = 1L;
057
058 @Logger Log log;
059
060 private transient TidePersistenceManager pm = null;
061
062 private Set<Object> loadedEntities = new HashSet<Object>();
063
064
065 /**
066 * Initiliazes the property for the passed in entity. It is attached to an associated context
067 * and then the property is accessed.
068 * @return Returns result from initializing the property.
069 */
070 @Transactional
071 public Object lazyInitialize(Object entity, String[] propertyNames) {
072 boolean removeAfterCall = false;
073
074 restoreLoadedEntities();
075
076 try {
077 if (entity instanceof String) {
078 String expression = "${" + entity + "}";
079 Expressions.ValueExpression<Object> valueExpr = Expressions.instance().createValueExpression(expression, Object.class);
080 entity = valueExpr.getValue();
081 }
082
083 if (pm == null) {
084 removeAfterCall = true;
085 pm = tryToDetermineInitiailzer();
086 if (pm == null)
087 throw new RuntimeException("TideInitializer is null, Entities with Lazy relationships have to be retrieved in a conversation, or the EntityManager name must be entityManager");
088 }
089
090 Object initializedEntity = pm.attachEntity(entity, propertyNames);
091
092 saveLoadedEntities();
093
094 return initializedEntity;
095 } finally {
096 if (removeAfterCall)
097 Component.forName("org.granite.tide.seam.seamInitializer").destroy(this);
098 }
099 }
100
101
102 /**
103 * Try to determine what type of persistence the application is using.
104 * If the EntityManager is stored under entityManager or if the Hibernate session is
105 * stored under session. Then the context will be found and used. This is only called if a
106 * ITidePersistenceManager is not found, probably because the query was not run in a conversation.
107 * @return The appropriate manager for the persistence context being used, if it can be determined
108 * otherwise a null is returned.
109 */
110 protected TidePersistenceManager tryToDetermineInitiailzer() {
111 EntityManager em = findEntityManager();
112 if (em != null)
113 return TidePersistenceFactory.createTidePersistence(null, em);
114
115 return null;
116 }
117
118 /**
119 * Try to find the entityManager if possible. Assume that the entityManager is stored under
120 * entityManager.
121 * @return The Current Entity manager
122 */
123 protected EntityManager findEntityManager() {
124 return (EntityManager) Component.getInstance("entityManager");
125 }
126
127 /**
128 * @return A instance of this component for the conversation.
129 */
130 public static SeamInitializer instance() {
131 return (SeamInitializer)Component.getInstance(SeamInitializer.class);
132 }
133
134 public void setTidePersistenceManager(TidePersistenceManager pm) {
135 this.pm = pm;
136 }
137
138 public TidePersistenceManager getTidePersistenceManager() {
139 return this.pm;
140 }
141
142 public void restoreLoadedEntities() {
143 DataMergeContext.restoreLoadedEntities(loadedEntities);
144 }
145
146 public void saveLoadedEntities() {
147 for (Object entity : DataMergeContext.getLoadedEntities())
148 loadedEntities.add(entity);
149 }
150 }
151