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 }