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