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 {
>> + }
>> +
>> +
>> +}
>> +
>>
>>
>
>