001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins;
023:
024: import org.jboss.ejb.EnterpriseContext;
025: import org.jboss.ejb.Container;
026: import org.jboss.ejb.EntityContainer;
027: import org.jboss.ejb.EntityEnterpriseContext;
028: import org.jboss.ejb.BeanLock;
029: import org.jboss.ejb.EntityCache;
030: import org.jboss.tm.TransactionLocal;
031: import org.jboss.logging.Logger;
032:
033: import java.rmi.RemoteException;
034: import java.rmi.NoSuchObjectException;
035: import java.util.HashMap;
036: import java.util.Map;
037:
038: /**
039: * Per transaction instance cache.
040: *
041: * @jmx:mbean
042: *
043: * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
044: * @version <tt>$Revision: 57209 $</tt>
045: */
046: public class PerTxEntityInstanceCache implements EntityCache,
047: PerTxEntityInstanceCacheMBean {
048: private static final Logger log = Logger
049: .getLogger(PerTxEntityInstanceCache.class);
050:
051: // per container tx instance cache
052: private final TransactionLocal txLocalCache = new TransactionLocal() {
053: protected Object initialValue() {
054: return new HashMap();
055: }
056: };
057:
058: private EntityContainer container;
059:
060: // EntityCache implementation
061:
062: public Object createCacheKey(Object id) {
063: return id;
064: }
065:
066: public EnterpriseContext get(Object id) throws RemoteException,
067: NoSuchObjectException {
068: if (id == null)
069: throw new IllegalArgumentException(
070: "Can't get an object with a null key");
071:
072: Map cache = getLocalCache();
073: EntityEnterpriseContext instance = (EntityEnterpriseContext) cache
074: .get(id);
075: if (instance == null) {
076: try {
077: // acquire
078: instance = (EntityEnterpriseContext) container
079: .getInstancePool().get();
080: // set key
081: instance.setId(id);
082: instance.setCacheKey(id);
083: // activate
084: container.getPersistenceManager().activateEntity(
085: instance);
086: // insert
087: cache.put(id, instance);
088: } catch (Throwable x) {
089: throw new NoSuchObjectException(x.getMessage());
090: }
091: }
092: return instance;
093: }
094:
095: public void insert(EnterpriseContext instance) {
096: if (instance == null)
097: throw new IllegalArgumentException(
098: "Can't insert a null object in the cache");
099:
100: EntityEnterpriseContext entity = (EntityEnterpriseContext) instance;
101: getLocalCache().put(entity.getCacheKey(), instance);
102: }
103:
104: public void release(EnterpriseContext instance) {
105: if (instance == null)
106: throw new IllegalArgumentException(
107: "Can't release a null object");
108:
109: tryToPassivate(instance);
110: }
111:
112: public void remove(Object id) {
113: getLocalCache().remove(id);
114: }
115:
116: public boolean isActive(Object id) {
117: return getLocalCache().containsKey(id);
118: }
119:
120: public long getCacheSize() {
121: return 0;
122: }
123:
124: public void flush() {
125: }
126:
127: // ContainerPlugin implementation
128:
129: public void setContainer(Container con) {
130: this .container = (EntityContainer) con;
131: }
132:
133: // Service implementation
134:
135: public void create() throws Exception {
136: }
137:
138: public void start() throws Exception {
139: }
140:
141: public void stop() {
142: }
143:
144: public void destroy() {
145: }
146:
147: // Protected
148:
149: protected void tryToPassivate(EnterpriseContext instance) {
150: Object id = instance.getId();
151: if (id != null) {
152: BeanLock lock = container.getLockManager().getLock(id);
153: try {
154: lock.sync();
155: if (canPassivate(instance)) {
156: try {
157: remove(id);
158: EntityEnterpriseContext entity = (EntityEnterpriseContext) instance;
159: container.getPersistenceManager()
160: .passivateEntity(entity);
161: container.getInstancePool().free(instance);
162: } catch (Exception ignored) {
163: log.warn("failed to passivate, id=" + id,
164: ignored);
165: }
166: } else {
167: log.warn("Unable to passivate due to ctx lock, id="
168: + id);
169: }
170: } finally {
171: lock.releaseSync();
172: container.getLockManager().removeLockRef(id);
173: }
174: }
175: }
176:
177: protected boolean canPassivate(EnterpriseContext ctx) {
178: if (ctx.isLocked()) {
179: // The context is in the interceptor chain
180: return false;
181: }
182:
183: if (ctx.getTransaction() != null) {
184: return false;
185: }
186:
187: Object key = ((EntityEnterpriseContext) ctx).getCacheKey();
188: return container.getLockManager().canPassivate(key);
189: }
190:
191: // Private
192:
193: private Map getLocalCache() {
194: return (Map) txLocalCache.get();
195: }
196: }
|