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.data;
022
023 import org.granite.logging.Logger;
024 import org.granite.context.GraniteContext;
025 import org.granite.messaging.amf.io.util.ClassGetter;
026 import org.granite.tide.TidePersistenceManager;
027 import org.granite.tide.TideTransactionManager;
028 import org.granite.util.Reflections;
029
030
031 /**
032 * Responsible for attaching a entity with the entity mangager
033 * @author cingram
034 *
035 */
036 public abstract class AbstractTidePersistenceManager implements TidePersistenceManager {
037
038 private static final Logger log = Logger.getLogger(AbstractTidePersistenceManager.class);
039
040 protected TideTransactionManager tm;
041
042
043 public AbstractTidePersistenceManager(TideTransactionManager tm) {
044 this.tm = tm;
045 if (this.tm == null)
046 throw new RuntimeException("transaction manager is null");
047 }
048
049
050 public Object attachEntity(Object entity, String[] propertyNames) {
051 return attachEntity(this, entity, propertyNames);
052 }
053
054 /**
055 * Attach the passed in entity with the EntityManager.
056 * @param entity
057 * @return the attached entity object
058 */
059 public Object attachEntity(TidePersistenceManager pm, Object entity, String[] propertyNames) {
060 Object attachedEntity = null;
061 ClassGetter getter = GraniteContext.getCurrentInstance().getGraniteConfig().getClassGetter();
062
063 try {
064 Object tx = tm.begin(pm instanceof TideTransactionPersistenceManager ? (TideTransactionPersistenceManager)pm : null);
065 if (tx == null)
066 throw new RuntimeException("Could not initiate transaction for lazy initialization");
067
068 try {
069 //the get is called to give the children a chance to override and
070 //use the implemented method
071 if (propertyNames != null)
072 attachedEntity = fetchEntity(entity, propertyNames);
073 else
074 attachedEntity = entity;
075
076 if (attachedEntity != null && propertyNames != null) {
077 for (int i = 0; i < propertyNames.length; i++) {
078 Object initializedObj = attachedEntity;
079 String[] pnames = propertyNames[i].split("\\.");
080 for (int j = 0; j < pnames.length; j++)
081 initializedObj = Reflections.getGetterMethod(initializedObj.getClass(), pnames[j]).invoke(initializedObj);
082
083 //This is here to make sure the list is forced to return a value while operating inside of a
084 //session. Forcing the initialization of object.
085 if (getter != null)
086 getter.initialize(entity, propertyNames[i], initializedObj);
087 }
088 }
089
090 tm.commit(tx);
091 }
092 catch (Exception e) {
093 String propertyName = propertyNames != null && propertyNames.length > 0 ? propertyNames[0] : "";
094 log.error(e, "Error during lazy-initialization of collection: %s", propertyName);
095 tm.rollback(tx);
096 }
097 }
098 finally {
099 close();
100 }
101
102 return attachedEntity;
103 }
104
105 protected abstract void close();
106
107 /**
108 * Fetch the entity with its lazy properties from the persistence context.
109 * @param entity entity to load
110 * @param fetch array of property names to fetch
111 * @return the entity with the persistence context.
112 */
113 public abstract Object fetchEntity(Object entity, String[] fetch);
114
115 }