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 021package org.granite.tide.seam.lazy; 022 023import static org.jboss.seam.annotations.Install.FRAMEWORK; 024 025import java.io.Serializable; 026import java.util.HashSet; 027import java.util.Set; 028 029import javax.persistence.EntityManager; 030 031import org.granite.tide.TidePersistenceManager; 032import org.granite.tide.data.DataMergeContext; 033import org.jboss.seam.Component; 034import org.jboss.seam.ScopeType; 035import org.jboss.seam.annotations.Install; 036import org.jboss.seam.annotations.Logger; 037import org.jboss.seam.annotations.Name; 038import org.jboss.seam.annotations.Scope; 039import org.jboss.seam.annotations.Transactional; 040import org.jboss.seam.annotations.intercept.BypassInterceptors; 041import org.jboss.seam.core.Expressions; 042import 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 053public 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