You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomee.apache.org by Kevan Miller <ke...@gmail.com> on 2007/08/23 06:46:04 UTC

Re: svn commit: r565996 - in /openejb/trunk/openejb3/container/openejb-core/src: main/java/org/apache/openejb/assembler/classic/ test/java/org/apache/openejb/assembler/classic/

Joe Bohn tracked down some major tck breakage that's associated with  
this change. David, perhaps you could have a look?

--kevan

On Aug 14, 2007, at 9:25 PM, dblevins@apache.org wrote:

> Author: dblevins
> Date: Tue Aug 14 18:25:15 2007
> New Revision: 565996
>
> URL: http://svn.apache.org/viewvc?view=rev&rev=565996
> Log:
> Improved proxy creation code so that for business interfaces it  
> includes as many interfaces as possible
>
> Added:
>     openejb/trunk/openejb3/container/openejb-core/src/main/java/org/ 
> apache/openejb/assembler/classic/ProxyInterfaceResolver.java
>     openejb/trunk/openejb3/container/openejb-core/src/test/java/org/ 
> apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java
> Modified:
>     openejb/trunk/openejb3/container/openejb-core/src/main/java/org/ 
> apache/openejb/assembler/classic/JndiBuilder.java
>
> Modified: openejb/trunk/openejb3/container/openejb-core/src/main/ 
> java/org/apache/openejb/assembler/classic/JndiBuilder.java
> URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/ 
> openejb-core/src/main/java/org/apache/openejb/assembler/classic/ 
> JndiBuilder.java?view=diff&rev=565996&r1=565995&r2=565996
> ====================================================================== 
> ========
> --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/ 
> apache/openejb/assembler/classic/JndiBuilder.java (original)
> +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/ 
> apache/openejb/assembler/classic/JndiBuilder.java Tue Aug 14  
> 18:25:15 2007
> @@ -19,9 +19,11 @@
>  import javax.naming.Context;
>  import javax.naming.NamingException;
>  import javax.naming.Reference;
> +import javax.naming.NameAlreadyBoundException;
>  import javax.jms.MessageListener;
>
>  import org.apache.openejb.DeploymentInfo;
> +import org.apache.openejb.InterfaceType;
>  import org.apache.openejb.util.LogCategory;
>  import org.apache.openejb.util.Logger;
>  import org.apache.openejb.loader.SystemInstance;
> @@ -36,6 +38,7 @@
>  import java.util.ArrayList;
>  import java.util.Map;
>  import java.util.HashMap;
> +import java.util.Comparator;
>
>
>  /**
> @@ -77,7 +80,58 @@
>
>          public static enum Interface {
>
> -            REMOTE_HOME, LOCAL_HOME, BUSINESS_LOCAL,  
> BUSINESS_REMOTE, SERVICE_ENDPOINT
> +            REMOTE_HOME(InterfaceType.EJB_HOME, "RemoteHome",  
> "home", ""),
> +            LOCAL_HOME(InterfaceType.EJB_LOCAL_HOME, "LocalHome",  
> "local-home", "Local"),
> +            BUSINESS_LOCAL(InterfaceType.BUSINESS_LOCAL, "Local",  
> "business-local", "BusinessLocal"),
> +            BUSINESS_REMOTE(InterfaceType.BUSINESS_REMOTE,  
> "Remote", "business-remote", "BusinessRemote"),
> +            SERVICE_ENDPOINT(InterfaceType.SERVICE_ENDPOINT,  
> "Endpoint", "service-endpoint", "ServiceEndpoint");
> +
> +            private final InterfaceType type;
> +            private final String annotatedName;
> +            private final String xmlName;
> +            private final String xmlNameCc;
> +            private final String openejbLegacy;
> +
> +            Interface(InterfaceType type, String annotatedName,  
> String xmlName, String openejbLegacy) {
> +                this.type = type;
> +                this.annotatedName = annotatedName;
> +                this.xmlName = xmlName;
> +                this.xmlNameCc = camelCase(xmlName);
> +                this.openejbLegacy = openejbLegacy;
> +            }
> +
> +            private String camelCase(String string){
> +                StringBuilder sb = new StringBuilder();
> +                String[] strings = string.split("-");
> +                for (String s : strings) {
> +                    int l = sb.length();
> +                    sb.append(s);
> +                    sb.setCharAt(l, Character.toUpperCase(sb.charAt 
> (l)));
> +                }
> +                return sb.toString();
> +            }
> +
> +
> +            public InterfaceType getType() {
> +                return type;
> +            }
> +
> +            public String getAnnotatedName() {
> +                return annotatedName;
> +            }
> +
> +            public String getXmlName() {
> +                return xmlName;
> +            }
> +
> +            public String getXmlNameCc() {
> +                return xmlNameCc;
> +            }
> +
> +            public String getOpenejbLegacy() {
> +                return openejbLegacy;
> +            }
> +
>          }
>
>          public String getName(DeploymentInfo deploymentInfo, Class  
> interfce, Interface type);
> @@ -101,7 +155,10 @@
>              contextData.put("ejbClass.simpleName",  
> deploymentInfo.getBeanClass().getSimpleName());
>              contextData.put("ejbName", deploymentInfo.getEjbName());
>              contextData.put("deploymentId",  
> deploymentInfo.getDeploymentID().toString());
> -            contextData.put("interfaceType",  
> deploymentInfo.getInterfaceType(interfce).name());
> +            contextData.put("interfaceType", type.annotatedName);
> +            contextData.put("interfaceType.xmlName",  
> type.getXmlName());
> +            contextData.put("interfaceType.xmlNameCc",  
> type.getXmlNameCc());
> +            contextData.put("interfaceType.openejbLegacyName",  
> type.getOpenejbLegacy());
>              contextData.put("interfaceClass", interfce.getName());
>              contextData.put("interfaceClass.simpleName",  
> interfce.getSimpleName());
>              return template.apply(contextData);
> @@ -198,7 +255,7 @@
>              Class homeInterface = deployment.getHomeInterface();
>              if (homeInterface != null) {
>
> -                String name = "openejb/ejb/" + strategy.getName 
> (deployment, deploymentInfo.getRemoteInterface(),  
> JndiNameStrategy.Interface.REMOTE_HOME);
> +                String name = "openejb/ejb/" + strategy.getName 
> (deployment, deploymentInfo.getHomeInterface(),  
> JndiNameStrategy.Interface.REMOTE_HOME);
>                  ObjectReference ref = new ObjectReference 
> (deployment.getEJBHome());
>                  bind(name, ref, bindings, beanInfo);
>
> @@ -213,7 +270,7 @@
>              Class localHomeInterface =  
> deployment.getLocalHomeInterface();
>              if (localHomeInterface != null) {
>
> -                String name = "openejb/ejb/" + strategy.getName 
> (deployment, deploymentInfo.getLocalInterface(),  
> JndiNameStrategy.Interface.LOCAL_HOME);
> +                String name = "openejb/ejb/" + strategy.getName 
> (deployment, deploymentInfo.getLocalHomeInterface(),  
> JndiNameStrategy.Interface.LOCAL_HOME);
>                  ObjectReference ref = new ObjectReference 
> (deployment.getEJBLocalHome());
>                  bind(name, ref, bindings, beanInfo);
>
> @@ -225,25 +282,22 @@
>          }
>
>          try {
> -            Class businessLocalInterface =  
> deployment.getBusinessLocalInterface();
> -            if (businessLocalInterface != null) {
> +            List<Class> localInterfaces =  
> deployment.getBusinessLocalInterfaces();
> +            Class beanClass = deployment.getBeanClass();
>
> -                String name = "openejb/ejb/" + strategy.getName 
> (deployment, businessLocalInterface,  
> JndiNameStrategy.Interface.BUSINESS_LOCAL);
> -                DeploymentInfo.BusinessLocalHome businessLocalHome  
> = deployment.getBusinessLocalHome();
> -                bind(name, new BusinessLocalReference 
> (businessLocalHome), bindings, beanInfo);
> -
> -                for (Class interfce :  
> deployment.getBusinessLocalInterfaces()) {
> -                    DeploymentInfo.BusinessLocalHome home =  
> deployment.getBusinessLocalHome(asList(interfce));
> -                    BusinessLocalReference ref = new  
> BusinessLocalReference(home);
> -
> -                    name = "openejb/Deployment/" +  
> deployment.getDeploymentID() + "/" + interfce.getName();
> -                    bind(name, ref, bindings, beanInfo);
> -
> -                    try {
> -                        name = "openejb/ejb/" + strategy.getName 
> (deployment, interfce, JndiNameStrategy.Interface.BUSINESS_LOCAL);
> -                        bind(name, ref, bindings, beanInfo);
> -                    } catch (NamingException dontCareJustYet) {
> -                    }
> +            for (Class interfce :  
> deployment.getBusinessLocalInterfaces()) {
> +
> +                List<Class> interfaces =  
> ProxyInterfaceResolver.getInterfaces(beanClass, interfce,  
> localInterfaces);
> +                DeploymentInfo.BusinessLocalHome home =  
> deployment.getBusinessLocalHome(interfaces);
> +                BusinessLocalReference ref = new  
> BusinessLocalReference(home);
> +
> +                String internalName = "openejb/Deployment/" +  
> deployment.getDeploymentID() + "/" + interfce.getName();
> +                bind(internalName, ref, bindings, beanInfo);
> +
> +                try {
> +                    String externalName = "openejb/ejb/" +  
> strategy.getName(deployment, interfce,  
> JndiNameStrategy.Interface.BUSINESS_LOCAL);
> +                    bind(externalName, ref, bindings, beanInfo);
> +                } catch (NamingException dontCareJustYet) {
>                  }
>              }
>          } catch (NamingException e) {
> @@ -251,27 +305,23 @@
>          }
>
>          try {
> -            Class businessRemoteInterface =  
> deployment.getBusinessRemoteInterface();
> -            if (businessRemoteInterface != null) {
>
> -                DeploymentInfo.BusinessRemoteHome  
> businessRemoteHome = deployment.getBusinessRemoteHome();
> -                BusinessRemoteReference ref = new  
> BusinessRemoteReference(businessRemoteHome);
> +            List<Class> remoteInterfaces =  
> deployment.getBusinessRemoteInterfaces();
> +            Class beanClass = deployment.getBeanClass();
>
> -                String name = "openejb/ejb/" + strategy.getName 
> (deployment, businessRemoteInterface,  
> JndiNameStrategy.Interface.BUSINESS_REMOTE);
> -                bind(name, ref, bindings, beanInfo);
> +            for (Class interfce :  
> deployment.getBusinessRemoteInterfaces()) {
>
> -                for (Class interfce :  
> deployment.getBusinessRemoteInterfaces()) {
> -                    DeploymentInfo.BusinessRemoteHome home =  
> deployment.getBusinessRemoteHome(asList(interfce));
> -                    ref = new BusinessRemoteReference(home);
> -
> -                    name = "openejb/Deployment/" +  
> deployment.getDeploymentID() + "/" + interfce.getName();
> -                    bind(name, ref, bindings, beanInfo);
> -
> -                    try {
> -                        name = "openejb/ejb/" + strategy.getName 
> (deployment, interfce, JndiNameStrategy.Interface.BUSINESS_REMOTE);
> -                        bind(name, ref, bindings, beanInfo);
> -                    } catch (NamingException dontCareJustYet) {
> -                    }
> +                List<Class> interfaces =  
> ProxyInterfaceResolver.getInterfaces(beanClass, interfce,  
> remoteInterfaces);
> +                DeploymentInfo.BusinessRemoteHome home =  
> deployment.getBusinessRemoteHome(interfaces);
> +                BusinessRemoteReference ref = new  
> BusinessRemoteReference(home);
> +
> +                String internalName = "openejb/Deployment/" +  
> deployment.getDeploymentID() + "/" + interfce.getName();
> +                bind(internalName, ref, bindings, beanInfo);
> +
> +                try {
> +                    String externalName = "openejb/ejb/" +  
> strategy.getName(deployment, interfce,  
> JndiNameStrategy.Interface.BUSINESS_REMOTE);
> +                    bind(externalName, ref, bindings, beanInfo);
> +                } catch (NamingException dontCareJustYet) {
>                  }
>              }
>          } catch (NamingException e) {
> @@ -295,14 +345,26 @@
>
>
>      private void bind(String name, Reference ref, Bindings  
> bindings, EnterpriseBeanInfo beanInfo) throws NamingException {
> -        context.bind(name, ref);
> -        bindings.add(name);
> +
>          if (name.startsWith("openejb/ejb/")) {
> -            name = name.replaceFirst("openejb/ejb/", "");
> -            logger.info("Jndi(name=" + name+")");
> -            if (!beanInfo.jndiNames.contains(name)){
> -                beanInfo.jndiNames.add(name);
> +
> +            String externalName = name.replaceFirst("openejb/ 
> ejb/", "");
> +
> +            if (beanInfo.jndiNames.contains(externalName)){
> +                logger.debug("Duplicate: Jndi(name=" +  
> externalName +")");
> +                return;
>              }
> +
> +            beanInfo.jndiNames.add(externalName);
> +            logger.info("Jndi(name=" + externalName +")");
> +        }
> +
> +        try {
> +            context.bind(name, ref);
> +            bindings.add(name);
> +        } catch (NameAlreadyBoundException e) {
> +            logger.error("Jndi name could not be bound; it may be  
> taken by another ejb.  Jndi(name=" + name +")");
> +            throw e;
>          }
>      }
>
> @@ -321,6 +383,17 @@
>
>          public boolean add(String o) {
>              return bindings.add(o);
> +        }
> +    }
> +
> +    public static class RemoteInterfaceComparator implements  
> Comparator<Class> {
> +
> +        public int compare(java.lang.Class a, java.lang.Class b) {
> +            boolean aIsRmote =  
> java.rmi.Remote.class.isAssignableFrom(a);
> +            boolean bIsRmote =  
> java.rmi.Remote.class.isAssignableFrom(b);
> +
> +            if (aIsRmote == bIsRmote) return 0;
> +            return (aIsRmote)? 1: -1;
>          }
>      }
>  }
>
> Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/ 
> org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java
> URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/ 
> openejb-core/src/main/java/org/apache/openejb/assembler/classic/ 
> ProxyInterfaceResolver.java?view=auto&rev=565996
> ====================================================================== 
> ========
> --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/ 
> apache/openejb/assembler/classic/ProxyInterfaceResolver.java (added)
> +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/ 
> apache/openejb/assembler/classic/ProxyInterfaceResolver.java Tue  
> Aug 14 18:25:15 2007
> @@ -0,0 +1,205 @@
> +/**
> + * 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.openejb.assembler.classic;
> +
> +import java.util.List;
> +import java.util.ArrayList;
> +import java.lang.reflect.Method;
> +
> +/**
> + * @version $Rev$ $Date$
> + */
> +public class ProxyInterfaceResolver {
> +
> +    public static List<Class> getInterfaces(Class implementation,  
> Class mainInterface, List<Class> interfaces){
> +        List<Class> valid = new ArrayList<Class>();
> +        // The intended interface is safe to add
> +        valid.add(mainInterface);
> +
> +        // Any interface the bean implements is safe (potentially)
> +        for (Class interfce : interfaces) {
> +            if (interfce.isAssignableFrom(implementation)){
> +                valid.add(interfce);
> +            }
> +        }
> +
> +
> +        // Here comes the trick, if any of them implement  
> java.rmi.Remote
> +        // we have to check the "remote" methods against the other  
> methods
> +        // of the same name and params to see if there are any  
> conflicts in
> +        // the exception clauses.  If there are, then we need to  
> remove the
> +        // conflicting interface(s).
> +        //
> +        // DETAILS:
> +        // The trick is that two nearly matching interface methods
> +        //   -InterfaceA: void doIt() throws Foo;
> +        //   -InterfaceB: void doIt() throws Bar;
> +        //
> +        // can be implemented in a class by leaving out exceptions  
> from the
> +        // throws clause that aren't declared in both interfaces  
> methods.
> +        //   -Implementation:  void doIt(){}
> +        //
> +        // This means the implementing class can not throw Foo or  
> Bar.  The
> +        // same rule applies to proxies created from these two  
> interfaces as
> +        // the proxy generating code will automatically remove  
> exceptions
> +        // not shared by the two matching interface methods;  
> eliminating
> +        // the proxy's and therefore container's ability to throw  
> those
> +        // exceptions.
> +        //
> +        // The specific issue with java.rmi.Remote interfaces is  
> that per
> +        // spec rules many runtime exceptions (container or  
> connection issues)
> +        // are thrown to clients as java.rmi.RemoteException which  
> is not
> +        // a runtime exception and must be throwable via the proxy.
> +
> +
> +        List<Class> remotes = new ArrayList<Class>();
> +        List<Class> nonremotes = new ArrayList<Class>();
> +        for (Class interfce : valid) {
> +            if (java.rmi.Remote.class.isAssignableFrom(interfce)){
> +                remotes.add(interfce);
> +            } else {
> +                nonremotes.add(interfce);
> +            }
> +        }
> +
> +        // No remote interfaces, we're good to go
> +        if (remotes.size() == 0) return valid;
> +
> +        //  
> -----------------------------------------------------------
> +        // If we got here, we have potentially clashing interfaces
> +        // We sort of have to start over and go "slower" checking
> +        // methods for conflicts and not including those interfaces
> +        //  
> -----------------------------------------------------------
> +
> +        valid.clear();
> +        remotes.remove(mainInterface);
> +        nonremotes.remove(mainInterface);
> +
> +        // Re-add the main interface
> +        valid.add(mainInterface);
> +
> +        // Track the method signatures of the interfaces we add
> +        List<Signature> proxySignatures = getSignatures 
> (mainInterface);
> +
> +
> +        // Show affinity for the remote interfaces if the main
> +        // interface is a java.rmi.Remote
> +        if (java.rmi.Remote.class.isAssignableFrom(mainInterface)){
> +            for (Class interfce : remotes) {
> +                addIfNotConflicting(interfce, valid,  
> proxySignatures);
> +            }
> +            for (Class interfce : nonremotes) {
> +                addIfNotConflicting(interfce, valid,  
> proxySignatures);
> +            }
> +        } else {
> +            for (Class interfce : nonremotes) {
> +                addIfNotConflicting(interfce, valid,  
> proxySignatures);
> +            }
> +            for (Class interfce : remotes) {
> +                addIfNotConflicting(interfce, valid,  
> proxySignatures);
> +            }
> +        }
> +
> +        return valid;
> +    }
> +
> +    /**
> +     * Adds the interface to the list of valid interfaces for the  
> proxy
> +     * if the signatures on the interface do not conflict with the  
> method
> +     * signatures already apart of the proxy's other interfaces.
> +     *
> +     * @param interfce
> +     * @param valid
> +     * @param proxySignatures
> +     */
> +    private static void addIfNotConflicting(Class interfce,  
> List<Class> valid, List<Signature> proxySignatures) {
> +
> +        List<Signature> interfaceSigs = getSignatures(interfce);
> +
> +
> +        for (Signature sig : interfaceSigs) {
> +            // Contains will return true if the
> +            // method signature exits *and* has
> +            // a different throws clause
> +            if (proxySignatures.contains(sig)){
> +                 return;  // conflicts and cannot be added
> +            }
> +        }
> +
> +
> +        // Does not conflict, add it and track the new signatures
> +        valid.add(interfce);
> +        proxySignatures.addAll(interfaceSigs);
> +    }
> +
> +    private static List<Signature> getSignatures(Class  
> mainInterface) {
> +        List<Signature> sigs = new ArrayList<Signature>();
> +        for (Method method : mainInterface.getMethods()) {
> +            sigs.add(new Signature(mainInterface, method));
> +        }
> +        return sigs;
> +    }
> +
> +    public static class Signature {
> +        private final Class clazz;
> +        private final Method method;
> +        private final String sig;
> +
> +        public Signature(Class clazz, Method method) {
> +            this.clazz = clazz;
> +            this.method = method;
> +            StringBuilder sb = new StringBuilder();
> +            sb.append(method.getName());
> +            sb.append('(');
> +            for (Class<?> type : method.getParameterTypes()) {
> +                sb.append(type.getName());
> +                sb.append(',');
> +            }
> +            sb.append(')');
> +            sig = sb.toString();
> +        }
> +
> +        public Method getMethod() {
> +            return method;
> +        }
> +
> +        // This equals returns true only if the method signatures
> +        // are the same *and* one is remote and one is not
> +        public boolean equals(Object o) {
> +            if (this == o) return true;
> +            if (o == null || getClass() != o.getClass()) return  
> false;
> +
> +            final Signature signature = (Signature) o;
> +
> +            if (!sig.equals(signature.sig)) return false;
> +
> +            boolean aIsRemote =  
> java.rmi.Remote.class.isAssignableFrom(clazz);
> +            boolean bIsRemote =  
> java.rmi.Remote.class.isAssignableFrom(signature.clazz);
> +
> +            return !(aIsRemote == bIsRemote);
> +        }
> +
> +        public int hashCode() {
> +            return sig.hashCode();
> +        }
> +
> +        public String toString() {
> +            return method.toString();
> +        }
> +    }
> +
> +}
>
> Added: openejb/trunk/openejb3/container/openejb-core/src/test/java/ 
> org/apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java
> URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/ 
> openejb-core/src/test/java/org/apache/openejb/assembler/classic/ 
> ProxyInterfaceResolverTest.java?view=auto&rev=565996
> ====================================================================== 
> ========
> --- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/ 
> apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java  
> (added)
> +++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/ 
> apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java  
> Tue Aug 14 18:25:15 2007
> @@ -0,0 +1,144 @@
> +/**
> + * 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.openejb.assembler.classic;
> +
> +import junit.framework.TestCase;
> +
> +import java.rmi.RemoteException;
> +import java.util.Arrays;
> +import java.util.List;
> +
> +/**
> + * @version $Rev$ $Date$
> + */
> +public class ProxyInterfaceResolverTest extends TestCase {
> +    public void test() throws Exception {
> +        Class smoothie;
> +        List<Class> ingredients;
> +
> +        // No remotes
> +        smoothie = implement(Mango.class, Lime.class, Lemon.class);
> +        ingredients = resolve(smoothie, Mango.class, Lime.class,  
> Lemon.class);
> +        assertEquals(3, ingredients.size());
> +        assertTrue(ingredients.contains(Mango.class));
> +        assertTrue(ingredients.contains(Lime.class));
> +        assertTrue(ingredients.contains(Lemon.class));
> +
> +        // All remotes
> +        smoothie = implement(Cherry.class, Honey.class, Grape.class);
> +        ingredients = resolve(smoothie, Cherry.class, Honey.class,  
> Grape.class);
> +        assertEquals(3, ingredients.size());
> +        assertTrue(ingredients.contains(Cherry.class));
> +        assertTrue(ingredients.contains(Grape.class));
> +        assertTrue(ingredients.contains(Honey.class));
> +
> +        // mixed remote and non-remote, no conflicts
> +        smoothie = implement(Banana.class, Honey.class, Creme.class);
> +        ingredients = resolve(smoothie, Banana.class, Honey.class,  
> Creme.class);
> +        assertEquals(3, ingredients.size());
> +        assertTrue(ingredients.contains(Banana.class));
> +        assertTrue(ingredients.contains(Honey.class));
> +        assertTrue(ingredients.contains(Creme.class));
> +
> +        // mixed remote and non-remote, conflicts (cherry, grape)
> +        smoothie = implement(Mango.class, Banana.class,  
> Creme.class, Honey.class, Cherry.class, Grape.class);
> +        ingredients = resolve(smoothie, Mango.class, Banana.class,  
> Creme.class, Honey.class, Cherry.class, Grape.class);
> +        assertEquals(4, ingredients.size());
> +        assertTrue(ingredients.contains(Mango.class));
> +        assertTrue(ingredients.contains(Banana.class));
> +        assertTrue(ingredients.contains(Creme.class));
> +        assertTrue(ingredients.contains(Honey.class));
> +
> +        // mixed remote and non-remote, conflicts (mango, banana)
> +        smoothie = implement(Cherry.class, Mango.class,  
> Banana.class, Creme.class, Honey.class, Grape.class);
> +        ingredients = resolve(smoothie, Cherry.class, Mango.class,  
> Banana.class, Creme.class, Honey.class, Grape.class);
> +        assertEquals(4, ingredients.size());
> +        assertTrue(ingredients.contains(Cherry.class));
> +        assertTrue(ingredients.contains(Grape.class));
> +        assertTrue(ingredients.contains(Creme.class));
> +        assertTrue(ingredients.contains(Honey.class));
> +    }
> +
> +    public List<Class> resolve(Class impl, Class mainInterface,  
> Class... interfaces) {
> +        return ProxyInterfaceResolver.getInterfaces(impl,  
> mainInterface, Arrays.asList(interfaces));
> +    }
> +
> +
> +    public Class implement(Class<?>... interfaces) {
> +        return java.lang.reflect.Proxy.getProxyClass(this.getClass 
> ().getClassLoader(), interfaces);
> +    }
> +
> +    public interface Mango {
> +        void exist() throws RoundException, GreenException;
> +
> +        void mango();
> +    }
> +
> +    public interface Lime {
> +        void exist() throws RoundException, GreenException;
> +
> +        void lime();
> +    }
> +
> +    public interface Lemon {
> +        void exist() throws RoundException, YellowException;
> +
> +        void lemon();
> +    }
> +
> +    public interface Banana {
> +        void exist() throws LongException, YellowException;
> +
> +        void banana();
> +    }
> +
> +    public interface Creme {
> +        void thiken();
> +    }
> +
> +    public interface Cherry extends java.rmi.Remote {
> +        void exist() throws RoundException, RemoteException;
> +
> +        void cherry() throws RemoteException;
> +    }
> +
> +    public interface Grape extends java.rmi.Remote {
> +        void exist() throws RoundException, RemoteException;
> +
> +        void grape() throws RemoteException;
> +    }
> +
> +    public interface Honey extends java.rmi.Remote {
> +        void sweeten() throws RemoteException;
> +    }
> +
> +    //--------------//
> +    public static class RoundException extends Exception {
> +    }
> +
> +    public static class GreenException extends Exception {
> +    }
> +
> +    public static class YellowException extends Exception {
> +    }
> +
> +    public static class LongException extends Exception {
> +    }
> +
> +
> +}
> +
>
>


Re: svn commit: r565996 - in /openejb/trunk/openejb3/container/openejb-core/src: main/java/org/apache/openejb/assembler/classic/ test/java/org/apache/openejb/assembler/classic/

Posted by David Blevins <da...@visi.com>.
Looking into it.  Thanks for the heads up.

-David

On Aug 23, 2007, at 6:32 AM, Joe Bohn wrote:

> Thanks Kevan ... I should have thought to put this on the openejb  
> list myself.
>
> David,  There are some more details on the geronimo tck list where  
> you can see the failing tests and a little info on the failure.
>
> Thanks,
> Joe
>
>
> Kevan Miller wrote:
>> Joe Bohn tracked down some major tck breakage that's associated  
>> with this change. David, perhaps you could have a look?
>> --kevan
>> On Aug 14, 2007, at 9:25 PM, dblevins@apache.org wrote:
>>> Author: dblevins
>>> Date: Tue Aug 14 18:25:15 2007
>>> New Revision: 565996
>>>
>>> URL: http://svn.apache.org/viewvc?view=rev&rev=565996
>>> Log:
>>> Improved proxy creation code so that for business interfaces it  
>>> includes as many interfaces as possible
>>>
>>> Added:
>>>     openejb/trunk/openejb3/container/openejb-core/src/main/java/ 
>>> org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java
>>>     openejb/trunk/openejb3/container/openejb-core/src/test/java/ 
>>> org/apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java
>>> Modified:
>>>     openejb/trunk/openejb3/container/openejb-core/src/main/java/ 
>>> org/apache/openejb/assembler/classic/JndiBuilder.java
>>>
>>> Modified: openejb/trunk/openejb3/container/openejb-core/src/main/ 
>>> java/org/apache/openejb/assembler/classic/JndiBuilder.java
>>> URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/ 
>>> container/openejb-core/src/main/java/org/apache/openejb/assembler/ 
>>> classic/JndiBuilder.java?view=diff&rev=565996&r1=565995&r2=565996
>>> ==================================================================== 
>>> ==========
>>> --- openejb/trunk/openejb3/container/openejb-core/src/main/java/ 
>>> org/apache/openejb/assembler/classic/JndiBuilder.java (original)
>>> +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/ 
>>> org/apache/openejb/assembler/classic/JndiBuilder.java Tue Aug 14  
>>> 18:25:15 2007
>>> @@ -19,9 +19,11 @@
>>>  import javax.naming.Context;
>>>  import javax.naming.NamingException;
>>>  import javax.naming.Reference;
>>> +import javax.naming.NameAlreadyBoundException;
>>>  import javax.jms.MessageListener;
>>>
>>>  import org.apache.openejb.DeploymentInfo;
>>> +import org.apache.openejb.InterfaceType;
>>>  import org.apache.openejb.util.LogCategory;
>>>  import org.apache.openejb.util.Logger;
>>>  import org.apache.openejb.loader.SystemInstance;
>>> @@ -36,6 +38,7 @@
>>>  import java.util.ArrayList;
>>>  import java.util.Map;
>>>  import java.util.HashMap;
>>> +import java.util.Comparator;
>>>
>>>
>>>  /**
>>> @@ -77,7 +80,58 @@
>>>
>>>          public static enum Interface {
>>>
>>> -            REMOTE_HOME, LOCAL_HOME, BUSINESS_LOCAL,  
>>> BUSINESS_REMOTE, SERVICE_ENDPOINT
>>> +            REMOTE_HOME(InterfaceType.EJB_HOME, "RemoteHome",  
>>> "home", ""),
>>> +            LOCAL_HOME(InterfaceType.EJB_LOCAL_HOME,  
>>> "LocalHome", "local-home", "Local"),
>>> +            BUSINESS_LOCAL(InterfaceType.BUSINESS_LOCAL,  
>>> "Local", "business-local", "BusinessLocal"),
>>> +            BUSINESS_REMOTE(InterfaceType.BUSINESS_REMOTE,  
>>> "Remote", "business-remote", "BusinessRemote"),
>>> +            SERVICE_ENDPOINT(InterfaceType.SERVICE_ENDPOINT,  
>>> "Endpoint", "service-endpoint", "ServiceEndpoint");
>>> +
>>> +            private final InterfaceType type;
>>> +            private final String annotatedName;
>>> +            private final String xmlName;
>>> +            private final String xmlNameCc;
>>> +            private final String openejbLegacy;
>>> +
>>> +            Interface(InterfaceType type, String annotatedName,  
>>> String xmlName, String openejbLegacy) {
>>> +                this.type = type;
>>> +                this.annotatedName = annotatedName;
>>> +                this.xmlName = xmlName;
>>> +                this.xmlNameCc = camelCase(xmlName);
>>> +                this.openejbLegacy = openejbLegacy;
>>> +            }
>>> +
>>> +            private String camelCase(String string){
>>> +                StringBuilder sb = new StringBuilder();
>>> +                String[] strings = string.split("-");
>>> +                for (String s : strings) {
>>> +                    int l = sb.length();
>>> +                    sb.append(s);
>>> +                    sb.setCharAt(l, Character.toUpperCase 
>>> (sb.charAt(l)));
>>> +                }
>>> +                return sb.toString();
>>> +            }
>>> +
>>> +
>>> +            public InterfaceType getType() {
>>> +                return type;
>>> +            }
>>> +
>>> +            public String getAnnotatedName() {
>>> +                return annotatedName;
>>> +            }
>>> +
>>> +            public String getXmlName() {
>>> +                return xmlName;
>>> +            }
>>> +
>>> +            public String getXmlNameCc() {
>>> +                return xmlNameCc;
>>> +            }
>>> +
>>> +            public String getOpenejbLegacy() {
>>> +                return openejbLegacy;
>>> +            }
>>> +
>>>          }
>>>
>>>          public String getName(DeploymentInfo deploymentInfo,  
>>> Class interfce, Interface type);
>>> @@ -101,7 +155,10 @@
>>>              contextData.put("ejbClass.simpleName",  
>>> deploymentInfo.getBeanClass().getSimpleName());
>>>              contextData.put("ejbName", deploymentInfo.getEjbName 
>>> ());
>>>              contextData.put("deploymentId",  
>>> deploymentInfo.getDeploymentID().toString());
>>> -            contextData.put("interfaceType",  
>>> deploymentInfo.getInterfaceType(interfce).name());
>>> +            contextData.put("interfaceType", type.annotatedName);
>>> +            contextData.put("interfaceType.xmlName",  
>>> type.getXmlName());
>>> +            contextData.put("interfaceType.xmlNameCc",  
>>> type.getXmlNameCc());
>>> +            contextData.put("interfaceType.openejbLegacyName",  
>>> type.getOpenejbLegacy());
>>>              contextData.put("interfaceClass", interfce.getName());
>>>              contextData.put("interfaceClass.simpleName",  
>>> interfce.getSimpleName());
>>>              return template.apply(contextData);
>>> @@ -198,7 +255,7 @@
>>>              Class homeInterface = deployment.getHomeInterface();
>>>              if (homeInterface != null) {
>>>
>>> -                String name = "openejb/ejb/" + strategy.getName 
>>> (deployment, deploymentInfo.getRemoteInterface(),  
>>> JndiNameStrategy.Interface.REMOTE_HOME);
>>> +                String name = "openejb/ejb/" + strategy.getName 
>>> (deployment, deploymentInfo.getHomeInterface(),  
>>> JndiNameStrategy.Interface.REMOTE_HOME);
>>>                  ObjectReference ref = new ObjectReference 
>>> (deployment.getEJBHome());
>>>                  bind(name, ref, bindings, beanInfo);
>>>
>>> @@ -213,7 +270,7 @@
>>>              Class localHomeInterface =  
>>> deployment.getLocalHomeInterface();
>>>              if (localHomeInterface != null) {
>>>
>>> -                String name = "openejb/ejb/" + strategy.getName 
>>> (deployment, deploymentInfo.getLocalInterface(),  
>>> JndiNameStrategy.Interface.LOCAL_HOME);
>>> +                String name = "openejb/ejb/" + strategy.getName 
>>> (deployment, deploymentInfo.getLocalHomeInterface(),  
>>> JndiNameStrategy.Interface.LOCAL_HOME);
>>>                  ObjectReference ref = new ObjectReference 
>>> (deployment.getEJBLocalHome());
>>>                  bind(name, ref, bindings, beanInfo);
>>>
>>> @@ -225,25 +282,22 @@
>>>          }
>>>
>>>          try {
>>> -            Class businessLocalInterface =  
>>> deployment.getBusinessLocalInterface();
>>> -            if (businessLocalInterface != null) {
>>> +            List<Class> localInterfaces =  
>>> deployment.getBusinessLocalInterfaces();
>>> +            Class beanClass = deployment.getBeanClass();
>>>
>>> -                String name = "openejb/ejb/" + strategy.getName 
>>> (deployment, businessLocalInterface,  
>>> JndiNameStrategy.Interface.BUSINESS_LOCAL);
>>> -                DeploymentInfo.BusinessLocalHome  
>>> businessLocalHome = deployment.getBusinessLocalHome();
>>> -                bind(name, new BusinessLocalReference 
>>> (businessLocalHome), bindings, beanInfo);
>>> -
>>> -                for (Class interfce :  
>>> deployment.getBusinessLocalInterfaces()) {
>>> -                    DeploymentInfo.BusinessLocalHome home =  
>>> deployment.getBusinessLocalHome(asList(interfce));
>>> -                    BusinessLocalReference ref = new  
>>> BusinessLocalReference(home);
>>> -
>>> -                    name = "openejb/Deployment/" +  
>>> deployment.getDeploymentID() + "/" + interfce.getName();
>>> -                    bind(name, ref, bindings, beanInfo);
>>> -
>>> -                    try {
>>> -                        name = "openejb/ejb/" + strategy.getName 
>>> (deployment, interfce, JndiNameStrategy.Interface.BUSINESS_LOCAL);
>>> -                        bind(name, ref, bindings, beanInfo);
>>> -                    } catch (NamingException dontCareJustYet) {
>>> -                    }
>>> +            for (Class interfce :  
>>> deployment.getBusinessLocalInterfaces()) {
>>> +
>>> +                List<Class> interfaces =  
>>> ProxyInterfaceResolver.getInterfaces(beanClass, interfce,  
>>> localInterfaces);
>>> +                DeploymentInfo.BusinessLocalHome home =  
>>> deployment.getBusinessLocalHome(interfaces);
>>> +                BusinessLocalReference ref = new  
>>> BusinessLocalReference(home);
>>> +
>>> +                String internalName = "openejb/Deployment/" +  
>>> deployment.getDeploymentID() + "/" + interfce.getName();
>>> +                bind(internalName, ref, bindings, beanInfo);
>>> +
>>> +                try {
>>> +                    String externalName = "openejb/ejb/" +  
>>> strategy.getName(deployment, interfce,  
>>> JndiNameStrategy.Interface.BUSINESS_LOCAL);
>>> +                    bind(externalName, ref, bindings, beanInfo);
>>> +                } catch (NamingException dontCareJustYet) {
>>>                  }
>>>              }
>>>          } catch (NamingException e) {
>>> @@ -251,27 +305,23 @@
>>>          }
>>>
>>>          try {
>>> -            Class businessRemoteInterface =  
>>> deployment.getBusinessRemoteInterface();
>>> -            if (businessRemoteInterface != null) {
>>>
>>> -                DeploymentInfo.BusinessRemoteHome  
>>> businessRemoteHome = deployment.getBusinessRemoteHome();
>>> -                BusinessRemoteReference ref = new  
>>> BusinessRemoteReference(businessRemoteHome);
>>> +            List<Class> remoteInterfaces =  
>>> deployment.getBusinessRemoteInterfaces();
>>> +            Class beanClass = deployment.getBeanClass();
>>>
>>> -                String name = "openejb/ejb/" + strategy.getName 
>>> (deployment, businessRemoteInterface,  
>>> JndiNameStrategy.Interface.BUSINESS_REMOTE);
>>> -                bind(name, ref, bindings, beanInfo);
>>> +            for (Class interfce :  
>>> deployment.getBusinessRemoteInterfaces()) {
>>>
>>> -                for (Class interfce :  
>>> deployment.getBusinessRemoteInterfaces()) {
>>> -                    DeploymentInfo.BusinessRemoteHome home =  
>>> deployment.getBusinessRemoteHome(asList(interfce));
>>> -                    ref = new BusinessRemoteReference(home);
>>> -
>>> -                    name = "openejb/Deployment/" +  
>>> deployment.getDeploymentID() + "/" + interfce.getName();
>>> -                    bind(name, ref, bindings, beanInfo);
>>> -
>>> -                    try {
>>> -                        name = "openejb/ejb/" + strategy.getName 
>>> (deployment, interfce, JndiNameStrategy.Interface.BUSINESS_REMOTE);
>>> -                        bind(name, ref, bindings, beanInfo);
>>> -                    } catch (NamingException dontCareJustYet) {
>>> -                    }
>>> +                List<Class> interfaces =  
>>> ProxyInterfaceResolver.getInterfaces(beanClass, interfce,  
>>> remoteInterfaces);
>>> +                DeploymentInfo.BusinessRemoteHome home =  
>>> deployment.getBusinessRemoteHome(interfaces);
>>> +                BusinessRemoteReference ref = new  
>>> BusinessRemoteReference(home);
>>> +
>>> +                String internalName = "openejb/Deployment/" +  
>>> deployment.getDeploymentID() + "/" + interfce.getName();
>>> +                bind(internalName, ref, bindings, beanInfo);
>>> +
>>> +                try {
>>> +                    String externalName = "openejb/ejb/" +  
>>> strategy.getName(deployment, interfce,  
>>> JndiNameStrategy.Interface.BUSINESS_REMOTE);
>>> +                    bind(externalName, ref, bindings, beanInfo);
>>> +                } catch (NamingException dontCareJustYet) {
>>>                  }
>>>              }
>>>          } catch (NamingException e) {
>>> @@ -295,14 +345,26 @@
>>>
>>>
>>>      private void bind(String name, Reference ref, Bindings  
>>> bindings, EnterpriseBeanInfo beanInfo) throws NamingException {
>>> -        context.bind(name, ref);
>>> -        bindings.add(name);
>>> +
>>>          if (name.startsWith("openejb/ejb/")) {
>>> -            name = name.replaceFirst("openejb/ejb/", "");
>>> -            logger.info("Jndi(name=" + name+")");
>>> -            if (!beanInfo.jndiNames.contains(name)){
>>> -                beanInfo.jndiNames.add(name);
>>> +
>>> +            String externalName = name.replaceFirst("openejb/ 
>>> ejb/", "");
>>> +
>>> +            if (beanInfo.jndiNames.contains(externalName)){
>>> +                logger.debug("Duplicate: Jndi(name=" +  
>>> externalName +")");
>>> +                return;
>>>              }
>>> +
>>> +            beanInfo.jndiNames.add(externalName);
>>> +            logger.info("Jndi(name=" + externalName +")");
>>> +        }
>>> +
>>> +        try {
>>> +            context.bind(name, ref);
>>> +            bindings.add(name);
>>> +        } catch (NameAlreadyBoundException e) {
>>> +            logger.error("Jndi name could not be bound; it may  
>>> be taken by another ejb.  Jndi(name=" + name +")");
>>> +            throw e;
>>>          }
>>>      }
>>>
>>> @@ -321,6 +383,17 @@
>>>
>>>          public boolean add(String o) {
>>>              return bindings.add(o);
>>> +        }
>>> +    }
>>> +
>>> +    public static class RemoteInterfaceComparator implements  
>>> Comparator<Class> {
>>> +
>>> +        public int compare(java.lang.Class a, java.lang.Class b) {
>>> +            boolean aIsRmote =  
>>> java.rmi.Remote.class.isAssignableFrom(a);
>>> +            boolean bIsRmote =  
>>> java.rmi.Remote.class.isAssignableFrom(b);
>>> +
>>> +            if (aIsRmote == bIsRmote) return 0;
>>> +            return (aIsRmote)? 1: -1;
>>>          }
>>>      }
>>>  }
>>>
>>> Added: openejb/trunk/openejb3/container/openejb-core/src/main/ 
>>> java/org/apache/openejb/assembler/classic/ 
>>> ProxyInterfaceResolver.java
>>> URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/ 
>>> container/openejb-core/src/main/java/org/apache/openejb/assembler/ 
>>> classic/ProxyInterfaceResolver.java?view=auto&rev=565996
>>> ==================================================================== 
>>> ==========
>>> --- openejb/trunk/openejb3/container/openejb-core/src/main/java/ 
>>> org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java  
>>> (added)
>>> +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/ 
>>> org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java  
>>> Tue Aug 14 18:25:15 2007
>>> @@ -0,0 +1,205 @@
>>> +/**
>>> + * 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.openejb.assembler.classic;
>>> +
>>> +import java.util.List;
>>> +import java.util.ArrayList;
>>> +import java.lang.reflect.Method;
>>> +
>>> +/**
>>> + * @version $Rev$ $Date$
>>> + */
>>> +public class ProxyInterfaceResolver {
>>> +
>>> +    public static List<Class> getInterfaces(Class  
>>> implementation, Class mainInterface, List<Class> interfaces){
>>> +        List<Class> valid = new ArrayList<Class>();
>>> +        // The intended interface is safe to add
>>> +        valid.add(mainInterface);
>>> +
>>> +        // Any interface the bean implements is safe (potentially)
>>> +        for (Class interfce : interfaces) {
>>> +            if (interfce.isAssignableFrom(implementation)){
>>> +                valid.add(interfce);
>>> +            }
>>> +        }
>>> +
>>> +
>>> +        // Here comes the trick, if any of them implement  
>>> java.rmi.Remote
>>> +        // we have to check the "remote" methods against the  
>>> other methods
>>> +        // of the same name and params to see if there are any  
>>> conflicts in
>>> +        // the exception clauses.  If there are, then we need to  
>>> remove the
>>> +        // conflicting interface(s).
>>> +        //
>>> +        // DETAILS:
>>> +        // The trick is that two nearly matching interface methods
>>> +        //   -InterfaceA: void doIt() throws Foo;
>>> +        //   -InterfaceB: void doIt() throws Bar;
>>> +        //
>>> +        // can be implemented in a class by leaving out  
>>> exceptions from the
>>> +        // throws clause that aren't declared in both interfaces  
>>> methods.
>>> +        //   -Implementation:  void doIt(){}
>>> +        //
>>> +        // This means the implementing class can not throw Foo  
>>> or Bar.  The
>>> +        // same rule applies to proxies created from these two  
>>> interfaces as
>>> +        // the proxy generating code will automatically remove  
>>> exceptions
>>> +        // not shared by the two matching interface methods;  
>>> eliminating
>>> +        // the proxy's and therefore container's ability to  
>>> throw those
>>> +        // exceptions.
>>> +        //
>>> +        // The specific issue with java.rmi.Remote interfaces is  
>>> that per
>>> +        // spec rules many runtime exceptions (container or  
>>> connection issues)
>>> +        // are thrown to clients as java.rmi.RemoteException  
>>> which is not
>>> +        // a runtime exception and must be throwable via the proxy.
>>> +
>>> +
>>> +        List<Class> remotes = new ArrayList<Class>();
>>> +        List<Class> nonremotes = new ArrayList<Class>();
>>> +        for (Class interfce : valid) {
>>> +            if (java.rmi.Remote.class.isAssignableFrom(interfce)){
>>> +                remotes.add(interfce);
>>> +            } else {
>>> +                nonremotes.add(interfce);
>>> +            }
>>> +        }
>>> +
>>> +        // No remote interfaces, we're good to go
>>> +        if (remotes.size() == 0) return valid;
>>> +
>>> +        //  
>>> -----------------------------------------------------------
>>> +        // If we got here, we have potentially clashing interfaces
>>> +        // We sort of have to start over and go "slower" checking
>>> +        // methods for conflicts and not including those interfaces
>>> +        //  
>>> -----------------------------------------------------------
>>> +
>>> +        valid.clear();
>>> +        remotes.remove(mainInterface);
>>> +        nonremotes.remove(mainInterface);
>>> +
>>> +        // Re-add the main interface
>>> +        valid.add(mainInterface);
>>> +
>>> +        // Track the method signatures of the interfaces we add
>>> +        List<Signature> proxySignatures = getSignatures 
>>> (mainInterface);
>>> +
>>> +
>>> +        // Show affinity for the remote interfaces if the main
>>> +        // interface is a java.rmi.Remote
>>> +        if (java.rmi.Remote.class.isAssignableFrom(mainInterface)){
>>> +            for (Class interfce : remotes) {
>>> +                addIfNotConflicting(interfce, valid,  
>>> proxySignatures);
>>> +            }
>>> +            for (Class interfce : nonremotes) {
>>> +                addIfNotConflicting(interfce, valid,  
>>> proxySignatures);
>>> +            }
>>> +        } else {
>>> +            for (Class interfce : nonremotes) {
>>> +                addIfNotConflicting(interfce, valid,  
>>> proxySignatures);
>>> +            }
>>> +            for (Class interfce : remotes) {
>>> +                addIfNotConflicting(interfce, valid,  
>>> proxySignatures);
>>> +            }
>>> +        }
>>> +
>>> +        return valid;
>>> +    }
>>> +
>>> +    /**
>>> +     * Adds the interface to the list of valid interfaces for  
>>> the proxy
>>> +     * if the signatures on the interface do not conflict with  
>>> the method
>>> +     * signatures already apart of the proxy's other interfaces.
>>> +     *
>>> +     * @param interfce
>>> +     * @param valid
>>> +     * @param proxySignatures
>>> +     */
>>> +    private static void addIfNotConflicting(Class interfce,  
>>> List<Class> valid, List<Signature> proxySignatures) {
>>> +
>>> +        List<Signature> interfaceSigs = getSignatures(interfce);
>>> +
>>> +
>>> +        for (Signature sig : interfaceSigs) {
>>> +            // Contains will return true if the
>>> +            // method signature exits *and* has
>>> +            // a different throws clause
>>> +            if (proxySignatures.contains(sig)){
>>> +                 return;  // conflicts and cannot be added
>>> +            }
>>> +        }
>>> +
>>> +
>>> +        // Does not conflict, add it and track the new signatures
>>> +        valid.add(interfce);
>>> +        proxySignatures.addAll(interfaceSigs);
>>> +    }
>>> +
>>> +    private static List<Signature> getSignatures(Class  
>>> mainInterface) {
>>> +        List<Signature> sigs = new ArrayList<Signature>();
>>> +        for (Method method : mainInterface.getMethods()) {
>>> +            sigs.add(new Signature(mainInterface, method));
>>> +        }
>>> +        return sigs;
>>> +    }
>>> +
>>> +    public static class Signature {
>>> +        private final Class clazz;
>>> +        private final Method method;
>>> +        private final String sig;
>>> +
>>> +        public Signature(Class clazz, Method method) {
>>> +            this.clazz = clazz;
>>> +            this.method = method;
>>> +            StringBuilder sb = new StringBuilder();
>>> +            sb.append(method.getName());
>>> +            sb.append('(');
>>> +            for (Class<?> type : method.getParameterTypes()) {
>>> +                sb.append(type.getName());
>>> +                sb.append(',');
>>> +            }
>>> +            sb.append(')');
>>> +            sig = sb.toString();
>>> +        }
>>> +
>>> +        public Method getMethod() {
>>> +            return method;
>>> +        }
>>> +
>>> +        // This equals returns true only if the method signatures
>>> +        // are the same *and* one is remote and one is not
>>> +        public boolean equals(Object o) {
>>> +            if (this == o) return true;
>>> +            if (o == null || getClass() != o.getClass()) return  
>>> false;
>>> +
>>> +            final Signature signature = (Signature) o;
>>> +
>>> +            if (!sig.equals(signature.sig)) return false;
>>> +
>>> +            boolean aIsRemote =  
>>> java.rmi.Remote.class.isAssignableFrom(clazz);
>>> +            boolean bIsRemote =  
>>> java.rmi.Remote.class.isAssignableFrom(signature.clazz);
>>> +
>>> +            return !(aIsRemote == bIsRemote);
>>> +        }
>>> +
>>> +        public int hashCode() {
>>> +            return sig.hashCode();
>>> +        }
>>> +
>>> +        public String toString() {
>>> +            return method.toString();
>>> +        }
>>> +    }
>>> +
>>> +}
>>>
>>> Added: openejb/trunk/openejb3/container/openejb-core/src/test/ 
>>> java/org/apache/openejb/assembler/classic/ 
>>> ProxyInterfaceResolverTest.java
>>> URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/ 
>>> container/openejb-core/src/test/java/org/apache/openejb/assembler/ 
>>> classic/ProxyInterfaceResolverTest.java?view=auto&rev=565996
>>> ==================================================================== 
>>> ==========
>>> --- openejb/trunk/openejb3/container/openejb-core/src/test/java/ 
>>> org/apache/openejb/assembler/classic/ 
>>> ProxyInterfaceResolverTest.java (added)
>>> +++ openejb/trunk/openejb3/container/openejb-core/src/test/java/ 
>>> org/apache/openejb/assembler/classic/ 
>>> ProxyInterfaceResolverTest.java Tue Aug 14 18:25:15 2007
>>> @@ -0,0 +1,144 @@
>>> +/**
>>> + * 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.openejb.assembler.classic;
>>> +
>>> +import junit.framework.TestCase;
>>> +
>>> +import java.rmi.RemoteException;
>>> +import java.util.Arrays;
>>> +import java.util.List;
>>> +
>>> +/**
>>> + * @version $Rev$ $Date$
>>> + */
>>> +public class ProxyInterfaceResolverTest extends TestCase {
>>> +    public void test() throws Exception {
>>> +        Class smoothie;
>>> +        List<Class> ingredients;
>>> +
>>> +        // No remotes
>>> +        smoothie = implement(Mango.class, Lime.class, Lemon.class);
>>> +        ingredients = resolve(smoothie, Mango.class, Lime.class,  
>>> Lemon.class);
>>> +        assertEquals(3, ingredients.size());
>>> +        assertTrue(ingredients.contains(Mango.class));
>>> +        assertTrue(ingredients.contains(Lime.class));
>>> +        assertTrue(ingredients.contains(Lemon.class));
>>> +
>>> +        // All remotes
>>> +        smoothie = implement(Cherry.class, Honey.class,  
>>> Grape.class);
>>> +        ingredients = resolve(smoothie, Cherry.class,  
>>> Honey.class, Grape.class);
>>> +        assertEquals(3, ingredients.size());
>>> +        assertTrue(ingredients.contains(Cherry.class));
>>> +        assertTrue(ingredients.contains(Grape.class));
>>> +        assertTrue(ingredients.contains(Honey.class));
>>> +
>>> +        // mixed remote and non-remote, no conflicts
>>> +        smoothie = implement(Banana.class, Honey.class,  
>>> Creme.class);
>>> +        ingredients = resolve(smoothie, Banana.class,  
>>> Honey.class, Creme.class);
>>> +        assertEquals(3, ingredients.size());
>>> +        assertTrue(ingredients.contains(Banana.class));
>>> +        assertTrue(ingredients.contains(Honey.class));
>>> +        assertTrue(ingredients.contains(Creme.class));
>>> +
>>> +        // mixed remote and non-remote, conflicts (cherry, grape)
>>> +        smoothie = implement(Mango.class, Banana.class,  
>>> Creme.class, Honey.class, Cherry.class, Grape.class);
>>> +        ingredients = resolve(smoothie, Mango.class,  
>>> Banana.class, Creme.class, Honey.class, Cherry.class, Grape.class);
>>> +        assertEquals(4, ingredients.size());
>>> +        assertTrue(ingredients.contains(Mango.class));
>>> +        assertTrue(ingredients.contains(Banana.class));
>>> +        assertTrue(ingredients.contains(Creme.class));
>>> +        assertTrue(ingredients.contains(Honey.class));
>>> +
>>> +        // mixed remote and non-remote, conflicts (mango, banana)
>>> +        smoothie = implement(Cherry.class, Mango.class,  
>>> Banana.class, Creme.class, Honey.class, Grape.class);
>>> +        ingredients = resolve(smoothie, Cherry.class,  
>>> Mango.class, Banana.class, Creme.class, Honey.class, Grape.class);
>>> +        assertEquals(4, ingredients.size());
>>> +        assertTrue(ingredients.contains(Cherry.class));
>>> +        assertTrue(ingredients.contains(Grape.class));
>>> +        assertTrue(ingredients.contains(Creme.class));
>>> +        assertTrue(ingredients.contains(Honey.class));
>>> +    }
>>> +
>>> +    public List<Class> resolve(Class impl, Class mainInterface,  
>>> Class... interfaces) {
>>> +        return ProxyInterfaceResolver.getInterfaces(impl,  
>>> mainInterface, Arrays.asList(interfaces));
>>> +    }
>>> +
>>> +
>>> +    public Class implement(Class<?>... interfaces) {
>>> +        return java.lang.reflect.Proxy.getProxyClass 
>>> (this.getClass().getClassLoader(), interfaces);
>>> +    }
>>> +
>>> +    public interface Mango {
>>> +        void exist() throws RoundException, GreenException;
>>> +
>>> +        void mango();
>>> +    }
>>> +
>>> +    public interface Lime {
>>> +        void exist() throws RoundException, GreenException;
>>> +
>>> +        void lime();
>>> +    }
>>> +
>>> +    public interface Lemon {
>>> +        void exist() throws RoundException, YellowException;
>>> +
>>> +        void lemon();
>>> +    }
>>> +
>>> +    public interface Banana {
>>> +        void exist() throws LongException, YellowException;
>>> +
>>> +        void banana();
>>> +    }
>>> +
>>> +    public interface Creme {
>>> +        void thiken();
>>> +    }
>>> +
>>> +    public interface Cherry extends java.rmi.Remote {
>>> +        void exist() throws RoundException, RemoteException;
>>> +
>>> +        void cherry() throws RemoteException;
>>> +    }
>>> +
>>> +    public interface Grape extends java.rmi.Remote {
>>> +        void exist() throws RoundException, RemoteException;
>>> +
>>> +        void grape() throws RemoteException;
>>> +    }
>>> +
>>> +    public interface Honey extends java.rmi.Remote {
>>> +        void sweeten() throws RemoteException;
>>> +    }
>>> +
>>> +    //--------------//
>>> +    public static class RoundException extends Exception {
>>> +    }
>>> +
>>> +    public static class GreenException extends Exception {
>>> +    }
>>> +
>>> +    public static class YellowException extends Exception {
>>> +    }
>>> +
>>> +    public static class LongException extends Exception {
>>> +    }
>>> +
>>> +
>>> +}
>>> +
>>>
>>>
>


Re: svn commit: r565996 - in /openejb/trunk/openejb3/container/openejb-core/src: main/java/org/apache/openejb/assembler/classic/ test/java/org/apache/openejb/assembler/classic/

Posted by Joe Bohn <jo...@earthlink.net>.
Thanks Kevan ... I should have thought to put this on the openejb list 
myself.

David,  There are some more details on the geronimo tck list where you 
can see the failing tests and a little info on the failure.

Thanks,
Joe


Kevan Miller wrote:
> Joe Bohn tracked down some major tck breakage that's associated with 
> this change. David, perhaps you could have a look?
> 
> --kevan
> 
> On Aug 14, 2007, at 9:25 PM, dblevins@apache.org wrote:
> 
>> Author: dblevins
>> Date: Tue Aug 14 18:25:15 2007
>> New Revision: 565996
>>
>> URL: http://svn.apache.org/viewvc?view=rev&rev=565996
>> Log:
>> Improved proxy creation code so that for business interfaces it 
>> includes as many interfaces as possible
>>
>> Added:
>>     
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java 
>>
>>     
>> openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java 
>>
>> Modified:
>>     
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/JndiBuilder.java 
>>
>>
>> Modified: 
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/JndiBuilder.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/JndiBuilder.java?view=diff&rev=565996&r1=565995&r2=565996 
>>
>> ============================================================================== 
>>
>> --- 
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/JndiBuilder.java 
>> (original)
>> +++ 
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/JndiBuilder.java 
>> Tue Aug 14 18:25:15 2007
>> @@ -19,9 +19,11 @@
>>  import javax.naming.Context;
>>  import javax.naming.NamingException;
>>  import javax.naming.Reference;
>> +import javax.naming.NameAlreadyBoundException;
>>  import javax.jms.MessageListener;
>>
>>  import org.apache.openejb.DeploymentInfo;
>> +import org.apache.openejb.InterfaceType;
>>  import org.apache.openejb.util.LogCategory;
>>  import org.apache.openejb.util.Logger;
>>  import org.apache.openejb.loader.SystemInstance;
>> @@ -36,6 +38,7 @@
>>  import java.util.ArrayList;
>>  import java.util.Map;
>>  import java.util.HashMap;
>> +import java.util.Comparator;
>>
>>
>>  /**
>> @@ -77,7 +80,58 @@
>>
>>          public static enum Interface {
>>
>> -            REMOTE_HOME, LOCAL_HOME, BUSINESS_LOCAL, BUSINESS_REMOTE, 
>> SERVICE_ENDPOINT
>> +            REMOTE_HOME(InterfaceType.EJB_HOME, "RemoteHome", "home", 
>> ""),
>> +            LOCAL_HOME(InterfaceType.EJB_LOCAL_HOME, "LocalHome", 
>> "local-home", "Local"),
>> +            BUSINESS_LOCAL(InterfaceType.BUSINESS_LOCAL, "Local", 
>> "business-local", "BusinessLocal"),
>> +            BUSINESS_REMOTE(InterfaceType.BUSINESS_REMOTE, "Remote", 
>> "business-remote", "BusinessRemote"),
>> +            SERVICE_ENDPOINT(InterfaceType.SERVICE_ENDPOINT, 
>> "Endpoint", "service-endpoint", "ServiceEndpoint");
>> +
>> +            private final InterfaceType type;
>> +            private final String annotatedName;
>> +            private final String xmlName;
>> +            private final String xmlNameCc;
>> +            private final String openejbLegacy;
>> +
>> +            Interface(InterfaceType type, String annotatedName, 
>> String xmlName, String openejbLegacy) {
>> +                this.type = type;
>> +                this.annotatedName = annotatedName;
>> +                this.xmlName = xmlName;
>> +                this.xmlNameCc = camelCase(xmlName);
>> +                this.openejbLegacy = openejbLegacy;
>> +            }
>> +
>> +            private String camelCase(String string){
>> +                StringBuilder sb = new StringBuilder();
>> +                String[] strings = string.split("-");
>> +                for (String s : strings) {
>> +                    int l = sb.length();
>> +                    sb.append(s);
>> +                    sb.setCharAt(l, 
>> Character.toUpperCase(sb.charAt(l)));
>> +                }
>> +                return sb.toString();
>> +            }
>> +
>> +
>> +            public InterfaceType getType() {
>> +                return type;
>> +            }
>> +
>> +            public String getAnnotatedName() {
>> +                return annotatedName;
>> +            }
>> +
>> +            public String getXmlName() {
>> +                return xmlName;
>> +            }
>> +
>> +            public String getXmlNameCc() {
>> +                return xmlNameCc;
>> +            }
>> +
>> +            public String getOpenejbLegacy() {
>> +                return openejbLegacy;
>> +            }
>> +
>>          }
>>
>>          public String getName(DeploymentInfo deploymentInfo, Class 
>> interfce, Interface type);
>> @@ -101,7 +155,10 @@
>>              contextData.put("ejbClass.simpleName", 
>> deploymentInfo.getBeanClass().getSimpleName());
>>              contextData.put("ejbName", deploymentInfo.getEjbName());
>>              contextData.put("deploymentId", 
>> deploymentInfo.getDeploymentID().toString());
>> -            contextData.put("interfaceType", 
>> deploymentInfo.getInterfaceType(interfce).name());
>> +            contextData.put("interfaceType", type.annotatedName);
>> +            contextData.put("interfaceType.xmlName", type.getXmlName());
>> +            contextData.put("interfaceType.xmlNameCc", 
>> type.getXmlNameCc());
>> +            contextData.put("interfaceType.openejbLegacyName", 
>> type.getOpenejbLegacy());
>>              contextData.put("interfaceClass", interfce.getName());
>>              contextData.put("interfaceClass.simpleName", 
>> interfce.getSimpleName());
>>              return template.apply(contextData);
>> @@ -198,7 +255,7 @@
>>              Class homeInterface = deployment.getHomeInterface();
>>              if (homeInterface != null) {
>>
>> -                String name = "openejb/ejb/" + 
>> strategy.getName(deployment, deploymentInfo.getRemoteInterface(), 
>> JndiNameStrategy.Interface.REMOTE_HOME);
>> +                String name = "openejb/ejb/" + 
>> strategy.getName(deployment, deploymentInfo.getHomeInterface(), 
>> JndiNameStrategy.Interface.REMOTE_HOME);
>>                  ObjectReference ref = new 
>> ObjectReference(deployment.getEJBHome());
>>                  bind(name, ref, bindings, beanInfo);
>>
>> @@ -213,7 +270,7 @@
>>              Class localHomeInterface = 
>> deployment.getLocalHomeInterface();
>>              if (localHomeInterface != null) {
>>
>> -                String name = "openejb/ejb/" + 
>> strategy.getName(deployment, deploymentInfo.getLocalInterface(), 
>> JndiNameStrategy.Interface.LOCAL_HOME);
>> +                String name = "openejb/ejb/" + 
>> strategy.getName(deployment, deploymentInfo.getLocalHomeInterface(), 
>> JndiNameStrategy.Interface.LOCAL_HOME);
>>                  ObjectReference ref = new 
>> ObjectReference(deployment.getEJBLocalHome());
>>                  bind(name, ref, bindings, beanInfo);
>>
>> @@ -225,25 +282,22 @@
>>          }
>>
>>          try {
>> -            Class businessLocalInterface = 
>> deployment.getBusinessLocalInterface();
>> -            if (businessLocalInterface != null) {
>> +            List<Class> localInterfaces = 
>> deployment.getBusinessLocalInterfaces();
>> +            Class beanClass = deployment.getBeanClass();
>>
>> -                String name = "openejb/ejb/" + 
>> strategy.getName(deployment, businessLocalInterface, 
>> JndiNameStrategy.Interface.BUSINESS_LOCAL);
>> -                DeploymentInfo.BusinessLocalHome businessLocalHome = 
>> deployment.getBusinessLocalHome();
>> -                bind(name, new 
>> BusinessLocalReference(businessLocalHome), bindings, beanInfo);
>> -
>> -                for (Class interfce : 
>> deployment.getBusinessLocalInterfaces()) {
>> -                    DeploymentInfo.BusinessLocalHome home = 
>> deployment.getBusinessLocalHome(asList(interfce));
>> -                    BusinessLocalReference ref = new 
>> BusinessLocalReference(home);
>> -
>> -                    name = "openejb/Deployment/" + 
>> deployment.getDeploymentID() + "/" + interfce.getName();
>> -                    bind(name, ref, bindings, beanInfo);
>> -
>> -                    try {
>> -                        name = "openejb/ejb/" + 
>> strategy.getName(deployment, interfce, 
>> JndiNameStrategy.Interface.BUSINESS_LOCAL);
>> -                        bind(name, ref, bindings, beanInfo);
>> -                    } catch (NamingException dontCareJustYet) {
>> -                    }
>> +            for (Class interfce : 
>> deployment.getBusinessLocalInterfaces()) {
>> +
>> +                List<Class> interfaces = 
>> ProxyInterfaceResolver.getInterfaces(beanClass, interfce, 
>> localInterfaces);
>> +                DeploymentInfo.BusinessLocalHome home = 
>> deployment.getBusinessLocalHome(interfaces);
>> +                BusinessLocalReference ref = new 
>> BusinessLocalReference(home);
>> +
>> +                String internalName = "openejb/Deployment/" + 
>> deployment.getDeploymentID() + "/" + interfce.getName();
>> +                bind(internalName, ref, bindings, beanInfo);
>> +
>> +                try {
>> +                    String externalName = "openejb/ejb/" + 
>> strategy.getName(deployment, interfce, 
>> JndiNameStrategy.Interface.BUSINESS_LOCAL);
>> +                    bind(externalName, ref, bindings, beanInfo);
>> +                } catch (NamingException dontCareJustYet) {
>>                  }
>>              }
>>          } catch (NamingException e) {
>> @@ -251,27 +305,23 @@
>>          }
>>
>>          try {
>> -            Class businessRemoteInterface = 
>> deployment.getBusinessRemoteInterface();
>> -            if (businessRemoteInterface != null) {
>>
>> -                DeploymentInfo.BusinessRemoteHome businessRemoteHome 
>> = deployment.getBusinessRemoteHome();
>> -                BusinessRemoteReference ref = new 
>> BusinessRemoteReference(businessRemoteHome);
>> +            List<Class> remoteInterfaces = 
>> deployment.getBusinessRemoteInterfaces();
>> +            Class beanClass = deployment.getBeanClass();
>>
>> -                String name = "openejb/ejb/" + 
>> strategy.getName(deployment, businessRemoteInterface, 
>> JndiNameStrategy.Interface.BUSINESS_REMOTE);
>> -                bind(name, ref, bindings, beanInfo);
>> +            for (Class interfce : 
>> deployment.getBusinessRemoteInterfaces()) {
>>
>> -                for (Class interfce : 
>> deployment.getBusinessRemoteInterfaces()) {
>> -                    DeploymentInfo.BusinessRemoteHome home = 
>> deployment.getBusinessRemoteHome(asList(interfce));
>> -                    ref = new BusinessRemoteReference(home);
>> -
>> -                    name = "openejb/Deployment/" + 
>> deployment.getDeploymentID() + "/" + interfce.getName();
>> -                    bind(name, ref, bindings, beanInfo);
>> -
>> -                    try {
>> -                        name = "openejb/ejb/" + 
>> strategy.getName(deployment, interfce, 
>> JndiNameStrategy.Interface.BUSINESS_REMOTE);
>> -                        bind(name, ref, bindings, beanInfo);
>> -                    } catch (NamingException dontCareJustYet) {
>> -                    }
>> +                List<Class> interfaces = 
>> ProxyInterfaceResolver.getInterfaces(beanClass, interfce, 
>> remoteInterfaces);
>> +                DeploymentInfo.BusinessRemoteHome home = 
>> deployment.getBusinessRemoteHome(interfaces);
>> +                BusinessRemoteReference ref = new 
>> BusinessRemoteReference(home);
>> +
>> +                String internalName = "openejb/Deployment/" + 
>> deployment.getDeploymentID() + "/" + interfce.getName();
>> +                bind(internalName, ref, bindings, beanInfo);
>> +
>> +                try {
>> +                    String externalName = "openejb/ejb/" + 
>> strategy.getName(deployment, interfce, 
>> JndiNameStrategy.Interface.BUSINESS_REMOTE);
>> +                    bind(externalName, ref, bindings, beanInfo);
>> +                } catch (NamingException dontCareJustYet) {
>>                  }
>>              }
>>          } catch (NamingException e) {
>> @@ -295,14 +345,26 @@
>>
>>
>>      private void bind(String name, Reference ref, Bindings bindings, 
>> EnterpriseBeanInfo beanInfo) throws NamingException {
>> -        context.bind(name, ref);
>> -        bindings.add(name);
>> +
>>          if (name.startsWith("openejb/ejb/")) {
>> -            name = name.replaceFirst("openejb/ejb/", "");
>> -            logger.info("Jndi(name=" + name+")");
>> -            if (!beanInfo.jndiNames.contains(name)){
>> -                beanInfo.jndiNames.add(name);
>> +
>> +            String externalName = name.replaceFirst("openejb/ejb/", "");
>> +
>> +            if (beanInfo.jndiNames.contains(externalName)){
>> +                logger.debug("Duplicate: Jndi(name=" + externalName 
>> +")");
>> +                return;
>>              }
>> +
>> +            beanInfo.jndiNames.add(externalName);
>> +            logger.info("Jndi(name=" + externalName +")");
>> +        }
>> +
>> +        try {
>> +            context.bind(name, ref);
>> +            bindings.add(name);
>> +        } catch (NameAlreadyBoundException e) {
>> +            logger.error("Jndi name could not be bound; it may be 
>> taken by another ejb.  Jndi(name=" + name +")");
>> +            throw e;
>>          }
>>      }
>>
>> @@ -321,6 +383,17 @@
>>
>>          public boolean add(String o) {
>>              return bindings.add(o);
>> +        }
>> +    }
>> +
>> +    public static class RemoteInterfaceComparator implements 
>> Comparator<Class> {
>> +
>> +        public int compare(java.lang.Class a, java.lang.Class b) {
>> +            boolean aIsRmote = 
>> java.rmi.Remote.class.isAssignableFrom(a);
>> +            boolean bIsRmote = 
>> java.rmi.Remote.class.isAssignableFrom(b);
>> +
>> +            if (aIsRmote == bIsRmote) return 0;
>> +            return (aIsRmote)? 1: -1;
>>          }
>>      }
>>  }
>>
>> Added: 
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java?view=auto&rev=565996 
>>
>> ============================================================================== 
>>
>> --- 
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java 
>> (added)
>> +++ 
>> openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolver.java 
>> Tue Aug 14 18:25:15 2007
>> @@ -0,0 +1,205 @@
>> +/**
>> + * 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.openejb.assembler.classic;
>> +
>> +import java.util.List;
>> +import java.util.ArrayList;
>> +import java.lang.reflect.Method;
>> +
>> +/**
>> + * @version $Rev$ $Date$
>> + */
>> +public class ProxyInterfaceResolver {
>> +
>> +    public static List<Class> getInterfaces(Class implementation, 
>> Class mainInterface, List<Class> interfaces){
>> +        List<Class> valid = new ArrayList<Class>();
>> +        // The intended interface is safe to add
>> +        valid.add(mainInterface);
>> +
>> +        // Any interface the bean implements is safe (potentially)
>> +        for (Class interfce : interfaces) {
>> +            if (interfce.isAssignableFrom(implementation)){
>> +                valid.add(interfce);
>> +            }
>> +        }
>> +
>> +
>> +        // Here comes the trick, if any of them implement 
>> java.rmi.Remote
>> +        // we have to check the "remote" methods against the other 
>> methods
>> +        // of the same name and params to see if there are any 
>> conflicts in
>> +        // the exception clauses.  If there are, then we need to 
>> remove the
>> +        // conflicting interface(s).
>> +        //
>> +        // DETAILS:
>> +        // The trick is that two nearly matching interface methods
>> +        //   -InterfaceA: void doIt() throws Foo;
>> +        //   -InterfaceB: void doIt() throws Bar;
>> +        //
>> +        // can be implemented in a class by leaving out exceptions 
>> from the
>> +        // throws clause that aren't declared in both interfaces 
>> methods.
>> +        //   -Implementation:  void doIt(){}
>> +        //
>> +        // This means the implementing class can not throw Foo or 
>> Bar.  The
>> +        // same rule applies to proxies created from these two 
>> interfaces as
>> +        // the proxy generating code will automatically remove 
>> exceptions
>> +        // not shared by the two matching interface methods; eliminating
>> +        // the proxy's and therefore container's ability to throw those
>> +        // exceptions.
>> +        //
>> +        // The specific issue with java.rmi.Remote interfaces is that 
>> per
>> +        // spec rules many runtime exceptions (container or 
>> connection issues)
>> +        // are thrown to clients as java.rmi.RemoteException which is 
>> not
>> +        // a runtime exception and must be throwable via the proxy.
>> +
>> +
>> +        List<Class> remotes = new ArrayList<Class>();
>> +        List<Class> nonremotes = new ArrayList<Class>();
>> +        for (Class interfce : valid) {
>> +            if (java.rmi.Remote.class.isAssignableFrom(interfce)){
>> +                remotes.add(interfce);
>> +            } else {
>> +                nonremotes.add(interfce);
>> +            }
>> +        }
>> +
>> +        // No remote interfaces, we're good to go
>> +        if (remotes.size() == 0) return valid;
>> +
>> +        // -----------------------------------------------------------
>> +        // If we got here, we have potentially clashing interfaces
>> +        // We sort of have to start over and go "slower" checking
>> +        // methods for conflicts and not including those interfaces
>> +        // -----------------------------------------------------------
>> +
>> +        valid.clear();
>> +        remotes.remove(mainInterface);
>> +        nonremotes.remove(mainInterface);
>> +
>> +        // Re-add the main interface
>> +        valid.add(mainInterface);
>> +
>> +        // Track the method signatures of the interfaces we add
>> +        List<Signature> proxySignatures = getSignatures(mainInterface);
>> +
>> +
>> +        // Show affinity for the remote interfaces if the main
>> +        // interface is a java.rmi.Remote
>> +        if (java.rmi.Remote.class.isAssignableFrom(mainInterface)){
>> +            for (Class interfce : remotes) {
>> +                addIfNotConflicting(interfce, valid, proxySignatures);
>> +            }
>> +            for (Class interfce : nonremotes) {
>> +                addIfNotConflicting(interfce, valid, proxySignatures);
>> +            }
>> +        } else {
>> +            for (Class interfce : nonremotes) {
>> +                addIfNotConflicting(interfce, valid, proxySignatures);
>> +            }
>> +            for (Class interfce : remotes) {
>> +                addIfNotConflicting(interfce, valid, proxySignatures);
>> +            }
>> +        }
>> +
>> +        return valid;
>> +    }
>> +
>> +    /**
>> +     * Adds the interface to the list of valid interfaces for the proxy
>> +     * if the signatures on the interface do not conflict with the 
>> method
>> +     * signatures already apart of the proxy's other interfaces.
>> +     *
>> +     * @param interfce
>> +     * @param valid
>> +     * @param proxySignatures
>> +     */
>> +    private static void addIfNotConflicting(Class interfce, 
>> List<Class> valid, List<Signature> proxySignatures) {
>> +
>> +        List<Signature> interfaceSigs = getSignatures(interfce);
>> +
>> +
>> +        for (Signature sig : interfaceSigs) {
>> +            // Contains will return true if the
>> +            // method signature exits *and* has
>> +            // a different throws clause
>> +            if (proxySignatures.contains(sig)){
>> +                 return;  // conflicts and cannot be added
>> +            }
>> +        }
>> +
>> +
>> +        // Does not conflict, add it and track the new signatures
>> +        valid.add(interfce);
>> +        proxySignatures.addAll(interfaceSigs);
>> +    }
>> +
>> +    private static List<Signature> getSignatures(Class mainInterface) {
>> +        List<Signature> sigs = new ArrayList<Signature>();
>> +        for (Method method : mainInterface.getMethods()) {
>> +            sigs.add(new Signature(mainInterface, method));
>> +        }
>> +        return sigs;
>> +    }
>> +
>> +    public static class Signature {
>> +        private final Class clazz;
>> +        private final Method method;
>> +        private final String sig;
>> +
>> +        public Signature(Class clazz, Method method) {
>> +            this.clazz = clazz;
>> +            this.method = method;
>> +            StringBuilder sb = new StringBuilder();
>> +            sb.append(method.getName());
>> +            sb.append('(');
>> +            for (Class<?> type : method.getParameterTypes()) {
>> +                sb.append(type.getName());
>> +                sb.append(',');
>> +            }
>> +            sb.append(')');
>> +            sig = sb.toString();
>> +        }
>> +
>> +        public Method getMethod() {
>> +            return method;
>> +        }
>> +
>> +        // This equals returns true only if the method signatures
>> +        // are the same *and* one is remote and one is not
>> +        public boolean equals(Object o) {
>> +            if (this == o) return true;
>> +            if (o == null || getClass() != o.getClass()) return false;
>> +
>> +            final Signature signature = (Signature) o;
>> +
>> +            if (!sig.equals(signature.sig)) return false;
>> +
>> +            boolean aIsRemote = 
>> java.rmi.Remote.class.isAssignableFrom(clazz);
>> +            boolean bIsRemote = 
>> java.rmi.Remote.class.isAssignableFrom(signature.clazz);
>> +
>> +            return !(aIsRemote == bIsRemote);
>> +        }
>> +
>> +        public int hashCode() {
>> +            return sig.hashCode();
>> +        }
>> +
>> +        public String toString() {
>> +            return method.toString();
>> +        }
>> +    }
>> +
>> +}
>>
>> Added: 
>> openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java?view=auto&rev=565996 
>>
>> ============================================================================== 
>>
>> --- 
>> openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java 
>> (added)
>> +++ 
>> openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ProxyInterfaceResolverTest.java 
>> Tue Aug 14 18:25:15 2007
>> @@ -0,0 +1,144 @@
>> +/**
>> + * 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.openejb.assembler.classic;
>> +
>> +import junit.framework.TestCase;
>> +
>> +import java.rmi.RemoteException;
>> +import java.util.Arrays;
>> +import java.util.List;
>> +
>> +/**
>> + * @version $Rev$ $Date$
>> + */
>> +public class ProxyInterfaceResolverTest extends TestCase {
>> +    public void test() throws Exception {
>> +        Class smoothie;
>> +        List<Class> ingredients;
>> +
>> +        // No remotes
>> +        smoothie = implement(Mango.class, Lime.class, Lemon.class);
>> +        ingredients = resolve(smoothie, Mango.class, Lime.class, 
>> Lemon.class);
>> +        assertEquals(3, ingredients.size());
>> +        assertTrue(ingredients.contains(Mango.class));
>> +        assertTrue(ingredients.contains(Lime.class));
>> +        assertTrue(ingredients.contains(Lemon.class));
>> +
>> +        // All remotes
>> +        smoothie = implement(Cherry.class, Honey.class, Grape.class);
>> +        ingredients = resolve(smoothie, Cherry.class, Honey.class, 
>> Grape.class);
>> +        assertEquals(3, ingredients.size());
>> +        assertTrue(ingredients.contains(Cherry.class));
>> +        assertTrue(ingredients.contains(Grape.class));
>> +        assertTrue(ingredients.contains(Honey.class));
>> +
>> +        // mixed remote and non-remote, no conflicts
>> +        smoothie = implement(Banana.class, Honey.class, Creme.class);
>> +        ingredients = resolve(smoothie, Banana.class, Honey.class, 
>> Creme.class);
>> +        assertEquals(3, ingredients.size());
>> +        assertTrue(ingredients.contains(Banana.class));
>> +        assertTrue(ingredients.contains(Honey.class));
>> +        assertTrue(ingredients.contains(Creme.class));
>> +
>> +        // mixed remote and non-remote, conflicts (cherry, grape)
>> +        smoothie = implement(Mango.class, Banana.class, Creme.class, 
>> Honey.class, Cherry.class, Grape.class);
>> +        ingredients = resolve(smoothie, Mango.class, Banana.class, 
>> Creme.class, Honey.class, Cherry.class, Grape.class);
>> +        assertEquals(4, ingredients.size());
>> +        assertTrue(ingredients.contains(Mango.class));
>> +        assertTrue(ingredients.contains(Banana.class));
>> +        assertTrue(ingredients.contains(Creme.class));
>> +        assertTrue(ingredients.contains(Honey.class));
>> +
>> +        // mixed remote and non-remote, conflicts (mango, banana)
>> +        smoothie = implement(Cherry.class, Mango.class, Banana.class, 
>> Creme.class, Honey.class, Grape.class);
>> +        ingredients = resolve(smoothie, Cherry.class, Mango.class, 
>> Banana.class, Creme.class, Honey.class, Grape.class);
>> +        assertEquals(4, ingredients.size());
>> +        assertTrue(ingredients.contains(Cherry.class));
>> +        assertTrue(ingredients.contains(Grape.class));
>> +        assertTrue(ingredients.contains(Creme.class));
>> +        assertTrue(ingredients.contains(Honey.class));
>> +    }
>> +
>> +    public List<Class> resolve(Class impl, Class mainInterface, 
>> Class... interfaces) {
>> +        return ProxyInterfaceResolver.getInterfaces(impl, 
>> mainInterface, Arrays.asList(interfaces));
>> +    }
>> +
>> +
>> +    public Class implement(Class<?>... interfaces) {
>> +        return 
>> java.lang.reflect.Proxy.getProxyClass(this.getClass().getClassLoader(), 
>> interfaces);
>> +    }
>> +
>> +    public interface Mango {
>> +        void exist() throws RoundException, GreenException;
>> +
>> +        void mango();
>> +    }
>> +
>> +    public interface Lime {
>> +        void exist() throws RoundException, GreenException;
>> +
>> +        void lime();
>> +    }
>> +
>> +    public interface Lemon {
>> +        void exist() throws RoundException, YellowException;
>> +
>> +        void lemon();
>> +    }
>> +
>> +    public interface Banana {
>> +        void exist() throws LongException, YellowException;
>> +
>> +        void banana();
>> +    }
>> +
>> +    public interface Creme {
>> +        void thiken();
>> +    }
>> +
>> +    public interface Cherry extends java.rmi.Remote {
>> +        void exist() throws RoundException, RemoteException;
>> +
>> +        void cherry() throws RemoteException;
>> +    }
>> +
>> +    public interface Grape extends java.rmi.Remote {
>> +        void exist() throws RoundException, RemoteException;
>> +
>> +        void grape() throws RemoteException;
>> +    }
>> +
>> +    public interface Honey extends java.rmi.Remote {
>> +        void sweeten() throws RemoteException;
>> +    }
>> +
>> +    //--------------//
>> +    public static class RoundException extends Exception {
>> +    }
>> +
>> +    public static class GreenException extends Exception {
>> +    }
>> +
>> +    public static class YellowException extends Exception {
>> +    }
>> +
>> +    public static class LongException extends Exception {
>> +    }
>> +
>> +
>> +}
>> +
>>
>>
> 
>