001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2014 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.seam.lazy; 023 024import static org.jboss.seam.annotations.Install.FRAMEWORK; 025 026import java.io.Serializable; 027import java.util.HashSet; 028import java.util.Set; 029 030import javax.persistence.EntityManager; 031 032import org.granite.tide.TidePersistenceManager; 033import org.granite.tide.data.DataMergeContext; 034import org.jboss.seam.Component; 035import org.jboss.seam.ScopeType; 036import org.jboss.seam.annotations.Install; 037import org.jboss.seam.annotations.Logger; 038import org.jboss.seam.annotations.Name; 039import org.jboss.seam.annotations.Scope; 040import org.jboss.seam.annotations.Transactional; 041import org.jboss.seam.annotations.intercept.BypassInterceptors; 042import org.jboss.seam.core.Expressions; 043import 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 054public 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