/* * 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.manager; import com.caucho.amber.AmberException; import com.caucho.amber.AmberRuntimeException; import com.caucho.amber.cfg.AmberConfigManager; import com.caucho.amber.cfg.EmbeddableIntrospector; import com.caucho.amber.cfg.EntityMappingsConfig; import com.caucho.amber.cfg.MappedSuperIntrospector; import com.caucho.amber.cfg.NamedNativeQueryConfig; import com.caucho.amber.cfg.SqlResultSetMappingConfig; import com.caucho.amber.entity.AmberCompletion; import com.caucho.amber.entity.AmberEntityHome; import com.caucho.amber.entity.Entity; import com.caucho.amber.entity.EntityItem; import com.caucho.amber.entity.EntityKey; import com.caucho.amber.entity.Listener; import com.caucho.amber.gen.AmberGenerator; import com.caucho.amber.gen.AmberGeneratorImpl; import com.caucho.amber.idgen.IdGenerator; import com.caucho.amber.idgen.SequenceIdGenerator; import com.caucho.amber.query.AbstractQuery; import com.caucho.amber.query.QueryCacheKey; import com.caucho.amber.query.ResultSetCacheChunk; import com.caucho.amber.table.AmberTable; import com.caucho.amber.type.*; import com.caucho.config.ConfigException; import com.caucho.config.Names; import com.caucho.config.inject.BeanBuilder; import com.caucho.config.inject.InjectManager; import com.caucho.java.gen.JavaClassGenerator; import com.caucho.jdbc.JdbcMetaData; import com.caucho.naming.Jndi; import com.caucho.util.L10N; import com.caucho.util.LruCache; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.io.IOException; import java.lang.ref.SoftReference; import java.lang.reflect.Method; import java.sql.ResultSetMetaData; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; /** * Main interface between Resin and the connector. It's the * top-level SPI class for creating the SPI ManagedConnections. * * The resource configuration in Resin's web.xml will use bean-style * configuration to configure the ManagecConnectionFactory. */ public class AmberPersistenceUnit { private static final L10N L = new L10N(AmberPersistenceUnit.class); private static final Logger log = Logger.getLogger(AmberPersistenceUnit.class.getName()); private String _name; private boolean _isJPA; private AmberContainer _amberContainer; // Actual class is EntityManagerProxy, but EntityManager is JDK 1.5 dependent private Object _entityManagerProxy; // basic data source private DataSource _dataSource; // data source for read-only requests private DataSource _readDataSource; // data source for requests in a transaction private DataSource _xaDataSource; private String _jtaDataSourceName; private String _nonJtaDataSourceName; // persistence.xml jta-data-source private DataSource _jtaDataSource; // persistence.xml non-jta-data-source private DataSource _nonJtaDataSource; private JdbcMetaData _jdbcMetaData; private Boolean _createDatabaseTables; private boolean _validateDatabaseTables = true; // private long _tableCacheTimeout = 250; private long _tableCacheTimeout = 2000; private TypeManager _typeManager = new TypeManager(); // loader override for ejb private ClassLoader _enhancedLoader; private HashMap<String,AmberTable> _tableMap = new HashMap<String,AmberTable>(); private HashMap<String,AmberEntityHome> _entityHomeMap = new HashMap<String,AmberEntityHome>(); private HashMap<String,IdGenerator> _tableGenMap = new HashMap<String,IdGenerator>(); private HashMap<String,SequenceIdGenerator> _sequenceGenMap = new HashMap<String,SequenceIdGenerator>(); private LruCache<String,AbstractQuery> _queryParseCache = new LruCache<String,AbstractQuery>(1024); private LruCache<QueryCacheKey,SoftReference<ResultSetCacheChunk>> _queryCache = new LruCache<QueryCacheKey,SoftReference<ResultSetCacheChunk>>(1024); private LruCache<QueryCacheKey,SoftReference<ResultSetMetaData>> _queryCacheMetaData = new LruCache<QueryCacheKey,SoftReference<ResultSetMetaData>>(16); private LruCache<EntityKey,SoftReference<EntityItem>> _entityCache = new LruCache<EntityKey,SoftReference<EntityItem>>(32 * 1024); private EntityKey _entityKey = new EntityKey(); private ArrayList<EntityType> _lazyConfigure = new ArrayList<EntityType>(); private ArrayList<EntityType> _lazyGenerate = new ArrayList<EntityType>(); private ArrayList<AmberEntityHome> _lazyHomeInit = new ArrayList<AmberEntityHome>(); private ArrayList<AmberTable> _lazyTable = new ArrayList<AmberTable>(); private HashMap<String,String> _namedQueryMap = new HashMap<String,String>(); private HashMap<String, SqlResultSetMappingConfig> _sqlResultSetMap = new HashMap<String, SqlResultSetMappingConfig>(); private HashMap<String, NamedNativeQueryConfig> _namedNativeQueryMap = new HashMap<String, NamedNativeQueryConfig>(); private ArrayList<EntityMappingsConfig> _entityMappingsList; private ArrayList<EmbeddableType> _embeddableTypes = new ArrayList<EmbeddableType>(); private ArrayList<MappedSuperclassType> _mappedSuperclassTypes = new ArrayList<MappedSuperclassType>(); private ArrayList<ListenerType> _defaultListeners = new ArrayList<ListenerType>(); private AmberConfigManager _configManager; private EmbeddableIntrospector _embeddableIntrospector; private MappedSuperIntrospector _mappedSuperIntrospector; private AmberGenerator _generator; // private boolean _supportsGetGeneratedKeys; private ThreadLocal<AmberConnection> _threadConnection = new ThreadLocal<AmberConnection>(); private volatile boolean _isInit; private long _xid = 1; public AmberPersistenceUnit(AmberContainer container, String name) { _amberContainer = container; _name = name; _dataSource = container.getDataSource(); _xaDataSource = container.getXADataSource(); _readDataSource = container.getReadDataSource(); _configManager = new AmberConfigManager(this); // needed to support JDK 1.4 compatibility try { bindProxy(); } catch (Throwable e) { log.log(Level.FINE, e.toString(), e); } } public void setName(String name) { _name = name; } public String getName() { return _name; } private void bindProxy() throws Exception { /* String name = getName(); // XXX: is "default" appropriate? // jpa/0s2m <=> tck: ejb30/persistence/ee/packaging/ejb/resource_local/test1 if (name == null || "".equals(name)) name = "default"; InjectManager manager = InjectManager.create(_amberContainer.getParentClassLoader()); EntityManagerFactory factory = new AmberEntityManagerFactory(this); BeanFactory beanFactory = manager.createBeanFactory(EntityManagerFactory.class); beanFactory.binding(Names.create(name)); manager.addBean(beanFactory.singleton(factory)); beanFactory = manager.createBeanFactory(EntityManager.class); beanFactory.binding(Names.create(name)); manager.addBean(beanFactory.singleton(new EntityManagerProxy(this))); String jndiName = AmberContainer.getPersistenceContextJndiPrefix() + '/' + name; Jndi.bindDeepShort(jndiName, factory); */ } public EntityManager getEntityManager() { // return (EntityManager) _entityManagerProxy; return null; } public AmberContainer getAmberContainer() { return _amberContainer; } public ClassLoader getTempClassLoader() { return _amberContainer.getTempClassLoader(); } public ClassLoader getEnhancedLoader() { if (_enhancedLoader != null) return _enhancedLoader; else return _amberContainer.getEnhancedLoader(); } /** * EJB/CMP needs to set a special enhanced loader. */ public void setEnhancedLoader(ClassLoader loader) { _enhancedLoader = loader; } /** * Sets the data source. */ public void setDataSource(DataSource dataSource) { _dataSource = dataSource; } /** * Gets the data source. */ public DataSource getDataSource() { if (_jtaDataSource != null) return _jtaDataSource; else if (_nonJtaDataSource != null) return _nonJtaDataSource; else if (_dataSource != null) return _dataSource; else { return _amberContainer.getDataSource(); } } /** * Sets the read data source. */ public void setReadDataSource(DataSource dataSource) { _readDataSource = dataSource; } /** * Gets the read data source. */ public DataSource getReadDataSource() { return _readDataSource; } /** * Sets the XA data source. */ public void setXADataSource(DataSource dataSource) { _xaDataSource = dataSource; } /** * Gets the xa data source. */ public DataSource getXADataSource() { return _xaDataSource; } /** * Sets the persistence.xml jta data source. */ public void setJtaDataSourceName(String name) { _jtaDataSourceName = name; } /** * Sets the persistence.xml non-jta data source. */ public void setNonJtaDataSourceName(String name) { _nonJtaDataSourceName = name; } /** * Sets the persistence.xml jta data source. */ public void setJtaDataSource(DataSource dataSource) { _jtaDataSource = dataSource; } /** * Sets the persistence.xml non-jta data source. */ public void setNonJtaDataSource(DataSource dataSource) { _nonJtaDataSource = dataSource; } /** * Return true for a jta-managed persistence unit */ public boolean isJta() { return _nonJtaDataSource == null || _jtaDataSource != null; } /** * Returns the jdbc meta data. */ public JdbcMetaData getMetaData() { if (_jdbcMetaData == null) { if (getDataSource() == null) throw new ConfigException("No data-source specified for PersistenceUnit"); _jdbcMetaData = JdbcMetaData.create(getDataSource()); } return _jdbcMetaData; } /** * Set true if database tables should be created automatically. */ public void setCreateDatabaseTables(boolean create) { _createDatabaseTables = create; } /** * Set true if database tables should be created automatically. */ public boolean getCreateDatabaseTables() { if (_createDatabaseTables != null) return _createDatabaseTables; else return _amberContainer.getCreateDatabaseTables(); } /** * Set true if database tables should be validated automatically. */ public void setValidateDatabaseTables(boolean validate) { _validateDatabaseTables = validate; } /** * Set true if database tables should be validated automatically. */ public boolean getValidateDatabaseTables() { return _validateDatabaseTables; } /** * Set the default table cache time. */ public void setTableCacheTimeout(long timeout) { _tableCacheTimeout = timeout; } /** * Get the default table cache time. */ public long getTableCacheTimeout() { return _tableCacheTimeout; } /** * Set false for EJB-style generation. */ public void setBytecodeGenerator(boolean isBytecodeGenerator) { if (isBytecodeGenerator) _generator = _amberContainer.getGenerator(); else _generator = new AmberGeneratorImpl(this); } /** * Returns a new xid. */ public long getXid() { synchronized (this) { return _xid++; } } public Class loadTempClass(String className) { try { return Class.forName(className, false, getTempClassLoader()); } catch (ClassNotFoundException e) { throw ConfigException.create(e); } } /** * Creates a table. */ public AmberTable createTable(String tableName) { if (log.isLoggable(Level.FINER)) log.log(Level.FINER, "AmberPersistenceUnit.createTable: " + tableName); AmberTable table = _tableMap.get(tableName); if (table == null) { table = new AmberTable(this, tableName); table.setCacheTimeout(getTableCacheTimeout()); _tableMap.put(tableName, table); _lazyTable.add(table); } return table; } public Throwable getConfigException() { return _amberContainer.getConfigException(); } /** * Add an entity. * * @param className the class name * @param type the JClass type if it is already verified as an * Entity | Embeddable | MappedSuperclass */ public void addEntityClass(String className, Class type) throws ConfigException { if (type == null) { type = loadTempClass(className); if (type == null) { throw new ConfigException(L.l("'{0}' is an unknown type", className)); } } BeanType beanType = _configManager.introspect(type); if (beanType instanceof EntityType) _amberContainer.addEntity(className, (EntityType) beanType); } /** * Adds a sql result set mapping. */ public void addSqlResultSetMapping(String resultSetName, SqlResultSetMappingConfig resultSet) throws ConfigException { if (_sqlResultSetMap.containsKey(resultSetName)) { throw new ConfigException(L.l("SqlResultSetMapping '{0}' is already defined.", resultSetName)); } _sqlResultSetMap.put(resultSetName, resultSet); } /** * Returns the sql result set mapping. */ public SqlResultSetMappingConfig getSqlResultSetMapping(String resultSetName) { return _sqlResultSetMap.get(resultSetName); } /** * Adds a named query. */ public void addNamedQuery(String name, String query) throws ConfigException { if (_namedQueryMap.containsKey(name)) { throw new ConfigException(L.l("Named query '{0}': '{1}' is already defined.", name, query)); } _namedQueryMap.put(name, query); } /** * Returns the named query statement. */ public String getNamedQuery(String name) { return (String) _namedQueryMap.get(name); } /** * Adds a named native query. */ public void addNamedNativeQuery(String name, NamedNativeQueryConfig queryConfig) throws ConfigException { if (_namedNativeQueryMap.containsKey(name)) { throw new ConfigException(L.l("NamedNativeQuery '{0}' is already defined.", name)); } _namedNativeQueryMap.put(name, queryConfig); } /** * Returns the named native query. */ public NamedNativeQueryConfig getNamedNativeQuery(String name) { return _namedNativeQueryMap.get(name); } /** * Adds an entity. */ public EntityType createEntity(Class beanClass) { return createEntity(beanClass.getName(), beanClass); } /** * Adds an entity. */ public EntityType createEntity(String name, Class beanClass) { EntityType entityType = (EntityType) _typeManager.get(name); if (entityType != null) return entityType; // ejb/0al2 // entityType = (EntityType) _typeManager.get(beanClass.getName()); if (entityType == null) { // The parent type can be a @MappedSuperclass or an @EntityType. EntityType parentType = null; for (Class parentClass = beanClass.getSuperclass(); parentType == null && parentClass != null; parentClass = parentClass.getSuperclass()) { parentType = (EntityType) _typeManager.get(parentClass.getName()); } if (parentType != null) entityType = new SubEntityType(this, parentType); else entityType = new EntityType(this); } // _typeManager.put(name, entityType); _typeManager.put(name, entityType); // XXX: some confusion about the double entry if (_typeManager.get(beanClass.getName()) == null) _typeManager.put(beanClass.getName(), entityType); entityType.setName(name); entityType.setBeanClass(beanClass); _lazyConfigure.add(entityType); // getEnvManager().addLazyConfigure(entityType); AmberEntityHome entityHome = _entityHomeMap.get(beanClass.getName()); if (entityHome == null) { entityHome = new AmberEntityHome(this, entityType); _lazyHomeInit.add(entityHome); _isInit = false; } addEntityHome(name, entityHome); // XXX: some confusion about the double entry, related to the EJB 3.0 // confuction of named instances. addEntityHome(beanClass.getName(), entityHome); return entityType; } /** * Adds an entity. */ public MappedSuperclassType createMappedSuperclass(String name, Class beanClass) { MappedSuperclassType mappedSuperType = (MappedSuperclassType) _typeManager.get(name); if (mappedSuperType != null) return mappedSuperType; mappedSuperType = new MappedSuperclassType(this); _typeManager.put(name, mappedSuperType); // XXX: some confusion about the double entry if (_typeManager.get(beanClass.getName()) == null) _typeManager.put(beanClass.getName(), mappedSuperType); _mappedSuperclassTypes.add(mappedSuperType); mappedSuperType.setName(name); mappedSuperType.setBeanClass(beanClass); return mappedSuperType; } /** * Adds an embeddable type. */ public EmbeddableType createEmbeddable(Class beanClass) { return createEmbeddable(beanClass.getName(), beanClass); } /** * Adds an embeddable type. */ public EmbeddableType createEmbeddable(String name, Class beanClass) { AmberType type = _typeManager.get(name); if (type != null && ! (type instanceof EmbeddableType)) throw new ConfigException(L.l("'{0}' is not a valid embeddable type", name)); EmbeddableType embeddableType; embeddableType = (EmbeddableType) type; if (embeddableType != null) return embeddableType; embeddableType = new EmbeddableType(this); _typeManager.put(name, embeddableType); // XXX: some confusion about the double entry if (_typeManager.get(beanClass.getName()) == null) _typeManager.put(beanClass.getName(), embeddableType); embeddableType.setName(name); embeddableType.setBeanClass(beanClass); _embeddableTypes.add(embeddableType); _amberContainer.addEmbeddable(beanClass.getName(), embeddableType); return embeddableType; } /** * Adds an enumerated type. */ public EnumType createEnum(String name, Class beanClass) { EnumType enumType = (EnumType) _typeManager.get(name); if (enumType != null) return enumType; enumType = new EnumType(); _typeManager.put(name, enumType); // XXX: some confusion about the double entry if (_typeManager.get(beanClass.getName()) == null) _typeManager.put(beanClass.getName(), enumType); enumType.setName(name); enumType.setBeanClass(beanClass); return enumType; } /** * Gets a default listener. */ public ListenerType getDefaultListener(String className) { return _amberContainer.getDefaultListener(className); } /** * Adds a default listener. */ public ListenerType addDefaultListener(Class beanClass) { ListenerType listenerType = getListener(beanClass); if (! _defaultListeners.contains(listenerType)) { _defaultListeners.add(listenerType); _amberContainer.addDefaultListener(beanClass.getName(), listenerType); } return listenerType; } /** * Gets an entity listener. */ public ListenerType getEntityListener(String className) { return _amberContainer.getEntityListener(className); } /** * Adds an entity listener. */ public ListenerType addEntityListener(String entityName, Class listenerClass) { ListenerType listenerType = getListener(listenerClass); _amberContainer.addEntityListener(entityName, listenerType); return listenerType; } private ListenerType getListener(Class beanClass) { String name = beanClass.getName(); ListenerType listenerType = (ListenerType) _typeManager.get(name); if (listenerType != null) return listenerType; listenerType = new ListenerType(this); ListenerType parentType = null; for (Class parentClass = beanClass.getSuperclass(); parentType == null && parentClass != null; parentClass = parentClass.getSuperclass()) { parentType = (ListenerType) _typeManager.get(parentClass.getName()); } if (parentType != null) listenerType = new SubListenerType(this, parentType); else listenerType = new ListenerType(this); _typeManager.put(name, listenerType); listenerType.setName(name); listenerType.setBeanClass(beanClass); return listenerType; } /** * Adds a new home bean. */ private void addEntityHome(String name, AmberEntityHome home) { _entityHomeMap.put(name, home); // getEnvManager().addEntityHome(name, home); } /** * Returns a table generator. */ public IdGenerator getTableGenerator(String name) { return _tableGenMap.get(name); } /** * Sets a table generator. */ public IdGenerator putTableGenerator(String name, IdGenerator gen) { synchronized (_tableGenMap) { IdGenerator oldGen = _tableGenMap.get(name); if (oldGen != null) return oldGen; else { _tableGenMap.put(name, gen); return gen; } } } /** * Adds a generator table. */ public GeneratorTableType createGeneratorTable(String name) { AmberType type = _typeManager.get(name); if (type instanceof GeneratorTableType) return (GeneratorTableType) type; if (type != null) throw new RuntimeException(L.l("'{0}' is a duplicate generator table.", type)); GeneratorTableType genType = new GeneratorTableType(this, name); _typeManager.put(name, genType); // _lazyGenerate.add(genType); return genType; } /** * Returns a sequence generator. */ public SequenceIdGenerator createSequenceGenerator(String name, int size) throws ConfigException { synchronized (_sequenceGenMap) { SequenceIdGenerator gen = _sequenceGenMap.get(name); if (gen == null) { gen = new SequenceIdGenerator(this, name, size); _sequenceGenMap.put(name, gen); } return gen; } } /** * Configures a type. */ public void initType(AbstractEnhancedType type) throws Exception { type.init(); getGenerator().generate(type); } /** * Configure lazy. */ public void generate() throws Exception { configure(); AbstractEnhancedType type = null; try { for (MappedSuperclassType mappedType : _mappedSuperclassTypes) { type = mappedType; initType(mappedType); } while (_lazyGenerate.size() > 0) { EntityType entityType = _lazyGenerate.remove(0); type = entityType; // Entity initType(entityType); ArrayList<ListenerType> listeners; String className = entityType.getBeanClass().getName(); listeners = _amberContainer.getEntityListeners(className); if (listeners == null) continue; // Entity Listeners for (ListenerType listenerType : listeners) { type = listenerType; initType(listenerType); } } // Embeddable for (EmbeddableType embeddableType : _embeddableTypes) { type = embeddableType; initType(embeddableType); } // Default Listeners for (ListenerType listenerType : _defaultListeners) { type = listenerType; initType(listenerType); } } catch (Exception e) { if (type != null) { type.setConfigException(e); _amberContainer.addEntityException(type.getBeanClass().getName(), e); } throw e; } try { getGenerator().compile(); } catch (Exception e) { _amberContainer.addException(e); throw e; } } /** * Gets the JPA flag. */ public boolean isJPA() { return _isJPA; } /** * Sets the JPA flag. */ public void setJPA(boolean isJPA) { _isJPA = isJPA; } /** * Configure lazy. */ public void generate(JavaClassGenerator javaGen) throws Exception { configure(); while (_lazyGenerate.size() > 0) { EntityType type = _lazyGenerate.remove(0); type.init(); if (type instanceof EntityType) { EntityType entityType = (EntityType) type; if (! entityType.isGenerated()) { if (entityType.getInstanceClassName() == null) throw new ConfigException(L.l("'{0}' does not have a configured instance class.", entityType)); entityType.setGenerated(true); try { getGenerator().generateJava(javaGen, entityType); } catch (Exception e) { log.log(Level.FINER, e.toString(), e); } } } configure(); } for (EmbeddableType embeddableType : _embeddableTypes) { embeddableType.init(); if (! embeddableType.isGenerated()) { if (embeddableType.getInstanceClassName() == null) throw new ConfigException(L.l("'{0}' does not have a configured instance class.", embeddableType)); embeddableType.setGenerated(true); try { getGenerator().generateJava(javaGen, embeddableType); } catch (Exception e) { log.log(Level.FINER, e.toString(), e); } } } for (SequenceIdGenerator gen : _sequenceGenMap.values()) gen.init(this); while (_defaultListeners.size() > 0) { ListenerType type = _defaultListeners.remove(0); type.init(); if (! type.isGenerated()) { if (type.getInstanceClassName() == null) throw new ConfigException(L.l("'{0}' does not have a configured instance class.", type)); type.setGenerated(true); try { getGenerator().generateJava(javaGen, type); } catch (Exception e) { log.log(Level.FINER, e.toString(), e); } } } } /** * Returns the @Embeddable introspector. */ public EmbeddableIntrospector getEmbeddableIntrospector() { return _embeddableIntrospector; } /** * Configure lazy. */ public void configure() throws Exception { //_embeddableIntrospector.configure(); //_mappedSuperIntrospector.configure(); _configManager.configure(); while (_lazyConfigure.size() > 0) { EntityType type = _lazyConfigure.remove(0); if (type.startConfigure()) { // getEnvManager().getGenerator().configure(type); } _configManager.configure(); if (! _lazyGenerate.contains(type)) _lazyGenerate.add(type); } updateFlushPriority(); } /** * Returns the entity home. */ public AmberEntityHome getEntityHome(String name) { if (! _isInit) { try { initEntityHomes(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new AmberRuntimeException(e); } } return _entityHomeMap.get(name); } /** * Returns the entity home by the schema name. */ public AmberEntityHome getHomeBySchema(String name) { for (AmberEntityHome home : _entityHomeMap.values()) { if (name.equals(home.getEntityType().getName())) return home; } try { createType(name); } catch (Exception e) { } return _entityHomeMap.get(name); } /** * Returns a matching embeddable type. */ public EmbeddableType getEmbeddable(String className) { AmberType type = _typeManager.get(className); if (type instanceof EmbeddableType) return (EmbeddableType) type; else return null; } public EntityType getEntityType(Class cl) { return getEntityType(cl.getName()); } /** * Returns a matching entity. */ public EntityType getEntityType(String className) { AmberType type = _typeManager.get(className); if (type instanceof EntityType) return (EntityType) type; else return null; } /** * Returns a matching mapped superclass. */ public MappedSuperclassType getMappedSuperclass(String className) { AmberType type = _typeManager.get(className); if (type instanceof MappedSuperclassType) return (MappedSuperclassType) type; return null; } /** * Returns a matching entity. */ public EntityType getEntityByInstanceClass(String className) { return _typeManager.getEntityByInstanceClass(className); } /** * Updates global entity priorities for flushing. */ public void updateFlushPriority() { ArrayList<EntityType> updatingEntities = new ArrayList<EntityType>(); try { HashMap<String,AmberType> typeMap = _typeManager.getTypeMap(); Collection<AmberType> types = typeMap.values(); Iterator it = types.iterator(); while (it.hasNext()) { AmberType type = (AmberType) it.next(); if (type instanceof EntityType) { EntityType entityType = (EntityType) type; if (updatingEntities.contains(entityType)) continue; updatingEntities.add(entityType); entityType.updateFlushPriority(updatingEntities); } } } finally { updatingEntities = null; } } /** * Creates a type. */ public AmberType createType(String typeName) throws ConfigException { AmberType type = _typeManager.get(typeName); if (type != null) return type; Class cl = loadTempClass(typeName); if (cl == null) throw new ConfigException(L.l("'{0}' is an unknown type", typeName)); return createType(cl); } /** * Creates a type. */ public AmberType createType(Class javaType) throws ConfigException { AmberType type = _typeManager.create(javaType); if (type != null) return type; return createEntity(javaType); } /** * Sets the generator. */ public AmberGenerator getGenerator() { if (_generator != null) return _generator; /* else if (_enhancer != null) return _enhancer; */ else { _generator = _amberContainer.getGenerator(); return _generator; } } /** * Returns the FALSE SQL literal, i.e., either "false" or "0". */ public String getFalseLiteral() { return getMetaData().getFalseLiteral(); } /** * Returns true if POSITION SQL function is allowed. */ public boolean hasPositionFunction() { return getMetaData().supportsPositionFunction(); } /** * Returns true if generated keys are allowed. */ public boolean hasReturnGeneratedKeys() { return getMetaData().supportsGetGeneratedKeys(); } /** * Sets the entity mappings config. */ public void setEntityMappingsList(ArrayList<EntityMappingsConfig> entityMappingsList) { //_entityMappingsList = entityMappingsList; //_entityIntrospector.setEntityMappingsList(_entityMappingsList); //_mappedSuperIntrospector.setEntityMappingsList(_entityMappingsList); } /** * Initialize the resource. */ public void init() throws ConfigException, IOException { initLoaders(); /* if (_entityMappingsList != null) { BaseConfigIntrospector introspector = new BaseConfigIntrospector(); introspector.initMetaData(_entityMappingsList, this); } */ if (_dataSource == null) return; /* try { Connection conn = _dataSource.getConnection(); try { DatabaseMetaData metaData = conn.getMetaData(); try { _supportsGetGeneratedKeys = metaData.supportsGetGeneratedKeys(); } catch (Throwable e) { } } finally { conn.close(); } } catch (SQLException e) { throw new ConfigException(e); } */ } /** * Initialize the resource. */ public void initLoaders() throws ConfigException, IOException { // getEnvManager().initLoaders(); } public void initEntityHomes() throws AmberRuntimeException, ConfigException { ArrayList<AmberEntityHome> homeList; synchronized (this) { if (_isInit) return; _isInit = true; homeList = new ArrayList<AmberEntityHome>(_lazyHomeInit); _lazyHomeInit.clear(); } if (_jtaDataSourceName != null && _jtaDataSource == null) _jtaDataSource = (DataSource) Jndi.lookup(_jtaDataSourceName); if (_nonJtaDataSourceName != null && _nonJtaDataSource == null) _nonJtaDataSource = (DataSource) Jndi.lookup(_nonJtaDataSourceName); initTables(); // for QA consistency Collections.sort(homeList); for (AmberEntityHome home : homeList) { home.init(); } } /** * Configure lazy. */ public void initTables() throws ConfigException { for (IdGenerator gen : _tableGenMap.values()) gen.start(); while (_lazyTable.size() > 0) { AmberTable table = _lazyTable.remove(0); if (getDataSource() == null) throw new ConfigException(L.l("{0}: No configured data-source found.", this)); if (getCreateDatabaseTables()) table.createDatabaseTable(this); if (getValidateDatabaseTables()) table.validateDatabaseTable(this); } } /** * Returns the cache connection. */ public CacheConnection getCacheConnection() { // cache connection cannot be reused (#998) CacheConnection cacheConnection = new CacheConnection(this); // ejb/0a0b - avoid dangling connections. cacheConnection.register(); return cacheConnection; } /** * Returns the cache connection. */ public AmberConnection createAmberConnection(boolean isExtended) { return new AmberConnection(this, isExtended); } /** * Returns the thread's amber connection. */ public AmberConnection getThreadConnection(boolean isExtended) { AmberConnection aConn = _threadConnection.get(); if (aConn == null) { aConn = new AmberConnection(this, isExtended); aConn.initThreadConnection(); _threadConnection.set(aConn); } return aConn; } /** * Unset the thread's amber connection. */ public void removeThreadConnection() { _threadConnection.set(null); } /** * Returns an EntityHome. */ public AmberEntityHome getHome(Class cl) { return getEntityHome(cl.getName()); } /** * Returns the query cache. */ public AbstractQuery getQueryParseCache(String sql) { return _queryParseCache.get(sql); } /** * Returns the query cache. */ public void putQueryParseCache(String sql, AbstractQuery query) { _queryParseCache.put(sql, query); } /** * Returns the query result. */ public ResultSetCacheChunk getQueryChunk(QueryCacheKey key) { SoftReference<ResultSetCacheChunk> ref = _queryCache.get(key); if (ref == null) return null; else { ResultSetCacheChunk chunk = ref.get(); if (chunk != null && chunk.isValid()) return chunk; else return null; } } /** * Returns the query meta data. */ public ResultSetMetaData getQueryMetaData(QueryCacheKey key) { SoftReference<ResultSetMetaData> ref = _queryCacheMetaData.get(key); if (ref == null) return null; else return ref.get(); } /** * Applies persistence unit default and entity listeners * for @PreXxx, @PostXxx callbacks. */ protected void callListeners(int callbackIndex, Entity entity) { // ejb/0g22 if (! isJPA()) return; String className = entity.getClass().getName(); EntityType entityType = (EntityType) _typeManager.get(className); if (! entityType.getExcludeDefaultListeners()) { for (ListenerType listenerType : _defaultListeners) { for (Method m : listenerType.getCallbacks(callbackIndex)) { Listener listener = (Listener) listenerType.getInstance(); listener.__caucho_callback(callbackIndex, entity); } } } ArrayList<ListenerType> listeners; listeners = _amberContainer.getEntityListeners(className); if (listeners == null) return; for (ListenerType listenerType : listeners) { if ((! entityType.getExcludeDefaultListeners()) && _defaultListeners.contains(listenerType)) continue; for (Method m : listenerType.getCallbacks(callbackIndex)) { Listener listener = (Listener) listenerType.getInstance(); listener.__caucho_callback(callbackIndex, entity); } } } /** * Sets the query result. */ public void putQueryChunk(QueryCacheKey key, ResultSetCacheChunk chunk) { _queryCache.put(key, new SoftReference<ResultSetCacheChunk>(chunk)); } /** * Sets the query meta data. */ public void putQueryMetaData(QueryCacheKey key, ResultSetMetaData metaData) { _queryCacheMetaData.put(key, new SoftReference<ResultSetMetaData>(metaData)); } /** * Returns the entity item. */ public EntityItem getEntityItem(String homeName, Object key) throws AmberException { AmberEntityHome home = getEntityHome(homeName); // XXX: needs refactoring throw new IllegalStateException("XXXX:"); // return home.findEntityItem(getCacheConnection(), key, false); } /** * Returns the entity with the given key. */ public EntityItem getEntity(EntityType rootType, Object key) { SoftReference<EntityItem> ref; synchronized (_entityKey) { _entityKey.init(rootType.getInstanceClass(), key); ref = _entityCache.get(_entityKey); } if (ref != null) return ref.get(); else return null; } /** * Returns the entity with the given key. */ public EntityItem getEntity(EntityKey entityKey) { SoftReference<EntityItem> ref; ref = _entityCache.get(entityKey); if (ref != null) return ref.get(); else return null; } /** * Sets the entity result. */ public EntityItem putEntity(EntityType rootType, Object key, EntityItem entity) { if (entity == null) throw new IllegalStateException(L.l("Null entity item cannot be added to the persistence unit cache")); SoftReference<EntityItem> ref = new SoftReference<EntityItem>(entity); EntityKey entityKey = new EntityKey(rootType.getInstanceClass(), key); // can't use putIfNew because the SoftReference might be empty, i.e. // not "new" but in need of replacement ref = _entityCache.put(entityKey, ref); return entity; } /** * Sets the entity result. */ public EntityItem putEntity(Class cl, Object key, EntityItem entity) { if (entity == null) throw new IllegalStateException(L.l("Null entity item cannot be added to the persistence unit cache")); SoftReference<EntityItem> ref = new SoftReference<EntityItem>(entity); EntityKey entityKey = new EntityKey(cl, key); // can't use putIfNew because the SoftReference might be empty, i.e. // not "new" but in need of replacement ref = _entityCache.put(entityKey, ref); return entity; } /** * Remove the entity result. */ public EntityItem removeEntity(EntityType rootType, Object key) { SoftReference<EntityItem> ref; synchronized (_entityKey) { _entityKey.init(rootType.getInstanceClass(), key); ref = _entityCache.remove(_entityKey); } if (ref != null) return ref.get(); else return null; } /** * Updates the cache item after commit. */ public void updateCacheItem(EntityType rootType, Object key, EntityItem cacheItem) { if (cacheItem == null) throw new IllegalStateException(L.l("Null entity item cannot be used to update the persistence unit cache")); SoftReference<EntityItem> ref; synchronized (_entityKey) { _entityKey.init(rootType.getInstanceClass(), key); // jpa/0q00 ref = new SoftReference<EntityItem>(cacheItem); EntityKey entityKey = new EntityKey(rootType.getInstanceClass(), key); // ejb/0628, ejb/06d0 _entityCache.put(entityKey, ref); } } /** * Completions affecting the cache. */ public void complete(ArrayList<AmberCompletion> completions) { int size = completions.size(); if (size == 0) return; synchronized (_entityCache) { Iterator<LruCache.Entry<EntityKey,SoftReference<EntityItem>>> iter; iter = _entityCache.iterator(); while (iter.hasNext()) { LruCache.Entry<EntityKey,SoftReference<EntityItem>> entry; entry = iter.next(); EntityKey key = entry.getKey(); SoftReference<EntityItem> valueRef = entry.getValue(); EntityItem value = valueRef.get(); if (value == null) continue; AmberEntityHome entityHome = value.getEntityHome(); EntityType entityRoot = entityHome.getEntityType(); Object entityKey = key.getKey(); for (int i = 0; i < size; i++) { if (completions.get(i).complete(entityRoot, entityKey, value)) { // XXX: delete } } } } synchronized (_queryCache) { Iterator<SoftReference<ResultSetCacheChunk>> iter; iter = _queryCache.values(); while (iter.hasNext()) { SoftReference<ResultSetCacheChunk> ref = iter.next(); ResultSetCacheChunk chunk = ref.get(); if (chunk != null) { for (int i = 0; i < size; i++) { if (completions.get(i).complete(chunk)) { // XXX: delete } } } } } } /** * destroys the manager. */ public void destroy() { _typeManager = null; _queryCache = null; _entityCache = null; } /** * New Version of getCreateTableSQL which returns * the SQL for the table with the given SQL type * but takes sqlType, length, precision, and scale. */ public String getCreateColumnSQL(int sqlType, int length, int precision, int scale) { return getMetaData().getCreateColumnSQL(sqlType, length, precision, scale); } @Override public String toString() { return getClass().getSimpleName() + "[" + _name + "]"; } }