/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.tuscany.sca.binding.ejb.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.rmi.RemoteException; import java.rmi.UnexpectedException; import javax.ejb.CreateException; import javax.ejb.EJBLocalHome; import javax.naming.NamingException; import javax.rmi.CORBA.Util; import org.omg.CORBA.SystemException; import org.omg.CORBA.portable.ApplicationException; import org.omg.CORBA.portable.ObjectImpl; import org.omg.CORBA.portable.RemarshalException; import org.omg.stub.java.rmi._Remote_Stub; import org.oasisopen.sca.ServiceRuntimeException; /** * Factor class that is used to create EJB Proxies. * * @version $Rev$ $Date$ */ final class EJBObjectFactory { private EJBObjectFactory() { } /** * Get either a generated of dynamic EJB stub using the specified JNDI * properties. * <p> * The returned stub will implement the specified stubInterface Interface. * If the underlying EJB stub is not assignable from the specified * stubInterface then a proxy is used to convert between the two. * <p> * The returned EJB stub may be either the pregenerated EJB stub or a * dynamic stub. This allows a client to invoke an EJB without requiring any * of the pregenerated EJB stub classes be available in the classpath. * <p> */ static Object createStub(NamingEndpoint namingEndpoint, InterfaceInfo ejbInterface) throws NamingException, RemoteException, CreateException { EJBLocator locator = namingEndpoint.getLocator(); Object homeObject = locator.locate(namingEndpoint.getJndiName()); /* * The type of the object returned from the lookup is as follows: If the * generated stub exists on the classpath, it's an instance of that * type, otherwise, "org.omg.stub.java.rmi._Remote_Stub" or * "org.omg.stub.javax.ejb._EJBHome_Stub" */ Object stub = getEJBStub(homeObject, ejbInterface); // Cache dynamic stub only return stub; } /** * @param homeObject * @param ejbHomeClass * @return * @throws RemoteException */ private static Object getEJBStub(Object homeObject, InterfaceInfo ejbInterface) throws RemoteException, CreateException { Object stub = null; // Get the business interface of the EJB Class ejbInterfaceClass = null; try { ejbInterfaceClass = Thread.currentThread().getContextClassLoader().loadClass(ejbInterface.getName()); } catch (ClassNotFoundException e) { // ignore } if (ejbInterfaceClass != null && ejbInterfaceClass.isInstance(homeObject)) { // EJB 3 stub = homeObject; } else if (homeObject instanceof EJBLocalHome) { // Local EJB stub = createEJBLocalObject(homeObject); } else { // Handle dynamic stub if (homeObject instanceof ObjectImpl) { ObjectImpl objectImpl = (ObjectImpl)homeObject; stub = createEJBObject(objectImpl); }/** * Above checks will be satisfied if Bean is running on servers like WebSphere. With this * logic, client (SCA composite with EJB ref binding) doesn't need to include home class or * client stubs. * * Below check is needed SCA composite with EJB ref binding is accessing openEJB implementation. * For e.g if the bean is running on Geronimo. */ else if ((javax.rmi.PortableRemoteObject.narrow(homeObject, javax.ejb.EJBHome.class)) instanceof javax.ejb.EJBHome) { stub = createEJBObjectFromHome(homeObject); } else throw new ServiceRuntimeException("Invalid stub type: " + homeObject.getClass()); } return stub; } /** * Create a pre-generated EJB stub * * @param homeObject * @return * @throws RemoteException */ static private Object createEJBLocalObject(Object homeObject) throws RemoteException { Object stub = null; try { // Find the "create()" method Method createMethod = homeObject.getClass().getMethod("create", null); // Create an EJB object stub = createMethod.invoke(homeObject, null); } catch (NoSuchMethodException e) { // "create()" method not found, it's still a dynamic stub stub = null; } catch (InvocationTargetException e) { throw new RemoteException(e.getTargetException().toString()); } catch (Exception e) { throw new RemoteException(e.toString()); } return stub; } /** * Here homeObject is instance of EJBHome * * @param homeObject * @return * @throws RemoteException */ private static Object createEJBObjectFromHome(Object homeObject) throws RemoteException { Object stub = null; try { // Find the "create()" method Method createMethod = homeObject.getClass().getMethod("create", null); // Create an EJB object stub = createMethod.invoke(homeObject, null); } catch (NoSuchMethodException e) { // "create()" method not found, it's still a dynamic stub stub = null; } catch (InvocationTargetException e) { throw new RemoteException(e.getTargetException().toString()); } catch (Exception e) { throw new RemoteException(e.toString()); } return stub; } /** * Create an EJBObject using RMI/IIOP APIs * * @param ejbHomeObject * @return The EJBObject remote stub * @throws CreateException * @throws RemoteException */ private static Object createEJBObject(ObjectImpl ejbHomeObject) throws CreateException, RemoteException { try { org.omg.CORBA_2_3.portable.InputStream in = null; try { org.omg.CORBA.portable.OutputStream out = ejbHomeObject._request("create", true); in = (org.omg.CORBA_2_3.portable.InputStream)ejbHomeObject._invoke(out); // The Remote stub should be available in JDK // TODO: [rfeng] Work around an issue in Apache Yoko which doesn't understand the org.omg.stub.* return in.read_Object(_Remote_Stub.class); } catch (ApplicationException ex) { in = (org.omg.CORBA_2_3.portable.InputStream)ex.getInputStream(); String id = in.read_string(); if (id.equals("IDL:javax/ejb/CreateEx:1.0")) { throw (CreateException)in.read_value(CreateException.class); } throw new UnexpectedException(id); } catch (RemarshalException ex) { return createEJBObject(ejbHomeObject); } finally { ejbHomeObject._releaseReply(in); } } catch (SystemException ex) { throw Util.mapSystemException(ex); } } }