/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.amber.entity; import com.caucho.amber.AmberException; import com.caucho.amber.AmberRuntimeException; import com.caucho.amber.manager.AmberConnection; import com.caucho.amber.manager.AmberPersistenceUnit; import com.caucho.amber.query.CacheUpdate; import com.caucho.amber.type.*; import com.caucho.config.ConfigException; import com.caucho.util.L10N; import java.lang.ref.SoftReference; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.lang.Comparable; import java.util.logging.Level; import java.util.logging.Logger; /** * Manages the set of persistent beans. */ public class AmberEntityHome implements Comparable { private static final L10N L = new L10N(AmberEntityHome.class); private static final Logger log = Logger.getLogger(AmberEntityHome.class.getName()); private AmberPersistenceUnit _manager; private EntityType _entityType; private EntityFactory _entityFactory = new EntityFactory(); private Entity _homeBean; private ArrayList<SoftReference<CacheUpdate>> _cacheUpdates = new ArrayList<SoftReference<CacheUpdate>>(); private volatile boolean _isInit; private RuntimeException _configException; private Method _cauchoGetBeanMethod; public AmberEntityHome(AmberPersistenceUnit manager, EntityType type) { _manager = manager; _entityType = type; } /** * Returns the getBean method to instantiate the Amber object. */ public Method getCauchoGetBeanMethod() { return _cauchoGetBeanMethod; } /** * Returns the manager. */ public AmberPersistenceUnit getManager() { return _manager; } /** * Returns the entity type */ public EntityType getEntityType() { return _entityType; } /** * Returns the entity type */ public EntityType getRootType() { return (EntityType) _entityType.getRootType(); } /** * Returns the java class. */ public Class getJavaClass() { return _entityType.getInstanceClass(); } /** * Returns the entity factory. */ public EntityFactory getEntityFactory() { return _entityFactory; } /** * Sets the entity factory. */ public void setEntityFactory(EntityFactory factory) { _entityFactory = factory; } /** * Returns the cache timeout. */ public long getCacheTimeout() { return _entityType.getCacheTimeout(); } /** * Returns the instance class. */ public Class getInstanceClass() { return _entityType.getInstanceClass(); } /** * Link the classes. */ void link() throws ConfigException { // _entityClass.link(_manager); } /** * Initialize the home. */ public void init() throws ConfigException { synchronized (this) { if (_isInit) return; _isInit = true; } _entityType.init(); try { Class instanceClass = _entityType.getInstanceClass(); if (! Modifier.isAbstract(instanceClass.getModifiers())) _homeBean = (Entity) instanceClass.newInstance(); } catch (Exception e) { _entityType.setConfigException(e); _configException = ConfigException.create(e); throw _configException; } _entityType.start(); } /** * Returns the entity from the key. */ public Object getKeyFromEntity(Entity entity) throws AmberException { // return _entityType.getId().getType().getValue(obj); return null; } /** * Converts a long key to the key. */ public Object toObjectKey(long key) { return _entityType.getId().toObjectKey(key); } /** * Finds by the primary key. */ public EntityItem findItem(AmberConnection aConn, ResultSet rs, int index) throws SQLException { EntityItem item = _homeBean.__caucho_home_find(aConn, this, rs, index); return item; } /** * Finds by the primary key. */ public Object loadFull(AmberConnection aConn, ResultSet rs, int index) throws SQLException { // jpa/0l43 Entity entity; if (_homeBean == null) throw new NullPointerException("HOME:" + this); entity = aConn.getSubEntity(_homeBean.getClass(), rs.getObject(index)); if (entity != null) { if (entity.__caucho_getEntityState().isManaged()) return entity; } EntityItem item = findItem(aConn, rs, index); if (item == null) return null; entity = null; Object value = aConn.getEntityLazy(item); if (aConn.isActiveTransaction()) { if (value instanceof Entity) entity = (Entity) value; else if (_cauchoGetBeanMethod != null) { try { entity = (Entity) _cauchoGetBeanMethod.invoke(value, new Object[0]); entity.__caucho_makePersistent(aConn, item); } catch (Exception e) { log.log(Level.FINER, e.toString(), e); } } if (entity == null) entity = aConn.getEntity(item); } else entity = item.getEntity(); int keyLength = _entityType.getId().getKeyCount(); entity.__caucho_load(aConn, rs, index + keyLength); return entity; } /** * Finds by the primary key. */ public Object loadLazy(AmberConnection aConn, ResultSet rs, int index) throws SQLException { EntityItem item = findItem(aConn, rs, index); if (item == null) return null; return aConn.getEntity(item); } public EntityItem findEntityItem(AmberConnection aConn, Object key) throws AmberException { if (_homeBean == null && _configException != null) throw _configException; Entity entity; entity = (Entity) _homeBean.__caucho_home_find(aConn, this, key); // jpa/0l43 - with inheritance, an XA entity creates XAEntityItem // to avoid double loading if (entity == null) return null; else if (aConn.isActiveTransaction()) return new XAEntityItem(this, entity); else return new CacheableEntityItem(this, entity); } /** * Loads an entity based on the primary key. * * @param key the primary key * @param aConn the Amber connection to associate with the loaded item * @param isLoad if true, try to load the bean */ public EntityItem setEntityItem(Object key, EntityItem item) throws AmberException { if (key == null) throw new NullPointerException("primaryKey"); try { item.getEntity().__caucho_setConnection(_manager.getCacheConnection()); return _manager.putEntity(getRootType(), key, item); } catch (Exception e) { throw AmberException.create(e); } } /** * Loads an entity where the type is determined by a discriminator * * @param aConn the connection to associate with the entity * @param key the primary key * @param discriminator the object's discriminator */ public EntityItem findDiscriminatorEntityItem(AmberConnection aConn, Object key, String discriminator) throws SQLException { EntityItem item = null; // jpa/0l20 // XXX: ejb/0d01 // if (aConn.shouldRetrieveFromCache()) item = _manager.getEntity(getRootType(), key); if (item == null) { EntityType subEntity = (EntityType) _entityType.getSubClass(discriminator); Entity cacheEntity = subEntity.createBean(); cacheEntity.__caucho_setPrimaryKey(key); cacheEntity.__caucho_makePersistent(_manager.getCacheConnection(), subEntity); item = new CacheableEntityItem(this, cacheEntity); // The cache entity is added after commit. if (! aConn.isActiveTransaction()) { item = _manager.putEntity(getRootType(), key, item); } } return item; } /** * Instantiates a new entity for this home. */ public Entity newEntity(Object key) { return (Entity) _homeBean.__caucho_home_new(this, key, null, null); } /** * Loads an entity where the type is determined by a discriminator * * @param aConn the connection to associate with the entity * @param key the primary key * @param discriminator the object's discriminator */ public Entity newDiscriminatorEntity(Object key, String discriminator) { if (discriminator == null || key == null) throw new AmberRuntimeException(L.l("{0} is not a valid inheritance key.", key)); EntityType subType = (EntityType) _entityType.getSubClass(discriminator); return subType.getHome().newEntity(key); } /** * Finds by the primary key. */ public Entity makePersistent(Entity entity, AmberConnection aConn, boolean isLazy) throws SQLException { entity.__caucho_makePersistent(aConn, _entityType); return entity; } /** * Saves based on the object. */ public void save(AmberConnection aConn, Entity entity) throws SQLException { // Common to JPA and CMP. entity.__caucho_lazy_create(aConn, _entityType); if (! _manager.isJPA()) entity.__caucho_create(aConn, _entityType); } /** * Deletes by the primary key. */ public void delete(AmberConnection aConn, Object key) throws SQLException { _manager.removeEntity(getRootType(), key); } /** * Deletes by the primary key. */ public void delete(AmberConnection aConn, long primaryKey) throws SQLException { } /** * Update for a modification. */ public void update(Entity entity) throws SQLException { } /** * Adds a cache update. */ public void addUpdate(CacheUpdate update) { _cacheUpdates.add(new SoftReference<CacheUpdate>(update)); } public int compareTo(Object b) { AmberEntityHome home = (AmberEntityHome) b; return _entityType.getClassName().compareTo(home.getEntityType().getClassName()); } public String toString() { return "AmberEntityHome[" + _entityType + "]"; } }