/* * 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; import com.caucho.amber.entity.AmberCompletion; import com.caucho.amber.entity.AmberEntityHome; import com.caucho.amber.entity.EntityItem; import com.caucho.amber.entity.EntityKey; import com.caucho.amber.gen.AmberEnhancer; import com.caucho.amber.gen.AmberGenerator; import com.caucho.amber.manager.AmberConnection; import com.caucho.amber.manager.AmberPersistenceUnit; import com.caucho.amber.query.QueryCacheKey; import com.caucho.amber.query.ResultSetCacheChunk; import com.caucho.amber.type.EntityType; import com.caucho.bytecode.JClassLoader; import com.caucho.config.ConfigException; import com.caucho.loader.DynamicClassLoader; import com.caucho.loader.EnvironmentLocal; import com.caucho.loader.enhancer.EnhancerManager; import com.caucho.util.L10N; import com.caucho.util.LruCache; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; 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 EnvAmberManager { private static final Logger log = Logger.getLogger(AmberPersistenceUnit.class.getName()); private static final L10N L = new L10N(AmberPersistenceUnit.class); private static EnvironmentLocal<EnvAmberManager> _localManager = new EnvironmentLocal<EnvAmberManager>(); private ClassLoader _parentLoader; private ArrayList<AmberPersistenceUnit> _managerList = new ArrayList<AmberPersistenceUnit>(); private AmberEnhancer _enhancer; private long _tableCacheTimeout = 250; private JClassLoader _jClassLoader; private HashMap<String,AmberEntityHome> _entityHomeMap = new HashMap<String,AmberEntityHome>(); private LruCache<QueryCacheKey,SoftReference<ResultSetCacheChunk>> _queryCache = new LruCache<QueryCacheKey,SoftReference<ResultSetCacheChunk>>(1024); private LruCache<EntityKey,SoftReference<EntityItem>> _entityCache = new LruCache<EntityKey,SoftReference<EntityItem>>(32 * 1024); private EntityKey _entityKey = new EntityKey(); private long _xid; private AmberGenerator _generator; private volatile boolean _isInit; private EnvAmberManager() { _parentLoader = Thread.currentThread().getContextClassLoader(); _jClassLoader = EnhancerManager.create(_parentLoader).getJavaClassLoader(); try { if (_parentLoader instanceof DynamicClassLoader) ((DynamicClassLoader) _parentLoader).make(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } // _enhancer = new AmberEnhancer(this); EnhancerManager.create().addClassEnhancer(_enhancer); } public static EnvAmberManager createLocal() { EnvAmberManager manager = _localManager.get(); if (manager == null) { manager = new EnvAmberManager(); _localManager.set(manager); } return manager; } /** * Adds an amber manager. */ public void addAmberManager(AmberPersistenceUnit manager) { _managerList.add(manager); } /** * Set the default table cache time. */ public void setTableCacheTimeout(long timeout) { _tableCacheTimeout = timeout; } /** * Get the default table cache time. */ public long getTableCacheTimeout() { return _tableCacheTimeout; } /** * Returns a new xid. */ public long getXid() { synchronized (this) { return _xid++; } } /** * Returns the enhanced loader. */ public ClassLoader getEnhancedLoader() { return _parentLoader; } /** * Returns the enhanced loader. */ public JClassLoader getJClassLoader() { return _jClassLoader; } /** * Adds the entity home. */ public void addEntityHome(String name, AmberEntityHome home) { _entityHomeMap.put(name, home); } /** * Returns the entity home. */ public AmberEntityHome getEntityHome(String name) { if (! _isInit) { /* XXX: try { initEntityHomes(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new AmberRuntimeException(e); } */ } return _entityHomeMap.get(name); } /** * Returns a matching entity. */ public EntityType getEntity(String className) { AmberEntityHome home = _entityHomeMap.get(className); if (home != null) return home.getEntityType(); else return null; } /** * Returns a matching entity. */ public EntityType getEntityByInstanceClass(String className) { throw new UnsupportedOperationException(); } /** * Sets the generator. */ public void setGenerator(AmberGenerator generator) { _generator = generator; } /** * Sets the generator. */ public AmberGenerator getGenerator() { if (_generator != null) return _generator; else if (_enhancer != null) return _enhancer; else { // _generator = new AmberGeneratorImpl(this); return _generator; } } /** * Initialize the resource. */ public void initLoaders() throws ConfigException, IOException { } /** * Returns the cache connection. */ public AmberConnection createAmberConnection(boolean isExtended) { // XXX: needs to be an EnvAmberConnection return _managerList.get(0).createAmberConnection(isExtended); } /** * Initialize the home interfaces. */ public void initEntityHomes() throws Exception { for (AmberPersistenceUnit manager : _managerList) manager.initEntityHomes(); } /** * Initialize the resource. */ public void init() throws ConfigException, IOException { initLoaders(); } /** * Returns an EntityHome. */ public AmberEntityHome getHome(Class cl) { return getEntityHome(cl.getName()); } /** * 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; } } /** * Sets the query result. */ public void putQueryChunk(QueryCacheKey key, ResultSetCacheChunk chunk) { _queryCache.put(key, new SoftReference<ResultSetCacheChunk>(chunk)); } /** * Returns the entity item. */ public EntityItem getEntityItem(String homeName, Object key) throws AmberException { AmberEntityHome home = getEntityHome(homeName); // return home.findEntityItem(getCacheConnection(), key, false); return null; // XXX: } /** * Returns the query result. */ 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; } /** * Sets the entity result. */ public EntityItem putEntity(EntityType rootType, Object key, EntityItem entity) { SoftReference<EntityItem> ref = new SoftReference<EntityItem>(entity); EntityKey entityKey = new EntityKey(rootType.getInstanceClass(), key); ref = _entityCache.putIfNew(entityKey, ref); return ref.get(); } /** * 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; } /** * 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; EntityType entityRoot = value.getEntityHome().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() { _queryCache = null; _entityCache = null; _parentLoader = null; } public String toString() { return "EnvAmberManager[]"; } }