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