Repository: tomee Updated Branches: refs/heads/master 64ca1f3e9 -> 2aeae2be3
ensure we can proxy correctly JCA connections even without a noarg constructor Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/2aeae2be Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/2aeae2be Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/2aeae2be Branch: refs/heads/master Commit: 2aeae2be3cc8cd4b143447c1169c1df9ce2e01e5 Parents: 64ca1f3 Author: Romain manni-Bucau <rmannibu...@gmail.com> Authored: Fri Aug 19 12:07:00 2016 +0200 Committer: Romain manni-Bucau <rmannibu...@gmail.com> Committed: Fri Aug 19 12:07:00 2016 +0200 ---------------------------------------------------------------------- .../openejb/resource/AutoConnectionTracker.java | 23 +- .../ConnectorProxyNoNoArgConstructorTest.java | 293 +++++++++++++++++++ 2 files changed, 315 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/2aeae2be/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java index b7444de..0a26bad 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java @@ -34,14 +34,18 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import static org.apache.commons.lang3.ClassUtils.getAllInterfaces; + public class AutoConnectionTracker implements ConnectionTracker { private final ConcurrentMap<ManagedConnectionInfo, ProxyPhantomReference> references = new ConcurrentHashMap<ManagedConnectionInfo, ProxyPhantomReference>(); private final ReferenceQueue referenceQueue = new ReferenceQueue(); private final ConcurrentMap<Class<?>, Class<?>> proxies = new ConcurrentHashMap<>(); + private final ConcurrentMap<Class<?>, Class<?>[]> interfaces = new ConcurrentHashMap<>(); public Set<ManagedConnectionInfo> connections() { return references.keySet(); @@ -135,7 +139,24 @@ public class AutoConnectionTracker implements ConnectionTracker { // no-op } } - return Proxy.newProxyInstance(loader, handle.getClass().getInterfaces(), invocationHandler); + + return Proxy.newProxyInstance(loader, getAPi(handle.getClass()), invocationHandler); + } + + private Class<?>[] getAPi(final Class<?> aClass) { + Class<?>[] found = interfaces.get(aClass); + if (found == null) { + synchronized (this) { + found = interfaces.get(aClass); + if (found == null) { + final List<Class<?>> allInterfaces = getAllInterfaces(aClass); + final Class<?>[] asArray = allInterfaces.toArray(new Class<?>[allInterfaces.size()]); + interfaces.put(aClass, asArray); + found = interfaces.get(aClass); + } + } + } + return found; } private Class<?> getProxy(final Class<?> aClass, final ClassLoader loader) { http://git-wip-us.apache.org/repos/asf/tomee/blob/2aeae2be/container/openejb-core/src/test/java/org/apache/openejb/config/ConnectorProxyNoNoArgConstructorTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/config/ConnectorProxyNoNoArgConstructorTest.java b/container/openejb-core/src/test/java/org/apache/openejb/config/ConnectorProxyNoNoArgConstructorTest.java new file mode 100644 index 0000000..c0d2e13 --- /dev/null +++ b/container/openejb-core/src/test/java/org/apache/openejb/config/ConnectorProxyNoNoArgConstructorTest.java @@ -0,0 +1,293 @@ +/* + * 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.config; + +import org.apache.openejb.jee.ConnectionDefinition; +import org.apache.openejb.jee.Connector; +import org.apache.openejb.jee.OutboundResourceAdapter; +import org.apache.openejb.jee.ResourceAdapter; +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.loader.SystemInstance; +import org.apache.openejb.spi.ContainerSystem; +import org.apache.openejb.testing.Module; +import org.apache.openejb.testing.SimpleLog; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.resource.ResourceException; +import javax.resource.cci.Connection; +import javax.resource.cci.ConnectionFactory; +import javax.resource.cci.ConnectionMetaData; +import javax.resource.cci.ConnectionSpec; +import javax.resource.cci.Interaction; +import javax.resource.cci.RecordFactory; +import javax.resource.cci.ResourceAdapterMetaData; +import javax.resource.cci.ResultSetInfo; +import javax.resource.spi.ActivationSpec; +import javax.resource.spi.BootstrapContext; +import javax.resource.spi.ConnectionEventListener; +import javax.resource.spi.ConnectionManager; +import javax.resource.spi.ConnectionRequestInfo; +import javax.resource.spi.LocalTransaction; +import javax.resource.spi.ManagedConnection; +import javax.resource.spi.ManagedConnectionFactory; +import javax.resource.spi.ManagedConnectionMetaData; +import javax.resource.spi.ResourceAdapterInternalException; +import javax.resource.spi.endpoint.MessageEndpointFactory; +import javax.security.auth.Subject; +import javax.transaction.xa.XAResource; +import java.io.PrintWriter; +import java.util.Set; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +// dev note: the RA impl is very suspicious but it tests the fact we proxy the connection +@SimpleLog +@RunWith(ApplicationComposer.class) +public class ConnectorProxyNoNoArgConstructorTest { + @Module + public Connector connector() { + final ConnectionDefinition connectionDefinition = new ConnectionDefinition(); + connectionDefinition.setId("cf"); + connectionDefinition.setConnectionImplClass(MyCon.class.getName()); + connectionDefinition.setConnectionInterface(MyConAPI.class.getName()); + connectionDefinition.setConnectionFactoryImplClass(MyMcf.class.getName()); + connectionDefinition.setConnectionFactoryInterface(ConnectionFactory.class.getName()); + connectionDefinition.setManagedConnectionFactoryClass(MyMcf.class.getName()); + + final OutboundResourceAdapter out = new OutboundResourceAdapter(); + out.getConnectionDefinition().add(connectionDefinition); + + final ResourceAdapter ra = new ResourceAdapter(); + ra.setResourceAdapterClass(MyRa.class.getName()); + ra.setOutboundResourceAdapter(out); + + final Connector connector = new Connector(); + connector.setVersion("1.7"); + connector.setResourceAdapter(ra); + return connector; + } + + @Test + public void run() throws NamingException, ResourceException { + final MyCf jndi = MyCf.class.cast(SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext().lookup("openejb:Resource/cf")); + assertNotNull(jndi); + + final Connection connection = jndi.getConnection(); + assertTrue(MyConAPI.class.isInstance(connection)); + assertFalse(MyCon.class.isInstance(connection)); + } + + public static class MyRa implements javax.resource.spi.ResourceAdapter { + @Override + public void start(final BootstrapContext ctx) throws ResourceAdapterInternalException { + // no-op + } + + @Override + public void stop() { + // no-op + } + + @Override + public void endpointActivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec) throws ResourceException { + // no-op + } + + @Override + public void endpointDeactivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec) { + // no-op + } + + @Override + public XAResource[] getXAResources(final ActivationSpec[] specs) throws ResourceException { + return new XAResource[0]; + } + } + + public static class MyCf implements ConnectionFactory { + private final ConnectionManager mgr; + private final ManagedConnectionFactory mcf; + + public MyCf(final MyMcf myMcf, final ConnectionManager cxManager) { + this.mcf = myMcf; + this.mgr = cxManager; + } + + @Override + public Connection getConnection() throws ResourceException { + return MyConAPI.class/*impl, this is what we want to test*/.cast(mgr.allocateConnection(mcf, new ConnectionRequestInfo() { + })); + } + + @Override + public Connection getConnection(ConnectionSpec properties) throws ResourceException { + return getConnection(); + } + + @Override + public RecordFactory getRecordFactory() throws ResourceException { + return null; + } + + @Override + public ResourceAdapterMetaData getMetaData() throws ResourceException { + return null; + } + + @Override + public void setReference(Reference reference) { + + } + + @Override + public Reference getReference() throws NamingException { + return null; + } + } + + public static class MyMcf implements ManagedConnectionFactory { + @Override + public Object createConnectionFactory(final ConnectionManager cxManager) throws ResourceException { + return new MyCf(this, cxManager); + } + + @Override + public Object createConnectionFactory() throws ResourceException { + return new MyCf(this, null); + } + + @Override + public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { + return new MyMC(); + } + + @Override + public ManagedConnection matchManagedConnections(Set connectionSet, Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws ResourceException { + + } + + @Override + public PrintWriter getLogWriter() throws ResourceException { + return null; + } + } + + public interface MyConAPI extends Connection { + } + + public static class MyCon implements MyConAPI { + public MyCon(final String noNoArgConstructor) { + // no-op + } + + public String specific() { + return "yes"; + } + + @Override + public Interaction createInteraction() throws ResourceException { + return null; + } + + @Override + public javax.resource.cci.LocalTransaction getLocalTransaction() throws ResourceException { + return null; + } + + @Override + public ConnectionMetaData getMetaData() throws ResourceException { + return null; + } + + @Override + public ResultSetInfo getResultSetInfo() throws ResourceException { + return null; + } + + @Override + public void close() throws ResourceException { + + } + } + + public static class MyMC implements ManagedConnection { + @Override + public Object getConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException { + return new MyCon("-"); + } + + @Override + public void destroy() throws ResourceException { + + } + + @Override + public void cleanup() throws ResourceException { + + } + + @Override + public void associateConnection(Object connection) throws ResourceException { + + } + + @Override + public void addConnectionEventListener(ConnectionEventListener listener) { + + } + + @Override + public void removeConnectionEventListener(ConnectionEventListener listener) { + + } + + @Override + public XAResource getXAResource() throws ResourceException { + return null; + } + + @Override + public LocalTransaction getLocalTransaction() throws ResourceException { + return null; + } + + @Override + public ManagedConnectionMetaData getMetaData() throws ResourceException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws ResourceException { + + } + + @Override + public PrintWriter getLogWriter() throws ResourceException { + return null; + } + } +}