001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.client;
017:
018: import java.io.Serializable;
019: import java.lang.reflect.Method;
020: import java.lang.ref.WeakReference;
021: import java.rmi.NoSuchObjectException;
022: import java.rmi.RemoteException;
023: import java.rmi.AccessException;
024: import java.util.HashSet;
025: import java.util.Set;
026: import java.util.concurrent.ConcurrentHashMap;
027: import java.util.concurrent.ConcurrentMap;
028:
029: import org.apache.openejb.client.proxy.InvocationHandler;
030:
031: import javax.transaction.TransactionRequiredException;
032: import javax.transaction.TransactionRolledbackException;
033: import javax.ejb.TransactionRequiredLocalException;
034: import javax.ejb.TransactionRolledbackLocalException;
035: import javax.ejb.AccessLocalException;
036: import javax.ejb.EJBException;
037: import javax.ejb.EJBAccessException;
038: import javax.ejb.EJBObject;
039: import javax.ejb.EJBHome;
040: import javax.ejb.NoSuchEJBException;
041:
042: public abstract class EJBInvocationHandler implements
043: InvocationHandler, Serializable {
044:
045: protected static final Method EQUALS = getMethod(Object.class,
046: "equals", Object.class);
047: protected static final Method HASHCODE = getMethod(Object.class,
048: "hashCode");
049: protected static final Method TOSTRING = getMethod(Object.class,
050: "toString");
051:
052: protected static final ConcurrentMap<Object, Set<WeakReference<EJBInvocationHandler>>> liveHandleRegistry = new ConcurrentHashMap<Object, Set<WeakReference<EJBInvocationHandler>>>();
053:
054: protected transient boolean inProxyMap = false;
055:
056: protected transient boolean isInvalidReference = false;
057:
058: protected transient EJBRequest request;
059:
060: protected transient EJBMetaDataImpl ejb;
061: protected transient ServerMetaData server;
062: protected transient ClientMetaData client;
063:
064: protected transient Object primaryKey;
065: protected final boolean remote;
066:
067: public EJBInvocationHandler() {
068: remote = false;
069: }
070:
071: public EJBInvocationHandler(EJBMetaDataImpl ejb,
072: ServerMetaData server, ClientMetaData client) {
073: this .ejb = ejb;
074: this .server = server;
075: this .client = client;
076: Class remoteInterface = ejb.getRemoteInterfaceClass();
077: remote = remoteInterface != null
078: && (EJBObject.class.isAssignableFrom(remoteInterface) || EJBHome.class
079: .isAssignableFrom(remoteInterface));
080: }
081:
082: public EJBInvocationHandler(EJBMetaDataImpl ejb,
083: ServerMetaData server, ClientMetaData client,
084: Object primaryKey) {
085: this (ejb, server, client);
086: this .primaryKey = primaryKey;
087: }
088:
089: public EJBMetaDataImpl getEjb() {
090: return ejb;
091: }
092:
093: public ServerMetaData getServer() {
094: return server;
095: }
096:
097: public ClientMetaData getClient() {
098: return client;
099: }
100:
101: public Object getPrimaryKey() {
102: return primaryKey;
103: }
104:
105: protected static Method getMethod(Class c, String method,
106: Class... params) {
107: try {
108: return c.getMethod(method, params);
109: } catch (NoSuchMethodException nse) {
110:
111: }
112: return null;
113: }
114:
115: public Object invoke(Object proxy, Method method, Object[] args)
116: throws Throwable {
117: if (isInvalidReference) {
118: if (remote
119: || java.rmi.Remote.class.isAssignableFrom(method
120: .getDeclaringClass())) {
121: throw new NoSuchObjectException("reference is invalid");
122: } else {
123: throw new NoSuchEJBException("reference is invalid");
124: }
125: }
126:
127: Object returnObj = null;
128: returnObj = _invoke(proxy, method, args);
129: return returnObj;
130: }
131:
132: protected abstract Object _invoke(Object proxy, Method method,
133: Object[] args) throws Throwable;
134:
135: protected EJBResponse request(EJBRequest req) throws Exception {
136: req.setClientIdentity(getClientIdentity());
137:
138: req.setServerHash(server.buildHash());
139:
140: EJBResponse response = new EJBResponse();
141: Client.request(req, response, server);
142: if (null != response.getServer()) {
143: server.merge(response.getServer());
144: }
145: return response;
146: }
147:
148: protected Object getClientIdentity() {
149: if (client != null) {
150: Object identity = client.getClientIdentity();
151: if (identity != null) {
152: return identity;
153: }
154: }
155:
156: return ClientSecurity.getIdentity();
157: }
158:
159: protected void invalidateReference() {
160: this .server = null;
161: this .client = null;
162: // this.ejb = null;
163: this .inProxyMap = false;
164: this .isInvalidReference = true;
165: this .primaryKey = null;
166: }
167:
168: protected static void invalidateAllHandlers(Object key) {
169:
170: Set<WeakReference<EJBInvocationHandler>> set = liveHandleRegistry
171: .remove(key);
172: if (set == null)
173: return;
174:
175: synchronized (set) {
176: for (WeakReference<EJBInvocationHandler> ref : set) {
177: EJBInvocationHandler handler = ref.get();
178: if (handler != null) {
179: handler.invalidateReference();
180: }
181: }
182: set.clear();
183: }
184: }
185:
186: protected static void registerHandler(Object key,
187: EJBInvocationHandler handler) {
188: Set<WeakReference<EJBInvocationHandler>> set = liveHandleRegistry
189: .get(key);
190:
191: if (set == null) {
192: set = new HashSet<WeakReference<EJBInvocationHandler>>();
193: Set<WeakReference<EJBInvocationHandler>> current = liveHandleRegistry
194: .putIfAbsent(key, set);
195: // someone else added the set
196: if (current != null)
197: set = current;
198: }
199:
200: synchronized (set) {
201: set.add(new WeakReference<EJBInvocationHandler>(handler));
202: }
203: }
204:
205: /**
206: * Renamed method so it shows up with a much more understandable purpose as it
207: * will be the top element in the stacktrace
208: * @param e
209: * @param method
210: */
211: protected Throwable convertException(Throwable e, Method method) {
212: if (!remote && e instanceof RemoteException) {
213: if (e instanceof TransactionRequiredException) {
214: return new TransactionRequiredLocalException(e
215: .getMessage()).initCause(getCause(e));
216: }
217: if (e instanceof TransactionRolledbackException) {
218: return new TransactionRolledbackLocalException(e
219: .getMessage()).initCause(getCause(e));
220: }
221:
222: /**
223: * If a client attempts to invoke a method on a removed bean's business interface,
224: * we must throw a javax.ejb.NoSuchEJBException. If the business interface is a
225: * remote business interface that extends java.rmi.Remote, the
226: * java.rmi.NoSuchObjectException is thrown to the client instead.
227: * See EJB 3.0, section 4.4
228: */
229: if (e instanceof NoSuchObjectException) {
230: if (java.rmi.Remote.class.isAssignableFrom(method
231: .getDeclaringClass())) {
232: return e;
233: } else {
234: return new NoSuchEJBException(e.getMessage())
235: .initCause(getCause(e));
236: }
237: }
238: if (e instanceof AccessException) {
239: return new AccessLocalException(e.getMessage())
240: .initCause(getCause(e));
241: }
242: return new EJBException(e.getMessage())
243: .initCause(getCause(e));
244: }
245:
246: if (remote && e instanceof EJBAccessException) {
247: if (e.getCause() instanceof Exception) {
248: return new AccessException(e.getMessage(),
249: (Exception) e.getCause());
250: } else {
251: return new AccessException(e.getMessage());
252: }
253: }
254: return e;
255: }
256:
257: protected Throwable getCause(Throwable e) {
258: if (e != null && e.getCause() != null) {
259: return e.getCause();
260: }
261: return e;
262: }
263: }
|