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.geronimo.corba;
017:
018: import java.lang.reflect.Method;
019: import java.rmi.AccessException;
020: import java.rmi.MarshalException;
021: import java.rmi.NoSuchObjectException;
022: import java.rmi.RemoteException;
023: import java.util.HashMap;
024: import java.util.Vector;
025: import java.util.Map;
026:
027: import javax.ejb.EJBHome;
028: import javax.ejb.EJBObject;
029: import javax.ejb.Handle;
030: import javax.ejb.RemoveException;
031: import javax.naming.Context;
032: import javax.naming.NamingException;
033: import javax.rmi.PortableRemoteObject;
034: import javax.transaction.InvalidTransactionException;
035: import javax.transaction.TransactionRequiredException;
036: import javax.transaction.TransactionRolledbackException;
037:
038: import org.apache.commons.logging.Log;
039: import org.apache.commons.logging.LogFactory;
040: import org.apache.geronimo.naming.enc.EnterpriseNamingContext;
041: import org.apache.geronimo.naming.java.RootContext;
042: import org.apache.geronimo.openejb.EjbDeployment;
043: import org.apache.openejb.InterfaceType;
044: import org.apache.openejb.BeanType;
045: import org.apache.openejb.RpcContainer;
046: import org.apache.openejb.OpenEJBException;
047: import org.apache.openejb.ProxyInfo;
048: import org.apache.geronimo.corba.util.Util;
049: import org.omg.CORBA.INVALID_TRANSACTION;
050: import org.omg.CORBA.MARSHAL;
051: import org.omg.CORBA.NO_PERMISSION;
052: import org.omg.CORBA.OBJECT_NOT_EXIST;
053: import org.omg.CORBA.ORB;
054: import org.omg.CORBA.SystemException;
055: import org.omg.CORBA.TRANSACTION_REQUIRED;
056: import org.omg.CORBA.TRANSACTION_ROLLEDBACK;
057: import org.omg.CORBA.UNKNOWN;
058: import org.omg.CORBA.portable.InputStream;
059: import org.omg.CORBA.portable.InvokeHandler;
060: import org.omg.CORBA.portable.OutputStream;
061: import org.omg.CORBA.portable.ResponseHandler;
062: import org.omg.CORBA.portable.UnknownException;
063: import org.omg.PortableServer.Servant;
064:
065: /**
066: * @version $Revision: 494431 $ $Date: 2007-01-09 07:18:14 -0800 (Tue, 09 Jan 2007) $
067: */
068: public class StandardServant extends Servant implements InvokeHandler {
069: private static final Log log = LogFactory
070: .getLog(StandardServant.class);
071:
072: private static final Method GETEJBMETADATA = getMethod(
073: EJBHome.class, "getEJBMetaData", null);
074: private static final Method GETHOMEHANDLE = getMethod(
075: EJBHome.class, "getHomeHandle", null);
076: private static final Method REMOVE_W_KEY = getMethod(EJBHome.class,
077: "remove", new Class[] { Object.class });
078: private static final Method REMOVE_W_HAND = getMethod(
079: EJBHome.class, "remove", new Class[] { Handle.class });
080: private static final Method GETEJBHOME = getMethod(EJBObject.class,
081: "getEJBHome", null);
082: private static final Method GETHANDLE = getMethod(EJBObject.class,
083: "getHandle", null);
084: private static final Method GETPRIMARYKEY = getMethod(
085: EJBObject.class, "getPrimaryKey", null);
086: private static final Method ISIDENTICAL = getMethod(
087: EJBObject.class, "isIdentical",
088: new Class[] { EJBObject.class });
089: private static final Method REMOVE = getMethod(EJBObject.class,
090: "remove", null);
091:
092: private final InterfaceType interfaceType;
093: private final EjbDeployment ejbDeployment;
094: private final Object primaryKey;
095: private final String[] typeIds;
096: private final Map operations;
097: private final Context enc;
098:
099: public StandardServant(ORB orb, InterfaceType ejbInterfaceType,
100: EjbDeployment ejbDeployment) {
101: this (orb, ejbInterfaceType, ejbDeployment, null);
102: }
103:
104: public StandardServant(ORB orb, InterfaceType ejbInterfaceType,
105: EjbDeployment ejbDeployment, Object primaryKey) {
106: this .interfaceType = ejbInterfaceType;
107: this .ejbDeployment = ejbDeployment;
108: this .primaryKey = primaryKey;
109:
110: // get the interface class
111: Class type;
112: if (InterfaceType.EJB_HOME == ejbInterfaceType) {
113: type = ejbDeployment.getHomeInterface();
114: if (type == null) {
115: throw new IllegalArgumentException("EJB "
116: + ejbDeployment.getEjbName()
117: + " does not have a home interface");
118: }
119: } else if (InterfaceType.EJB_OBJECT == ejbInterfaceType) {
120: type = ejbDeployment.getRemoteInterface();
121: if (type == null) {
122: throw new IllegalArgumentException("EJB "
123: + ejbDeployment.getEjbName()
124: + " does not have a remote interface");
125: }
126: } else {
127: throw new IllegalArgumentException(
128: "Only home and remote interfaces are supported in this servant: "
129: + ejbInterfaceType);
130: }
131:
132: // build the operations index
133: this .operations = Util.mapOperationToMethod(type);
134:
135: // creat the corba ids array
136: typeIds = Util.createCorbaIds(type);
137:
138: // create ReadOnlyContext
139: Map componentContext = new HashMap(2);
140: componentContext.put("ORB", orb);
141: componentContext.put("HandleDelegate",
142: new CORBAHandleDelegate());
143: try {
144: enc = EnterpriseNamingContext
145: .createEnterpriseNamingContext(componentContext);
146: } catch (NamingException e) {
147: throw new RuntimeException(
148: "Error creating standard servant naming context", e);
149: }
150: }
151:
152: public InterfaceType getInterfaceType() {
153: return interfaceType;
154: }
155:
156: public EjbDeployment getEjbDeployment() {
157: return ejbDeployment;
158: }
159:
160: public Object getPrimaryKey() {
161: return primaryKey;
162: }
163:
164: public String[] _all_interfaces(org.omg.PortableServer.POA poa,
165: byte[] objectId) {
166: return typeIds;
167: }
168:
169: public OutputStream _invoke(String operationName, InputStream _in,
170: ResponseHandler reply) throws SystemException {
171: // get the method object
172: Method method = (Method) operations.get(operationName);
173:
174: org.omg.CORBA_2_3.portable.InputStream in = (org.omg.CORBA_2_3.portable.InputStream) _in;
175:
176: ClassLoader oldClassLoader = Thread.currentThread()
177: .getContextClassLoader();
178: Context oldContext = RootContext.getComponentContext();
179: try {
180: Thread.currentThread().setContextClassLoader(
181: ejbDeployment.getClassLoader());
182: RootContext.setComponentContext(enc);
183:
184: // read in all of the arguments
185: Class[] parameterTypes = method.getParameterTypes();
186: Object[] arguments = new Object[parameterTypes.length];
187: for (int i = 0; i < parameterTypes.length; i++) {
188: Class parameterType = parameterTypes[i];
189: arguments[i] = Util.readObject(parameterType, in);
190: }
191:
192: // invoke the method
193: Object result = null;
194: try {
195:
196: if (log.isDebugEnabled())
197: log.debug("Calling " + method.getName());
198:
199: if (method.getDeclaringClass() == javax.ejb.EJBObject.class) {
200: if (method.equals(GETHANDLE)) {
201: result = ejbDeployment.getEjbObject(primaryKey)
202: .getHandle();
203: } else if (method.equals(GETPRIMARYKEY)) {
204: result = ejbDeployment.getEjbObject(primaryKey)
205: .getPrimaryKey();
206: } else if (method.equals(ISIDENTICAL)) {
207: org.omg.CORBA.Object this Object = this
208: ._this _object();
209: org.omg.CORBA.Object otherObject = (org.omg.CORBA.Object) arguments[0];
210: result = new Boolean(this Object
211: ._is_equivalent(otherObject));
212: } else if (method.equals(GETEJBHOME)) {
213: result = ejbDeployment.getEJBHome();
214: } else if (method.equals(REMOVE)) {
215: try {
216: ejbDeployment.getEjbObject(primaryKey)
217: .remove();
218: result = null;
219: } catch (RemoveException e) {
220: return Util.writeUserException(method,
221: reply, e);
222: }
223: } else {
224: throw new UnsupportedOperationException(
225: "unknown method: " + method);
226: }
227: } else if (method.getDeclaringClass() == javax.ejb.EJBHome.class) {
228: if (method.equals(GETEJBMETADATA)) {
229: result = ejbDeployment.getEJBHome()
230: .getEJBMetaData();
231: } else if (method.equals(GETHOMEHANDLE)) {
232: result = ejbDeployment.getEJBHome()
233: .getHomeHandle();
234: } else if (method.equals(REMOVE_W_HAND)) {
235: CORBAHandle handle = (CORBAHandle) arguments[0];
236: try {
237: if (ejbDeployment.getComponentType() == BeanType.STATELESS) {
238: if (handle == null) {
239: throw new RemoveException(
240: "Handle is null");
241: }
242: Class remoteInterface = ejbDeployment
243: .getRemoteInterface();
244:
245: try {
246: EJBObject narrowed = (EJBObject) PortableRemoteObject
247: .narrow(handle
248: .getEJBObject(),
249: remoteInterface);
250: if (narrowed == null) {
251: throw new RemoteException(
252: "Handle does not hold a "
253: + remoteInterface
254: .getName());
255: }
256: } catch (ClassCastException e) {
257: throw new RemoteException(
258: "Handle does not hold a "
259: + remoteInterface
260: .getName(),
261: e);
262: }
263: } else {
264: try {
265: Object handleKey = handle
266: .getPrimaryKey();
267: RpcContainer container = (RpcContainer) ejbDeployment
268: .getContainer();
269: result = container.invoke(
270: ejbDeployment
271: .getDeploymentId(),
272: method, arguments,
273: handleKey, null);
274: } catch (OpenEJBException e) {
275: Throwable cause = e.getCause();
276: if (cause instanceof Exception) {
277: Exception exception = (Exception) cause;
278: return Util.writeUserException(
279: method, reply,
280: exception);
281: }
282: throw cause;
283: }
284: }
285: } catch (RemoveException e) {
286:
287: return Util.writeUserException(method,
288: reply, e);
289: }
290: result = null;
291: } else if (method.equals(REMOVE_W_KEY)) {
292: try {
293: ejbDeployment.getEJBHome().remove(
294: arguments[0]);
295: result = null;
296: } catch (RemoveException e) {
297: return Util.writeUserException(method,
298: reply, e);
299: }
300: } else {
301: throw new UnsupportedOperationException(
302: "unknown method: " + method);
303: }
304: } else {
305: try {
306: RpcContainer container = (RpcContainer) ejbDeployment
307: .getContainer();
308: result = container.invoke(ejbDeployment
309: .getDeploymentId(), method, arguments,
310: primaryKey, null);
311: // some methods like create() or find* return ProxyInfo objects. We need to
312: // turn those into real EJB remote references.
313: if (result instanceof ProxyInfo
314: || method.getName().startsWith("find")) {
315: result = createProxy(result);
316: }
317: } catch (OpenEJBException e) {
318: Throwable cause = e.getCause();
319: if (cause instanceof Exception) {
320: Exception exception = (Exception) cause;
321: return Util.writeUserException(method,
322: reply, exception);
323: }
324: throw cause;
325: }
326: }
327: } catch (TransactionRolledbackException e) {
328: log.debug("TransactionRolledbackException", e);
329: throw (SystemException) new TRANSACTION_ROLLEDBACK(e
330: .toString()).initCause(e);
331: } catch (TransactionRequiredException e) {
332: log.debug("TransactionRequiredException", e);
333: throw (SystemException) new TRANSACTION_REQUIRED(e
334: .toString()).initCause(e);
335: } catch (InvalidTransactionException e) {
336: log.debug("InvalidTransactionException", e);
337: throw (SystemException) new INVALID_TRANSACTION(e
338: .toString()).initCause(e);
339: } catch (NoSuchObjectException e) {
340: log.debug("NoSuchObjectException", e);
341: throw (SystemException) new OBJECT_NOT_EXIST(e
342: .toString()).initCause(e);
343: } catch (AccessException e) {
344: log.debug("AccessException", e);
345: throw (SystemException) new NO_PERMISSION(e.toString())
346: .initCause(e);
347: } catch (MarshalException e) {
348: log.debug("MarshalException", e);
349: throw (SystemException) new MARSHAL(e.toString())
350: .initCause(e);
351: } catch (RemoteException e) {
352: log.debug("RemoteException", e);
353: throw (SystemException) new UnknownException(e)
354: .initCause(e);
355: } catch (RuntimeException e) {
356: log.debug("RuntimeException", e);
357: RemoteException remoteException = new RemoteException(e
358: .getClass().getName()
359: + " thrown from "
360: + ejbDeployment.getDeploymentId()
361: + ": "
362: + e.getMessage(), e);
363: throw new UnknownException(remoteException);
364: } catch (Error e) {
365: log.debug("Error", e);
366: RemoteException remoteException = new RemoteException(e
367: .getClass().getName()
368: + " thrown from "
369: + ejbDeployment.getDeploymentId()
370: + ": "
371: + e.getMessage(), e);
372: throw new UnknownException(remoteException);
373: } catch (Throwable e) {
374: log.warn("Unexpected throwable", e);
375: throw (SystemException) new UNKNOWN(
376: "Unknown exception type "
377: + e.getClass().getName() + ": "
378: + e.getMessage()).initCause(e);
379: }
380:
381: // creat the output stream
382: org.omg.CORBA_2_3.portable.OutputStream out = (org.omg.CORBA_2_3.portable.OutputStream) reply
383: .createReply();
384:
385: // write the output value
386: Util.writeObject(method.getReturnType(), result, out);
387:
388: return out;
389: } finally {
390: Thread.currentThread()
391: .setContextClassLoader(oldClassLoader);
392: RootContext.setComponentContext(oldContext);
393: }
394: }
395:
396: private static Method getMethod(Class c, String method,
397: Class[] params) {
398: try {
399: return c.getMethod(method, params);
400: } catch (NoSuchMethodException e) {
401: throw (IllegalStateException) new IllegalStateException()
402: .initCause(e);
403: }
404: }
405:
406: /**
407: * Convert ProxyInfo items in a create* or find* result
408: * for returning as a corba result.
409: *
410: * @param retValue The return value.
411: *
412: * @return A CORBA compatible return result.
413: * @exception Throwable
414: */
415: protected Object createProxy(Object retValue) throws Throwable {
416: if (retValue instanceof java.util.Collection) {
417: Object[] proxyInfos = ((java.util.Collection) retValue)
418: .toArray();
419: Vector proxies = new Vector();
420: for (int i = 0; i < proxyInfos.length; i++) {
421: ProxyInfo proxyInfo = (ProxyInfo) proxyInfos[i];
422: proxies.addElement(Util.getEJBProxy(proxyInfo));
423: }
424: return proxies;
425: } else if (retValue instanceof org.apache.openejb.util.ArrayEnumeration) {
426: org.apache.openejb.util.ArrayEnumeration enumeration = (org.apache.openejb.util.ArrayEnumeration) retValue;
427: for (int i = enumeration.size() - 1; i >= 0; --i) {
428: ProxyInfo proxyInfo = ((ProxyInfo) enumeration.get(i));
429: enumeration.set(i, Util.getEJBProxy(proxyInfo));
430: }
431: return enumeration;
432: } else if (retValue instanceof java.util.Enumeration) {
433: java.util.Enumeration enumeration = (java.util.Enumeration) retValue;
434:
435: java.util.List proxies = new java.util.ArrayList();
436: while (enumeration.hasMoreElements()) {
437: ProxyInfo proxyInfo = ((ProxyInfo) enumeration
438: .nextElement());
439: proxies.add(Util.getEJBProxy(proxyInfo));
440: }
441: return new org.apache.openejb.util.ArrayEnumeration(proxies);
442: } else {
443: org.apache.openejb.ProxyInfo proxyInfo = (org.apache.openejb.ProxyInfo) retValue;
444: return Util.getEJBProxy(proxyInfo);
445: }
446:
447: }
448: }
|