/* * JBoss, Home of Professional Open Source. * Copyright 2008, 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.invocation.iiop; import java.net.InetAddress; import java.util.Collections; import java.util.Map; import java.util.HashMap; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.omg.CORBA.LocalObject; import org.omg.CORBA.Policy; import org.omg.CORBA.SetOverrideType; import org.omg.CORBA.UNKNOWN; import org.omg.PortableServer.IdAssignmentPolicyValue; import org.omg.PortableServer.IdUniquenessPolicyValue; import org.omg.PortableServer.LifespanPolicyValue; import org.omg.PortableServer.POA; import org.omg.PortableServer.POAManagerPackage.AdapterInactive; import org.omg.PortableServer.RequestProcessingPolicyValue; import org.omg.PortableServer.Servant; import org.omg.PortableServer.ServantLocator; import org.omg.PortableServer.ServantLocatorPackage.CookieHolder; import org.omg.PortableServer.ServantRetentionPolicyValue; import org.jboss.iiop.CorbaORBService; import org.jboss.naming.Util; import org.jboss.system.ServiceMBeanSupport; import org.jboss.system.Registry; /** * IIOP invoker that routs IIOP requests to CORBA servants. * It implements the interface <code>ServantRegistries</code>, which * gives access to four <code>ServantRegistry</code> instances: * <ul> * <li>a <code>ServantRegistry</code> with a single transient POA * shared among all its servants;</li> * <li>a <code>ServantRegistry</code> with a single persistent POA * shared among all its servants;</li> * <li>a <code>ServantRegistry</code> with a transient POA per servant;</li> * <li>a <code>ServantRegistry</code> with persistent POA per servant.</li> * </ul> * * CORBA servants registered with any of these * <code>ServantRegistry</code> instances will receive IIOP invocations. * These CORBA servants will typically be thin wrappers that merely forward * to the JBoss MBean server any invocations they receive. * * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a> * @version $Revision: 81018 $ */ public class IIOPInvoker extends ServiceMBeanSupport implements IIOPInvokerMBean, ServantRegistries, ObjectFactory { // Attributes ------------------------------------------------------------- /** A reference to the singleton IIOPInvoker. */ private static IIOPInvoker theIIOPInvoker; /** The root POA. **/ private POA rootPOA; /** A ServantRegistry with a transient POA shared by all servants. */ private ServantRegistry registryWithSharedTransientPOA; /** The transient POA used by the ServantRegistry above. */ private POA transientPOA; /** The transient servant map used by the ServantRegistry above. */ private Map transientServantMap; /** A ServantRegistry with a persistent POA shared by all servants. */ private ServantRegistry registryWithSharedPersistentPOA; /** The persistent POA used by the ServantRegistry above. */ private POA persistentPOA; /** The persistent servant map used by the ServantRegistry above. */ private Map persistentServantMap; /** A ServantRegistry with a transient POA per servant. */ private ServantRegistry registryWithTransientPOAPerServant; /** The transient POA map used by the ServantRegistry above. */ private Map transientPoaMap; /** POA policies used by the ServantRegistry above. */ private Policy[] transientPoaPolicies; /** A ServantRegistry with a persistent POA per servant. */ private ServantRegistry registryWithPersistentPOAPerServant; /** The persistent POA map used by the ServantRegistry above. */ private Map persistentPoaMap; /** POA policies used by the ServantRegistry above. */ private Policy[] persistentPoaPolicies; // ServiceMBeanSupport overrides --------------------------------- public void createService() throws Exception { theIIOPInvoker = this; transientServantMap = Collections.synchronizedMap(new HashMap()); persistentServantMap = Collections.synchronizedMap(new HashMap()); transientPoaMap = Collections.synchronizedMap(new HashMap()); persistentPoaMap = Collections.synchronizedMap(new HashMap()); } public void startService() throws Exception { // Get a reference for the root POA try { rootPOA = (POA)new InitialContext().lookup("java:/" + CorbaORBService.POA_NAME); } catch (NamingException e) { throw new RuntimeException("Cannot lookup java:/" + CorbaORBService.POA_NAME + ": " + e); } // Policies for per-servant transient POAs transientPoaPolicies = new Policy[] { rootPOA.create_lifespan_policy( LifespanPolicyValue.TRANSIENT), rootPOA.create_id_assignment_policy( IdAssignmentPolicyValue.USER_ID), rootPOA.create_servant_retention_policy( ServantRetentionPolicyValue.NON_RETAIN), rootPOA.create_request_processing_policy( RequestProcessingPolicyValue.USE_DEFAULT_SERVANT), rootPOA.create_id_uniqueness_policy( IdUniquenessPolicyValue.MULTIPLE_ID), }; // Policies for per-servant persistent POAs persistentPoaPolicies = new Policy[] { rootPOA.create_lifespan_policy( LifespanPolicyValue.PERSISTENT), rootPOA.create_id_assignment_policy( IdAssignmentPolicyValue.USER_ID), rootPOA.create_servant_retention_policy( ServantRetentionPolicyValue.NON_RETAIN), rootPOA.create_request_processing_policy( RequestProcessingPolicyValue.USE_DEFAULT_SERVANT), rootPOA.create_id_uniqueness_policy( IdUniquenessPolicyValue.MULTIPLE_ID), }; // Policies for this IIOPInvoker's shared transient POA Policy[] policies = new Policy[] { rootPOA.create_lifespan_policy( LifespanPolicyValue.TRANSIENT), rootPOA.create_id_assignment_policy( IdAssignmentPolicyValue.USER_ID), rootPOA.create_servant_retention_policy( ServantRetentionPolicyValue.NON_RETAIN), rootPOA.create_request_processing_policy( RequestProcessingPolicyValue.USE_SERVANT_MANAGER), rootPOA.create_id_uniqueness_policy( IdUniquenessPolicyValue.MULTIPLE_ID) }; // Create this IIOPInvoker's shared transient POA // and set its servant locator transientPOA = rootPOA.create_POA("TPOA", null, policies); transientPOA.set_servant_manager(new TransientServantLocator()); // Change just one policy for this IIOPInvoker's shared persistent POA policies[0] = rootPOA.create_lifespan_policy( LifespanPolicyValue.PERSISTENT); // Create this IIOPInvoker's shared persisten POA // and set its servant locator persistentPOA = rootPOA.create_POA("PPOA", null, policies); persistentPOA.set_servant_manager(new PersistentServantLocator()); // Create this IIOPInvoker's ServantRegistry implementations registryWithSharedTransientPOA = new ServantRegistryWithSharedTransientPOA(); registryWithSharedPersistentPOA = new ServantRegistryWithSharedPersistentPOA(); registryWithTransientPOAPerServant = new ServantRegistryWithTransientPOAPerServant(); registryWithPersistentPOAPerServant = new ServantRegistryWithPersistentPOAPerServant(); // Export this invoker Registry.bind(getServiceName(), this); // Activate my shared POAs transientPOA.the_POAManager().activate(); persistentPOA.the_POAManager().activate(); Context context = new InitialContext(); // Bind the invoker in the JNDI invoker naming space Util.rebind( // The context context, // It should look like so "invokers/<name>/iiop" "invokers/" + InetAddress.getLocalHost().getHostName() + "/iiop", // A reference to this invoker new Reference(getClass().getName(), getClass().getName(), null)); getLog().debug("Bound IIOP invoker for JMX node"); } public void stopService() throws Exception { // Destroy my shared POAs try { transientPOA.the_POAManager().deactivate( false, /* etherealize_objects */ true /* wait_for_completion */ ); persistentPOA.the_POAManager().deactivate( false, /* etherealize_objects */ true /* wait_for_completion */ ); transientPOA.destroy(false, /* etherealize_objects */ false /* wait_for_completion */ ); persistentPOA.destroy(false, /* etherealize_objects */ false /* wait_for_completion */ ); } catch (AdapterInactive adapterInactive) { getLog().error("Cannot deactivate home POA", adapterInactive); } } // Auxiliary static methods ----------------------------------------------- private static Policy[] concatPolicies(Policy[] policies1, Policy[] policies2) { Policy[] policies = new Policy[policies1.length + policies2.length]; int j = 0; for (int i = 0; i < policies1.length; i++, j++) { policies[j] = policies1[i]; } for (int i = 0; i < policies2.length; i++, j++) { policies[j] = policies2[i]; } return policies; } // Implementation of the interface ServantRegistries ----------------------- public ServantRegistry getServantRegistry(ServantRegistryKind kind) { if (kind == ServantRegistryKind.SHARED_TRANSIENT_POA) { return registryWithSharedTransientPOA; } else if (kind == ServantRegistryKind.SHARED_PERSISTENT_POA) { return registryWithSharedPersistentPOA; } else if (kind == ServantRegistryKind.TRANSIENT_POA_PER_SERVANT) { return registryWithTransientPOAPerServant; } else if (kind == ServantRegistryKind.PERSISTENT_POA_PER_SERVANT) { return registryWithPersistentPOAPerServant; } else { return null; } } // Implementation of the interface ObjectFactory --------------------------- public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { String s = name.toString(); if (getLog().isTraceEnabled()) getLog().trace("getObjectInstance: obj.getClass().getName=\"" + obj.getClass().getName() + "\n name=" + s); if (s.equals("iiop")) return theIIOPInvoker; else return null; } // Static nested classes that implement the interface ReferenceFactory ----- static class PoaAndPoliciesReferenceFactory implements ReferenceFactory { private POA poa; private String servantName; private Policy[] policies; private byte[] servantId; PoaAndPoliciesReferenceFactory(POA poa, String servantName, Policy[] policies) { this.poa = poa; this.servantName = servantName; this.policies = policies; servantId = ReferenceData.create(servantName); } PoaAndPoliciesReferenceFactory(POA poa, Policy[] policies) { this(poa, null, policies); } public org.omg.CORBA.Object createReference(String interfId) throws Exception { org.omg.CORBA.Object corbaRef = poa.create_reference_with_id(servantId, interfId); return corbaRef._set_policy_override(policies, SetOverrideType.ADD_OVERRIDE); } public org.omg.CORBA.Object createReferenceWithId(Object id, String interfId) throws Exception { byte[] referenceData = (servantName == null) ? ReferenceData.create(id) : ReferenceData.create(servantName, id); org.omg.CORBA.Object corbaRef = poa.create_reference_with_id(referenceData, interfId); return corbaRef._set_policy_override(policies, SetOverrideType.ADD_OVERRIDE); } public POA getPOA() { return poa; } } static class PoaReferenceFactory implements ReferenceFactory { private POA poa; private String servantName; private byte[] servantId; PoaReferenceFactory(POA poa, String servantName) { this.poa = poa; this.servantName = servantName; servantId = ReferenceData.create(servantName); } PoaReferenceFactory(POA poa) { this(poa, null); } public org.omg.CORBA.Object createReference(String interfId) throws Exception { return poa.create_reference_with_id(servantId, interfId); } public org.omg.CORBA.Object createReferenceWithId(Object id, String interfId) throws Exception { byte[] referenceData = (servantName == null) ? ReferenceData.create(id) : ReferenceData.create(servantName, id); return poa.create_reference_with_id(referenceData, interfId); } public POA getPOA() { return poa; } } // Inner classes that implement the interface ServantRegistry -------------- /** ServantRegistry with a shared transient POA */ class ServantRegistryWithSharedTransientPOA implements ServantRegistry { public ReferenceFactory bind(String name, Servant servant, Policy[] policies) { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } transientServantMap.put(name, servant); return new PoaAndPoliciesReferenceFactory(transientPOA, name, policies); } public ReferenceFactory bind(String name, Servant servant) { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } transientServantMap.put(name, servant); return new PoaReferenceFactory(transientPOA, name); } public void unbind(String name) { transientServantMap.remove(name); } } /** ServantRegistry with a shared persistent POA */ class ServantRegistryWithSharedPersistentPOA implements ServantRegistry { public ReferenceFactory bind(String name, Servant servant, Policy[] policies) { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } persistentServantMap.put(name, servant); return new PoaAndPoliciesReferenceFactory(persistentPOA, name, policies); } public ReferenceFactory bind(String name, Servant servant) { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } persistentServantMap.put(name, servant); return new PoaReferenceFactory(persistentPOA, name); } public void unbind(String name) { persistentServantMap.remove(name); } } /** ServantRegistry with a transient POA per servant */ class ServantRegistryWithTransientPOAPerServant implements ServantRegistry { public ReferenceFactory bind(String name, Servant servant, Policy[] policies) throws Exception { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } Policy[] poaPolicies = concatPolicies(transientPoaPolicies, policies); POA poa = rootPOA.create_POA(name, null, poaPolicies); transientPoaMap.put(name, poa); poa.set_servant(servant); poa.the_POAManager().activate(); return new PoaReferenceFactory(poa); // no servantName: in this case // name is the POA name } public ReferenceFactory bind(String name, Servant servant) throws Exception { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } POA poa = rootPOA.create_POA(name, null, transientPoaPolicies); transientPoaMap.put(name, poa); poa.set_servant(servant); poa.the_POAManager().activate(); return new PoaReferenceFactory(poa); // no servantName: in this case // name is the POA name } public void unbind(String name) throws Exception { POA poa = (POA) transientPoaMap.remove(name); if (poa != null) { poa.the_POAManager().deactivate(false, /* etherealize_objects */ true /* wait_for_completion */ ); poa.destroy(false, /* etherealize_objects */ false /* wait_for_completion */ ); } } } /** ServantRegistry with a persistent POA per servant */ class ServantRegistryWithPersistentPOAPerServant implements ServantRegistry { public ReferenceFactory bind(String name, Servant servant, Policy[] policies) throws Exception { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } Policy[] poaPolicies = concatPolicies(persistentPoaPolicies, policies); POA poa = rootPOA.create_POA(name, null, poaPolicies); persistentPoaMap.put(name, poa); poa.set_servant(servant); poa.the_POAManager().activate(); return new PoaReferenceFactory(poa); // no servantName: in this case // name is the POA name } public ReferenceFactory bind(String name, Servant servant) throws Exception { if (servant instanceof ServantWithMBeanServer) { ((ServantWithMBeanServer)servant).setMBeanServer(getServer()); } POA poa = rootPOA.create_POA(name, null, persistentPoaPolicies); persistentPoaMap.put(name, poa); poa.set_servant(servant); poa.the_POAManager().activate(); return new PoaReferenceFactory(poa); // no servantName: in this case // name is the POA name } public void unbind(String name) throws Exception { POA poa = (POA) persistentPoaMap.remove(name); if (poa != null) { poa.the_POAManager().deactivate(false, /* etherealize_objects */ true /* wait_for_completion */ ); poa.destroy(false, /* etherealize_objects */ false /* wait_for_completion */ ); } } } // Inner classes that implement the interface ServantLocator --------------- /** ServantLocator for the shared transient POA */ class TransientServantLocator extends LocalObject implements ServantLocator { public Servant preinvoke(byte[] oid, POA adapter, String operation, CookieHolder the_cookie) { try { the_cookie.value = null; Object id = ReferenceData.extractServantId(oid); return (Servant)transientServantMap.get(id); } catch (Exception e) { getLog().trace("Unexpected exception in preinvoke:", e); throw new UNKNOWN(e.toString()); } } public void postinvoke(byte[] oid, POA adapter, String operation, Object the_cookie, Servant the_servant) { } } /** ServantLocator for the shared persistent POA */ class PersistentServantLocator extends LocalObject implements ServantLocator { public Servant preinvoke(byte[] oid, POA adapter, String operation, CookieHolder the_cookie) { try { the_cookie.value = null; Object id = ReferenceData.extractServantId(oid); return (Servant)persistentServantMap.get(id); } catch (Exception e) { getLog().trace("Unexpected exception in preinvoke:", e); throw new UNKNOWN(e.toString()); } } public void postinvoke(byte[] oid, POA adapter, String operation, Object the_cookie, Servant the_servant) { } } }