/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.ejb3.iiop; import org.jboss.classloading.spi.RealClassLoader; import org.jboss.ejb3.InitialContextFactory; import org.jboss.ejb3.annotation.IIOP; import org.jboss.ejb3.common.lang.ClassHelper; import org.jboss.ejb3.core.proxy.spi.EJB2RemoteProxyFactory; import org.jboss.ejb3.core.proxy.spi.RemoteProxyFactory; import org.jboss.ejb3.proxy.factory.ProxyFactoryHelper; import org.jboss.ejb3.session.SessionContainer; import org.jboss.iiop.CorbaORBService; import org.jboss.iiop.codebase.CodebasePolicy; import org.jboss.iiop.csiv2.CSIv2Policy; import org.jboss.iiop.rmi.InterfaceAnalysis; import org.jboss.iiop.rmi.ir.InterfaceRepository; import org.jboss.invocation.iiop.ReferenceFactory; import org.jboss.invocation.iiop.ServantRegistries; import org.jboss.invocation.iiop.ServantRegistry; import org.jboss.invocation.iiop.ServantRegistryKind; import org.jboss.logging.Logger; import org.jboss.metadata.IorSecurityConfigMetaData; import org.jboss.mx.util.MBeanProxyExt; import org.jboss.proxy.ejb.handle.HandleDelegateImpl; import org.jboss.system.Registry; import org.jboss.util.naming.NonSerializableFactory; import org.jboss.web.WebClassLoader; import org.jboss.web.WebServiceMBean; import org.omg.CORBA.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.NotFound; import org.omg.PortableServer.Current; import org.omg.PortableServer.CurrentHelper; import org.omg.PortableServer.POA; import org.omg.PortableServer.Servant; import javax.ejb.EJBHome; import javax.ejb.EJBObject; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.naming.Context; import javax.naming.NamingException; import javax.rmi.PortableRemoteObject; import java.io.Serializable; import java.lang.Object; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.URL; import java.util.List; /** * Comment * * @author <a href="mailto:carlo.dewolf@jboss.com">Carlo de Wolf</a> * @version $Revision: 99933 $ */ public class IORFactory // implements SessionProxyFactory { private static final Logger log = Logger.getLogger(IORFactory.class); private SessionContainer container; //private RemoteBinding binding; private String webServiceName = "jboss:service=WebService"; // TODO: make webServiceName configurable // after start available private String beanRepositoryIds[]; private String homeRepositoryIds[]; // private InterfaceAnalysis interfaceAnalysis; private ORB orb; // private POA poa; private POA irPoa; private InterfaceRepository iri; private ServantRegistry servantRegistry; private ServantRegistry homeServantRegistry; private WebClassLoader wcl; private ReferenceFactory referenceFactory; private ReferenceFactory homeReferenceFactory; private EJB2RemoteProxyFactory remoteProxyFactory = new EJB2RemoteProxyFactory() { public EJBObject create(Serializable id) { if(id == null) return createProxy(); else return createProxy(id); } public EJBHome createHome() { return createHomeProxy(); } }; public IORFactory(SessionContainer container) { assert container != null : "container is null"; //assert binding != null : "binding is null"; this.container = container; //this.binding = binding; } // TODO: create a default IIOP annotation private static final IIOP defaultIIOP = new IIOP() { public boolean interfaceRepositorySupported() { return false; } public String poa() { return POA_PER_SERVANT; } public Class<? extends Annotation> annotationType() { return IIOP.class; } }; public EJBHome createHomeProxy() { try { org.omg.CORBA.Object corbaRef = homeReferenceFactory.createReference(homeRepositoryIds[0]); EJBHome corbaObj = (EJBHome) PortableRemoteObject.narrow(corbaRef, EJBHome.class); return corbaObj; } catch(Exception e) { throw new RuntimeException(e); } } public EJBObject createProxy() { try { org.omg.CORBA.Object corbaRef = referenceFactory.createReference(beanRepositoryIds[0]); EJBObject corbaObj = (EJBObject) PortableRemoteObject.narrow(corbaRef, EJBObject.class); return corbaObj; } catch(Exception e) { throw new RuntimeException(e); } } public EJBObject createProxy(Object id) { try { org.omg.CORBA.Object corbaRef = referenceFactory.createReferenceWithId(id, beanRepositoryIds[0]); EJBObject corbaObj = (EJBObject) PortableRemoteObject.narrow(corbaRef, EJBObject.class); return corbaObj; } catch(Exception e) { throw new RuntimeException(e); } } private IIOP getIIOP() { IIOP iiop = container.getAnnotation(IIOP.class); if(iiop != null) return iiop; return defaultIIOP; } private String getJndiName() { return ProxyFactoryHelper.getDefaultRemoteBusinessJndiName(container); } /** * A slow method that works around a lot of hacks to return the remote interface. * @return session bean’s remote interface, if the session bean provides an EJB 2.1 remote client view. */ protected Class<?> getRemoteInterface() { Class<?> homeInterface = ProxyFactoryHelper.getRemoteHomeInterface(container); assert homeInterface != null : "homeInterface is null"; List<Method> createMethods = ClassHelper.getAllMethodsByPrefix(homeInterface, "create"); assert createMethods.size() > 0 : "no create methods on " + homeInterface; return createMethods.get(0).getReturnType(); } protected RemoteProxyFactory getRemoteProxyFactory() { return remoteProxyFactory; } private String getServantName() { // TODO: is "Servant/" a good prefix for servant name return "Servant/" + getJndiName(); } private WebServiceMBean getWebServer() throws MalformedObjectNameException { if(webServiceName == null) throw new IllegalStateException("iiop is not going to work without a web service"); return (WebServiceMBean) MBeanProxyExt.create(WebServiceMBean.class, webServiceName); } /** * Literal copy from org.jboss.proxy.ejb.IORFactory */ private void rebind(NamingContextExt ctx, String strName, org.omg.CORBA.Object obj) throws Exception { NameComponent[] name = ctx.to_name(strName); NamingContext intermediateCtx = ctx; for (int i = 0; i < name.length - 1; i++ ) { NameComponent[] relativeName = new NameComponent[] { name[i] }; try { intermediateCtx = NamingContextHelper.narrow( intermediateCtx.resolve(relativeName)); } catch (NotFound e) { intermediateCtx = intermediateCtx.bind_new_context(relativeName); } } intermediateCtx.rebind(new NameComponent[] { name[name.length - 1] }, obj); } private void removeWebClassLoader() throws MalformedObjectNameException { getWebServer().removeClassLoader(wcl); } public void setWebServiceName(String name) { this.webServiceName = name; } public void start() throws Exception { Class<?> remoteInterface = getRemoteInterface(); InterfaceAnalysis interfaceAnalysis = InterfaceAnalysis.getInterfaceAnalysis(remoteInterface); this.beanRepositoryIds = interfaceAnalysis.getAllTypeIds(); InterfaceAnalysis homeInterfaceAnalysis = null; Class homeInterface = ProxyFactoryHelper.getRemoteHomeInterface(container); if(homeInterface != null) { if(!EJBHome.class.isAssignableFrom(homeInterface)) throw new IllegalArgumentException("home interface " + homeInterface.getName() + " must extend javax.ejb.EJBHome (EJB3 4.6.8)"); homeInterfaceAnalysis = InterfaceAnalysis.getInterfaceAnalysis(homeInterface); this.homeRepositoryIds = homeInterfaceAnalysis.getAllTypeIds(); } // To allow EJB3 Stateless beans to operate we can function without a home interface. // Note that a lot of other constructs both in the deployer and this class prevent a non-homed bean to work, // so basically a bean without an EJB 2.1 remote view does not work. // Get orb and irPoa references try { orb = (ORB)InitialContextFactory.getInitialContext().lookup("java:/" + CorbaORBService.ORB_NAME); } catch (NamingException e) { throw new Exception("Cannot lookup java:/" + CorbaORBService.ORB_NAME + ": " + e); } try { irPoa = (POA)InitialContextFactory.getInitialContext().lookup("java:/" + CorbaORBService.IR_POA_NAME); } catch (NamingException e) { throw new Exception("Cannot lookup java:/" + CorbaORBService.IR_POA_NAME + ": " + e); } IIOP iiop = getIIOP(); if(iiop.interfaceRepositorySupported()) { this.iri = new InterfaceRepository(orb, irPoa, getJndiName()); iri.mapClass(remoteInterface); if(homeInterface != null) iri.mapClass(homeInterface); iri.finishBuild(); } // TODO: obtain the iiop invoker name properly ObjectName invokerName = new ObjectName("jboss:service=invoker,type=iiop"); ServantRegistries servantRegistries = (ServantRegistries) Registry.lookup(invokerName); if(servantRegistries == null) throw new Exception("can't find iiop invoker"); ServantRegistryKind registryWithTransientPOA; ServantRegistryKind registryWithPersistentPOA; if(iiop.poa().equals(IIOP.POA_PER_SERVANT)) { registryWithTransientPOA = ServantRegistryKind.TRANSIENT_POA_PER_SERVANT; registryWithPersistentPOA = ServantRegistryKind.PERSISTENT_POA_PER_SERVANT; } else if(iiop.poa().equals(IIOP.POA_SHARED)) { registryWithTransientPOA = ServantRegistryKind.SHARED_TRANSIENT_POA; registryWithPersistentPOA = ServantRegistryKind.SHARED_PERSISTENT_POA; } else throw new IllegalArgumentException("@IIOP.poa can only be 'per-servant' or 'shared'"); // Only works for session container this.servantRegistry = servantRegistries.getServantRegistry(registryWithTransientPOA); this.homeServantRegistry = servantRegistries.getServantRegistry(registryWithPersistentPOA); // TODO: why is home interface in persistent poa? // Hack in a WebCL (from org.jboss.ejb.EjbModule.initializeContainer) // TODO: seting up a WebClassLoader needs to be done somewhere where ObjectName on = container.getObjectName(); this.wcl = new EJB3IIOPWebClassLoader(on, (RealClassLoader) container.getClassloader(), getJndiName()); WebServiceMBean webServer = getWebServer(); URL[] codebaseURLs = {webServer.addClassLoader(wcl)}; wcl.setWebURLs(codebaseURLs); // setup a codebase policy, the CodebaseInterceptor will translate this to a TAG_JAVA_CODEBASE String codebaseString = wcl.getCodebaseString(); log.debug("codebase = " + codebaseString); Any codebase = orb.create_any(); codebase.insert_string(codebaseString); Policy codebasePolicy; codebasePolicy = orb.create_policy(CodebasePolicy.TYPE, codebase); // Create csiv2Policy for both home and remote containing // IorSecurityConfigMetadata Any secPolicy = orb.create_any(); // IorSecurityConfigMetaData iorSecurityConfigMetaData = // container.getBeanMetaData().getIorSecurityConfigMetaData(); IorSecurityConfigMetaData iorSecurityConfigMetaData = new IorSecurityConfigMetaData(); // TODO: make ior security configurable secPolicy.insert_Value(iorSecurityConfigMetaData); Policy csiv2Policy = orb.create_policy(CSIv2Policy.TYPE, secPolicy); Policy policies[] = { codebasePolicy, csiv2Policy }; InterfaceDef interfaceDef = null; if(iri != null) { Repository ir = iri.getReference(); interfaceDef = InterfaceDefHelper.narrow(ir.lookup_id(beanRepositoryIds[0])); } Current poaCurrent = CurrentHelper.narrow(orb.resolve_initial_references("POACurrent")); NamingContextExt ctx = getNamingContextExt(); log.debug("binding servant name " + getServantName()); Servant servant = new BeanCorbaServant(this, poaCurrent, container, interfaceDef, interfaceAnalysis); this.referenceFactory = servantRegistry.bind(getServantName(), servant, policies); EJBObject corbaObj = (EJBObject) createProxy(); rebind(ctx, getJndiName(), (org.omg.CORBA.Object) corbaObj); // TODO: use iri if(homeInterfaceAnalysis != null) { servant = new BeanCorbaServant(this, poaCurrent, container, null, homeInterfaceAnalysis); this.homeReferenceFactory = homeServantRegistry.bind(getServantName() + "Home", servant, policies); Object homeObject = createHomeProxy(); rebind(ctx, ProxyFactoryHelper.getHomeJndiName(container), (org.omg.CORBA.Object) homeObject); } // bind HandleDelegate stuff for client usage Context compCtx = (Context) InitialContextFactory.getInitialContext().lookup("java:comp"); NonSerializableFactory.rebind(compCtx, "ORB", orb); NonSerializableFactory.rebind(compCtx, "HandleDelegate", new HandleDelegateImpl()); } public void stop() throws Exception { if(homeReferenceFactory != null) { unbind(ProxyFactoryHelper.getHomeJndiName(container)); unbindHomeServant(); } unbind(getJndiName()); unbindServant(); removeWebClassLoader(); } /** * Unbind the bean from CosNaming */ private void unbind(String strName) { try { NamingContextExt corbaContext = getNamingContextExt(); NameComponent n[] = corbaContext.to_name(strName); getNamingContextExt().unbind(n); } catch(Exception e) { log.warn("unable to unbind '" + strName + "'", e); } } private void unbindHomeServant() { try { homeServantRegistry.unbind(getServantName() + "Home"); } catch(Exception e) { log.warn("unable to unbind home servant", e); } } private void unbindServant() { try { servantRegistry.unbind(getServantName()); } catch(Exception e) { log.warn("unable to unbind servant", e); } } private NamingContextExt getNamingContextExt() throws NamingException { Context initialContext = InitialContextFactory.getInitialContext(); // NOTE: eclipse editor parser crashes silently on this line (because of org.jboss.iiop.CorbaNamingService) with unknown reason // that's why this method is at the end return NamingContextExtHelper.narrow((org.omg.CORBA.Object) initialContext.lookup("java:/" + org.jboss.iiop.CorbaNamingService.NAMING_NAME)); } }