001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.core.entity;
018:
019: import org.apache.openejb.DeploymentInfo;
020: import org.apache.openejb.ApplicationException;
021:
022: import javax.transaction.TransactionSynchronizationRegistry;
023: import java.util.Set;
024: import java.util.HashSet;
025: import java.rmi.RemoteException;
026:
027: public class EntrancyTracker {
028: /**
029: * Thread local used to track the insances in the current call stack so we can determine if an nonreentrant
030: * instance is being reentered.
031: */
032: private final ThreadLocal<Set<InstanceKey>> inCallThreadLocal = new ThreadLocal<Set<InstanceKey>>() {
033: protected Set<InstanceKey> initialValue() {
034: return new HashSet<InstanceKey>();
035: }
036: };
037:
038: private final TransactionSynchronizationRegistry synchronizationRegistry;
039:
040: public EntrancyTracker(
041: TransactionSynchronizationRegistry synchronizationRegistry) {
042: this .synchronizationRegistry = synchronizationRegistry;
043: }
044:
045: public void enter(DeploymentInfo deploymentInfo, Object primaryKey)
046: throws ApplicationException {
047: if (primaryKey == null || deploymentInfo.isReentrant()) {
048: return;
049: }
050:
051: Object deploymentId = deploymentInfo.getDeploymentID();
052: InstanceKey key = new InstanceKey(deploymentId, primaryKey);
053:
054: Set<InstanceKey> inCall;
055: try {
056: //noinspection unchecked
057: inCall = (Set<InstanceKey>) synchronizationRegistry
058: .getResource(EntrancyTracker.class);
059: if (inCall == null) {
060: inCall = new HashSet<InstanceKey>();
061: synchronizationRegistry.putResource(
062: EntrancyTracker.class, inCall);
063: }
064: } catch (IllegalStateException e) {
065: inCall = inCallThreadLocal.get();
066: }
067:
068: if (!inCall.add(key)) {
069: ApplicationException exception = new ApplicationException(
070: new RemoteException("Attempted reentrant access. "
071: + "Bean " + deploymentId
072: + " is not reentrant and instance "
073: + primaryKey
074: + " has already been entered : " + inCall));
075: exception.printStackTrace();
076: throw exception;
077: }
078:
079: }
080:
081: public void exit(DeploymentInfo deploymentInfo, Object primaryKey)
082: throws ApplicationException {
083: if (primaryKey == null || deploymentInfo.isReentrant()) {
084: return;
085: }
086:
087: Object deploymentId = deploymentInfo.getDeploymentID();
088: InstanceKey key = new InstanceKey(deploymentId, primaryKey);
089:
090: Set<InstanceKey> inCall = null;
091: try {
092: //noinspection unchecked
093: inCall = (Set<InstanceKey>) synchronizationRegistry
094: .getResource(EntrancyTracker.class);
095: } catch (IllegalStateException e) {
096: inCall = inCallThreadLocal.get();
097: }
098:
099: if (inCall != null) {
100: inCall.remove(key);
101: }
102: }
103:
104: private static class InstanceKey {
105: private final Object deploymentId;
106: private final Object primaryKey;
107:
108: public InstanceKey(Object deploymentId, Object primaryKey) {
109: this .deploymentId = deploymentId;
110: this .primaryKey = primaryKey;
111: }
112:
113: public boolean equals(Object o) {
114: if (this == o)
115: return true;
116: if (o == null || getClass() != o.getClass())
117: return false;
118:
119: InstanceKey that = (InstanceKey) o;
120:
121: return deploymentId.equals(that.deploymentId)
122: && primaryKey.equals(that.primaryKey);
123: }
124:
125: public int hashCode() {
126: int result;
127: result = deploymentId.hashCode();
128: result = 31 * result + primaryKey.hashCode();
129: return result;
130: }
131:
132: public String toString() {
133: return deploymentId + ":" + primaryKey;
134: }
135: }
136: }
|