Camel
  1. Camel
  2. CAMEL-3449

Change to allow proxying (of non-serializable beans) to work over protocols such as Mina/Netty

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 2.5.0
    • Fix Version/s: Future
    • Component/s: camel-core
    • Labels:
      None
    • Patch Info:
      Patch Available

      Description

      Hi,

      Hiding middleware with proxying of Pojos with transports such as JMS, or "direct: ..." is fantastically simple. However problems arise using Mina/Netty - there appears to be an issue with the default serializing codecs for these in that they cannot resolve the declaring class correctly from MethodBean used in BeanInvocation.

      I've looked at the documentation and am reasonably confident that it's not a configuration issue, but please enlighten me if it's so.

      Not spent long enough on this to understand why this happens - Class.java is Serializable and as the MethodBean is sending a definition not an instance it shouldn't matter whether the target pojo implements Serializable at all? The exceptions thrown are fairly cryptic, NullPointers from the bowels of Object stream deserialization etc.

      Anyway, by changing the MethodBean's internal rep to use the class' canonical name it's possible to enjoy painless proxying over these transports. This doesn't break any existing tests but there may be side effects of loading the class on the receiving side (not tested in OSGi or Spring envs).

      Also (issue for upstream project) Mina cannot resolve inner classes properly (uses dot not dollar).

      Some test code:
      ---------------------------------------------------------------------------------------------------------------------
      import java.io.Serializable;

      public interface HelloSerializableService extends HelloService, Serializable {}
      ---------------------------------------------------------------------------------------------------------------------
      public class HelloSerializableServiceImp implements HelloSerializableService {
      private static final long serialVersionUID = 1112126394143803848L;
      public String sayHelloTo(String who)

      { return "Hello " + who; }
      }
      ---------------------------------------------------------------------------------------------------------------------
      public interface HelloService { public String sayHelloTo(String who); }
      ---------------------------------------------------------------------------------------------------------------------
      public class HelloServiceImp implements HelloService {
      public String sayHelloTo(String who) { return "Hello " + who; }

      }
      ---------------------------------------------------------------------------------------------------------------------
      public class MethodBeanClassAsStringTest extends CamelTestSupport {

      public static final String DIRECT_TO_NONSERIAL = "direct:nonserial";
      public static final String MINA_TO_NONSERIAL = "mina:tcp://0.0.0.0:6060?sync=true&allowDefaultCodec=true";
      public static final String MINA_TO_SERIAL = "mina:tcp://0.0.0.0:6065?sync=true&allowDefaultCodec=true";

      public MethodBeanClassAsStringTest()

      { setUseRouteBuilder(true); }

      @Override
      protected RouteBuilder createRouteBuilder() throws Exception {
      return new RouteBuilder() {
      final HelloService service = new HelloServiceImp();
      final HelloSerializableService serialService = new HelloSerializableServiceImp();
      @Override
      public void configure() throws Exception

      { from(DIRECT_TO_NONSERIAL).bean(service); from(MINA_TO_NONSERIAL).bean(service); from(MINA_TO_SERIAL).bean(serialService); }

      };
      }

      @Test
      public void testDirectNonserial() throws Exception {
      Endpoint endpoint = context.getEndpoint(DIRECT_TO_NONSERIAL);
      HelloService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]

      { HelloService.class});
      String response = service.sayHelloTo("Camel");
      assertEquals("Hello Camel", response);
      }

      @Test
      public void testMinaNonserial() throws Exception {
      Endpoint endpoint = context.getEndpoint(MINA_TO_NONSERIAL);
      HelloService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]{ HelloService.class}

      );
      String response = service.sayHelloTo("Camel");
      assertEquals("Hello Camel", response);
      }

      @Test
      public void testMinaSerial() throws Exception {
      Endpoint endpoint = context.getEndpoint(MINA_TO_SERIAL);
      HelloSerializableService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]

      { HelloSerializableService.class}

      );
      String response = service.sayHelloTo("Camel");
      assertEquals("Hello Camel", response);
      }

      // https://issues.apache.org/activemq/browse/CAMEL-3341 fixed in 2.6-SNAPSHOT
      public static <T> T createProxy(Endpoint endpoint, ClassLoader cl, Class<?>[] interfaces) throws Exception

      { Producer producer = endpoint.createProducer(); ServiceHelper.startService(producer); CamelInvocationHandler invocationHandler = new CamelInvocationHandler(endpoint, producer, new MethodInfoCache(endpoint.getCamelContext())); @SuppressWarnings("unchecked") T retVal = (T) Proxy.newProxyInstance(cl, interfaces, invocationHandler); return retVal; }

      }
      ---------------------------------------------------------------------------------------------------------------------

      Exceptions from running the test without the patch:

      Sending side:
      java.lang.reflect.UndeclaredThrowableException
      at $Proxy9.sayHelloTo(Unknown Source)
      at net.earcam.camelproxy.MethodBeanClassAsStringTest.testMinaNonserial(MethodBeanClassAsStringTest.java:56)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
      at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
      at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
      Caused by: org.apache.camel.CamelExchangeException: No response received from remote server: mina://tcp://0.0.0.0:6060?allowDefaultCodec=true&sync=true. Exchange[Message: BeanInvocation public abstract java.lang.String net.earcam.camelproxy.HelloService.sayHelloTo(java.lang.String) with [Camel]]]
      at org.apache.camel.component.mina.MinaProducer.process(MinaProducer.java:133)
      at org.apache.camel.component.bean.CamelInvocationHandler.invoke(CamelInvocationHandler.java:65)
      ... 26 more

      Recieving side:
      837 [Camel Thread 21 - MinaThreadPool] WARN org.apache.camel.component.mina.MinaConsumer$ReceiveHandler - [/127.0.1.1:38374] Unexpected exception from exceptionCaught handler.
      org.apache.camel.CamelException: org.apache.mina.filter.codec.ProtocolDecoderException: java.lang.NullPointerException (Hexdump: 00 00 00 FB AC ED 00 05 73 72 01 00 2E 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 42 65 61 6E 49 6E 76 6F 63 61 74 69 6F 6E 78 70 73 72 01 00 2A 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 4D 65 74 68 6F 64 42 65 61 6E 78 70 74 00 0A 73 61 79 48 65 6C 6C 6F 54 6F 75 72 01 00 12 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 43 6C 61 73 73 3B 78 70 00 00 00 01 76 72 01 00 10 6A 61 76 61 2E 6C 61 6E 67 2E 53 74 72 69 6E 67 78 70 76 72 01 00 22 6E 65 74 2E 65 61 72 63 61 6D 2E 63 61 6D 65 6C 70 72 6F 78 79 2E 48 65 6C 6C 6F 53 65 72 76 69 63 65 78 70 75 72 01 00 13 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 3B 78 70 00 00 00 01 74 00 05 43 61 6D 65 6C 78)
      at org.apache.camel.component.mina.MinaConsumer$ReceiveHandler.exceptionCaught(MinaConsumer.java:92)
      at org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.exceptionCaught(AbstractIoFilterChain.java:564)
      at org.apache.mina.common.support.AbstractIoFilterChain.callNextExceptionCaught(AbstractIoFilterChain.java:345)
      at org.apache.mina.common.support.AbstractIoFilterChain.access$1000(AbstractIoFilterChain.java:53)
      at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.exceptionCaught(AbstractIoFilterChain.java:643)
      at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:224)
      at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:264)
      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
      at java.lang.Thread.run(Thread.java:662)
      Caused by: org.apache.mina.filter.codec.ProtocolDecoderException: java.lang.NullPointerException (Hexdump: 00 00 00 FB AC ED 00 05 73 72 01 00 2E 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 42 65 61 6E 49 6E 76 6F 63 61 74 69 6F 6E 78 70 73 72 01 00 2A 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 4D 65 74 68 6F 64 42 65 61 6E 78 70 74 00 0A 73 61 79 48 65 6C 6C 6F 54 6F 75 72 01 00 12 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 43 6C 61 73 73 3B 78 70 00 00 00 01 76 72 01 00 10 6A 61 76 61 2E 6C 61 6E 67 2E 53 74 72 69 6E 67 78 70 76 72 01 00 22 6E 65 74 2E 65 61 72 63 61 6D 2E 63 61 6D 65 6C 70 72 6F 78 79 2E 48 65 6C 6C 6F 53 65 72 76 69 63 65 78 70 75 72 01 00 13 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 3B 78 70 00 00 00 01 74 00 05 43 61 6D 65 6C 78)
      at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:165)
      at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
      at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
      at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
      at org.apache.mina.common.support.AbstractIoFilterChain$HeadFilter.messageReceived(AbstractIoFilterChain.java:499)
      at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
      at org.apache.mina.common.support.AbstractIoFilterChain.fireMessageReceived(AbstractIoFilterChain.java:293)
      at org.apache.mina.transport.socket.nio.SocketIoProcessor.read(SocketIoProcessor.java:228)
      at org.apache.mina.transport.socket.nio.SocketIoProcessor.process(SocketIoProcessor.java:198)
      at org.apache.mina.transport.socket.nio.SocketIoProcessor.access$400(SocketIoProcessor.java:45)
      at org.apache.mina.transport.socket.nio.SocketIoProcessor$Worker.run(SocketIoProcessor.java:485)
      at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
      ... 3 more
      Caused by: java.lang.NullPointerException
      at org.apache.mina.common.ByteBuffer$3.resolveClass(ByteBuffer.java:1529)
      at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
      at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
      at java.io.ObjectInputStream.readClass(ObjectInputStream.java:1461)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1311)
      at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1946)
      at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1870)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
      at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
      at org.apache.camel.component.bean.BeanInvocation.readExternal(BeanInvocation.java:99)
      at java.io.ObjectInputStream.readExternalData(ObjectInputStream.java:1791)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
      at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
      at org.apache.mina.common.ByteBuffer.getObject(ByteBuffer.java:1537)
      at org.apache.mina.filter.codec.serialization.ObjectSerializationDecoder.doDecode(ObjectSerializationDecoder.java:92)
      at org.apache.mina.filter.codec.CumulativeProtocolDecoder.decode(CumulativeProtocolDecoder.java:133)
      at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:158)
      ... 14 more

      1. camel-core.patch
        2 kB
        Caspar MacRae

        Activity

        Caspar MacRae created issue -
        Caspar MacRae made changes -
        Field Original Value New Value
        Attachment camel-core.patch [ 12466645 ]
        Claus Ibsen made changes -
        Fix Version/s Future [ 12315692 ]
        Fix Version/s 2.6.0 [ 12315690 ]
        Description
        Hi,

        Hiding middleware with proxying of Pojos with transports such as JMS, or "direct: ..." is fantastically simple. However problems arise using Mina/Netty - there appears to be an issue with the default serializing codecs for these in that they cannot resolve the declaring class correctly from MethodBean used in BeanInvocation.

        I've looked at the documentation and am reasonably confident that it's not a configuration issue, but please enlighten me if it's so.

        Not spent long enough on this to understand why this happens - Class.java is Serializable and as the MethodBean is sending a definition not an instance it shouldn't matter whether the target pojo implements Serializable at all? The exceptions thrown are fairly cryptic, NullPointers from the bowels of Object stream deserialization etc.

        Anyway, by changing the MethodBean's internal rep to use the class' canonical name it's possible to enjoy painless proxying over these transports. This doesn't break any existing tests but there may be side effects of loading the class on the receiving side (not tested in OSGi or Spring envs).


        Also (issue for upstream project) Mina cannot resolve inner classes properly (uses dot not dollar).



        Some test code:
        ---------------------------------------------------------------------------------------------------------------------
        import java.io.Serializable;

        public interface HelloSerializableService extends HelloService, Serializable {}
        ---------------------------------------------------------------------------------------------------------------------
        public class HelloSerializableServiceImp implements HelloSerializableService {
        private static final long serialVersionUID = 1112126394143803848L;
        public String sayHelloTo(String who) {
        return "Hello " + who;
        }
        }
        ---------------------------------------------------------------------------------------------------------------------
        public interface HelloService {
        public String sayHelloTo(String who);
        }
        ---------------------------------------------------------------------------------------------------------------------
        public class HelloServiceImp implements HelloService {
        public String sayHelloTo(String who) {
        return "Hello " + who;
        }
        }
        ---------------------------------------------------------------------------------------------------------------------
        public class MethodBeanClassAsStringTest extends CamelTestSupport {

        public static final String DIRECT_TO_NONSERIAL = "direct:nonserial";
        public static final String MINA_TO_NONSERIAL = "mina:tcp://0.0.0.0:6060?sync=true&allowDefaultCodec=true";
        public static final String MINA_TO_SERIAL = "mina:tcp://0.0.0.0:6065?sync=true&allowDefaultCodec=true";


        public MethodBeanClassAsStringTest() {
        setUseRouteBuilder(true);
        }


        @Override
        protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
        final HelloService service = new HelloServiceImp();
        final HelloSerializableService serialService = new HelloSerializableServiceImp();
        @Override
        public void configure() throws Exception {
        from(DIRECT_TO_NONSERIAL).bean(service);
        from(MINA_TO_NONSERIAL).bean(service);
        from(MINA_TO_SERIAL).bean(serialService);
        }
        };
        }

        @Test
        public void testDirectNonserial() throws Exception {
        Endpoint endpoint = context.getEndpoint(DIRECT_TO_NONSERIAL);
        HelloService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]{ HelloService.class});
        String response = service.sayHelloTo("Camel");
        assertEquals("Hello Camel", response);
        }

        @Test
        public void testMinaNonserial() throws Exception {
        Endpoint endpoint = context.getEndpoint(MINA_TO_NONSERIAL);
        HelloService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]{ HelloService.class});
        String response = service.sayHelloTo("Camel");
        assertEquals("Hello Camel", response);
        }

        @Test
        public void testMinaSerial() throws Exception {
        Endpoint endpoint = context.getEndpoint(MINA_TO_SERIAL);
        HelloSerializableService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]{ HelloSerializableService.class});
        String response = service.sayHelloTo("Camel");
        assertEquals("Hello Camel", response);
        }


        // https://issues.apache.org/activemq/browse/CAMEL-3341 fixed in 2.6-SNAPSHOT
        public static <T> T createProxy(Endpoint endpoint, ClassLoader cl, Class<?>[] interfaces) throws Exception {
        Producer producer = endpoint.createProducer();
        ServiceHelper.startService(producer);
        CamelInvocationHandler invocationHandler = new CamelInvocationHandler(endpoint, producer, new MethodInfoCache(endpoint.getCamelContext()));
        @SuppressWarnings("unchecked")
        T retVal = (T) Proxy.newProxyInstance(cl, interfaces, invocationHandler);
        return retVal;
        }

        }
        ---------------------------------------------------------------------------------------------------------------------



        Exceptions from running the test without the patch:

        Sending side:
        java.lang.reflect.UndeclaredThrowableException
        at $Proxy9.sayHelloTo(Unknown Source)
        at net.earcam.camelproxy.MethodBeanClassAsStringTest.testMinaNonserial(MethodBeanClassAsStringTest.java:56)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
        Caused by: org.apache.camel.CamelExchangeException: No response received from remote server: mina://tcp://0.0.0.0:6060?allowDefaultCodec=true&sync=true. Exchange[Message: BeanInvocation public abstract java.lang.String net.earcam.camelproxy.HelloService.sayHelloTo(java.lang.String) with [Camel]]]
        at org.apache.camel.component.mina.MinaProducer.process(MinaProducer.java:133)
        at org.apache.camel.component.bean.CamelInvocationHandler.invoke(CamelInvocationHandler.java:65)
        ... 26 more



        Recieving side:
        837 [Camel Thread 21 - MinaThreadPool] WARN org.apache.camel.component.mina.MinaConsumer$ReceiveHandler - [/127.0.1.1:38374] Unexpected exception from exceptionCaught handler.
        org.apache.camel.CamelException: org.apache.mina.filter.codec.ProtocolDecoderException: java.lang.NullPointerException (Hexdump: 00 00 00 FB AC ED 00 05 73 72 01 00 2E 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 42 65 61 6E 49 6E 76 6F 63 61 74 69 6F 6E 78 70 73 72 01 00 2A 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 4D 65 74 68 6F 64 42 65 61 6E 78 70 74 00 0A 73 61 79 48 65 6C 6C 6F 54 6F 75 72 01 00 12 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 43 6C 61 73 73 3B 78 70 00 00 00 01 76 72 01 00 10 6A 61 76 61 2E 6C 61 6E 67 2E 53 74 72 69 6E 67 78 70 76 72 01 00 22 6E 65 74 2E 65 61 72 63 61 6D 2E 63 61 6D 65 6C 70 72 6F 78 79 2E 48 65 6C 6C 6F 53 65 72 76 69 63 65 78 70 75 72 01 00 13 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 3B 78 70 00 00 00 01 74 00 05 43 61 6D 65 6C 78)
        at org.apache.camel.component.mina.MinaConsumer$ReceiveHandler.exceptionCaught(MinaConsumer.java:92)
        at org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.exceptionCaught(AbstractIoFilterChain.java:564)
        at org.apache.mina.common.support.AbstractIoFilterChain.callNextExceptionCaught(AbstractIoFilterChain.java:345)
        at org.apache.mina.common.support.AbstractIoFilterChain.access$1000(AbstractIoFilterChain.java:53)
        at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.exceptionCaught(AbstractIoFilterChain.java:643)
        at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:224)
        at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:264)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
        Caused by: org.apache.mina.filter.codec.ProtocolDecoderException: java.lang.NullPointerException (Hexdump: 00 00 00 FB AC ED 00 05 73 72 01 00 2E 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 42 65 61 6E 49 6E 76 6F 63 61 74 69 6F 6E 78 70 73 72 01 00 2A 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 4D 65 74 68 6F 64 42 65 61 6E 78 70 74 00 0A 73 61 79 48 65 6C 6C 6F 54 6F 75 72 01 00 12 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 43 6C 61 73 73 3B 78 70 00 00 00 01 76 72 01 00 10 6A 61 76 61 2E 6C 61 6E 67 2E 53 74 72 69 6E 67 78 70 76 72 01 00 22 6E 65 74 2E 65 61 72 63 61 6D 2E 63 61 6D 65 6C 70 72 6F 78 79 2E 48 65 6C 6C 6F 53 65 72 76 69 63 65 78 70 75 72 01 00 13 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 3B 78 70 00 00 00 01 74 00 05 43 61 6D 65 6C 78)
        at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:165)
        at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
        at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
        at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
        at org.apache.mina.common.support.AbstractIoFilterChain$HeadFilter.messageReceived(AbstractIoFilterChain.java:499)
        at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
        at org.apache.mina.common.support.AbstractIoFilterChain.fireMessageReceived(AbstractIoFilterChain.java:293)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor.read(SocketIoProcessor.java:228)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor.process(SocketIoProcessor.java:198)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor.access$400(SocketIoProcessor.java:45)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor$Worker.run(SocketIoProcessor.java:485)
        at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
        ... 3 more
        Caused by: java.lang.NullPointerException
        at org.apache.mina.common.ByteBuffer$3.resolveClass(ByteBuffer.java:1529)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
        at java.io.ObjectInputStream.readClass(ObjectInputStream.java:1461)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1311)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1946)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1870)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
        at org.apache.camel.component.bean.BeanInvocation.readExternal(BeanInvocation.java:99)
        at java.io.ObjectInputStream.readExternalData(ObjectInputStream.java:1791)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
        at org.apache.mina.common.ByteBuffer.getObject(ByteBuffer.java:1537)
        at org.apache.mina.filter.codec.serialization.ObjectSerializationDecoder.doDecode(ObjectSerializationDecoder.java:92)
        at org.apache.mina.filter.codec.CumulativeProtocolDecoder.decode(CumulativeProtocolDecoder.java:133)
        at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:158)
        ... 14 more
        Hi,

        Hiding middleware with proxying of Pojos with transports such as JMS, or "direct: ..." is fantastically simple. However problems arise using Mina/Netty - there appears to be an issue with the default serializing codecs for these in that they cannot resolve the declaring class correctly from MethodBean used in BeanInvocation.

        I've looked at the documentation and am reasonably confident that it's not a configuration issue, but please enlighten me if it's so.

        Not spent long enough on this to understand why this happens - Class.java is Serializable and as the MethodBean is sending a definition not an instance it shouldn't matter whether the target pojo implements Serializable at all? The exceptions thrown are fairly cryptic, NullPointers from the bowels of Object stream deserialization etc.

        Anyway, by changing the MethodBean's internal rep to use the class' canonical name it's possible to enjoy painless proxying over these transports. This doesn't break any existing tests but there may be side effects of loading the class on the receiving side (not tested in OSGi or Spring envs).


        Also (issue for upstream project) Mina cannot resolve inner classes properly (uses dot not dollar).



        Some test code:
        ---------------------------------------------------------------------------------------------------------------------
        import java.io.Serializable;

        public interface HelloSerializableService extends HelloService, Serializable {}
        ---------------------------------------------------------------------------------------------------------------------
        public class HelloSerializableServiceImp implements HelloSerializableService {
        private static final long serialVersionUID = 1112126394143803848L;
        public String sayHelloTo(String who) {
        return "Hello " + who;
        }
        }
        ---------------------------------------------------------------------------------------------------------------------
        public interface HelloService {
        public String sayHelloTo(String who);
        }
        ---------------------------------------------------------------------------------------------------------------------
        public class HelloServiceImp implements HelloService {
        public String sayHelloTo(String who) {
        return "Hello " + who;
        }
        }
        ---------------------------------------------------------------------------------------------------------------------
        public class MethodBeanClassAsStringTest extends CamelTestSupport {

        public static final String DIRECT_TO_NONSERIAL = "direct:nonserial";
        public static final String MINA_TO_NONSERIAL = "mina:tcp://0.0.0.0:6060?sync=true&allowDefaultCodec=true";
        public static final String MINA_TO_SERIAL = "mina:tcp://0.0.0.0:6065?sync=true&allowDefaultCodec=true";


        public MethodBeanClassAsStringTest() {
        setUseRouteBuilder(true);
        }


        @Override
        protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
        final HelloService service = new HelloServiceImp();
        final HelloSerializableService serialService = new HelloSerializableServiceImp();
        @Override
        public void configure() throws Exception {
        from(DIRECT_TO_NONSERIAL).bean(service);
        from(MINA_TO_NONSERIAL).bean(service);
        from(MINA_TO_SERIAL).bean(serialService);
        }
        };
        }

        @Test
        public void testDirectNonserial() throws Exception {
        Endpoint endpoint = context.getEndpoint(DIRECT_TO_NONSERIAL);
        HelloService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]{ HelloService.class});
        String response = service.sayHelloTo("Camel");
        assertEquals("Hello Camel", response);
        }

        @Test
        public void testMinaNonserial() throws Exception {
        Endpoint endpoint = context.getEndpoint(MINA_TO_NONSERIAL);
        HelloService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]{ HelloService.class});
        String response = service.sayHelloTo("Camel");
        assertEquals("Hello Camel", response);
        }

        @Test
        public void testMinaSerial() throws Exception {
        Endpoint endpoint = context.getEndpoint(MINA_TO_SERIAL);
        HelloSerializableService service = createProxy(endpoint, getClass().getClassLoader(), new Class<?>[]{ HelloSerializableService.class});
        String response = service.sayHelloTo("Camel");
        assertEquals("Hello Camel", response);
        }


        // https://issues.apache.org/activemq/browse/CAMEL-3341 fixed in 2.6-SNAPSHOT
        public static <T> T createProxy(Endpoint endpoint, ClassLoader cl, Class<?>[] interfaces) throws Exception {
        Producer producer = endpoint.createProducer();
        ServiceHelper.startService(producer);
        CamelInvocationHandler invocationHandler = new CamelInvocationHandler(endpoint, producer, new MethodInfoCache(endpoint.getCamelContext()));
        @SuppressWarnings("unchecked")
        T retVal = (T) Proxy.newProxyInstance(cl, interfaces, invocationHandler);
        return retVal;
        }

        }
        ---------------------------------------------------------------------------------------------------------------------



        Exceptions from running the test without the patch:

        Sending side:
        java.lang.reflect.UndeclaredThrowableException
        at $Proxy9.sayHelloTo(Unknown Source)
        at net.earcam.camelproxy.MethodBeanClassAsStringTest.testMinaNonserial(MethodBeanClassAsStringTest.java:56)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
        Caused by: org.apache.camel.CamelExchangeException: No response received from remote server: mina://tcp://0.0.0.0:6060?allowDefaultCodec=true&sync=true. Exchange[Message: BeanInvocation public abstract java.lang.String net.earcam.camelproxy.HelloService.sayHelloTo(java.lang.String) with [Camel]]]
        at org.apache.camel.component.mina.MinaProducer.process(MinaProducer.java:133)
        at org.apache.camel.component.bean.CamelInvocationHandler.invoke(CamelInvocationHandler.java:65)
        ... 26 more



        Recieving side:
        837 [Camel Thread 21 - MinaThreadPool] WARN org.apache.camel.component.mina.MinaConsumer$ReceiveHandler - [/127.0.1.1:38374] Unexpected exception from exceptionCaught handler.
        org.apache.camel.CamelException: org.apache.mina.filter.codec.ProtocolDecoderException: java.lang.NullPointerException (Hexdump: 00 00 00 FB AC ED 00 05 73 72 01 00 2E 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 42 65 61 6E 49 6E 76 6F 63 61 74 69 6F 6E 78 70 73 72 01 00 2A 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 4D 65 74 68 6F 64 42 65 61 6E 78 70 74 00 0A 73 61 79 48 65 6C 6C 6F 54 6F 75 72 01 00 12 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 43 6C 61 73 73 3B 78 70 00 00 00 01 76 72 01 00 10 6A 61 76 61 2E 6C 61 6E 67 2E 53 74 72 69 6E 67 78 70 76 72 01 00 22 6E 65 74 2E 65 61 72 63 61 6D 2E 63 61 6D 65 6C 70 72 6F 78 79 2E 48 65 6C 6C 6F 53 65 72 76 69 63 65 78 70 75 72 01 00 13 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 3B 78 70 00 00 00 01 74 00 05 43 61 6D 65 6C 78)
        at org.apache.camel.component.mina.MinaConsumer$ReceiveHandler.exceptionCaught(MinaConsumer.java:92)
        at org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.exceptionCaught(AbstractIoFilterChain.java:564)
        at org.apache.mina.common.support.AbstractIoFilterChain.callNextExceptionCaught(AbstractIoFilterChain.java:345)
        at org.apache.mina.common.support.AbstractIoFilterChain.access$1000(AbstractIoFilterChain.java:53)
        at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.exceptionCaught(AbstractIoFilterChain.java:643)
        at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:224)
        at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:264)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
        Caused by: org.apache.mina.filter.codec.ProtocolDecoderException: java.lang.NullPointerException (Hexdump: 00 00 00 FB AC ED 00 05 73 72 01 00 2E 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 42 65 61 6E 49 6E 76 6F 63 61 74 69 6F 6E 78 70 73 72 01 00 2A 6F 72 67 2E 61 70 61 63 68 65 2E 63 61 6D 65 6C 2E 63 6F 6D 70 6F 6E 65 6E 74 2E 62 65 61 6E 2E 4D 65 74 68 6F 64 42 65 61 6E 78 70 74 00 0A 73 61 79 48 65 6C 6C 6F 54 6F 75 72 01 00 12 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 43 6C 61 73 73 3B 78 70 00 00 00 01 76 72 01 00 10 6A 61 76 61 2E 6C 61 6E 67 2E 53 74 72 69 6E 67 78 70 76 72 01 00 22 6E 65 74 2E 65 61 72 63 61 6D 2E 63 61 6D 65 6C 70 72 6F 78 79 2E 48 65 6C 6C 6F 53 65 72 76 69 63 65 78 70 75 72 01 00 13 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 3B 78 70 00 00 00 01 74 00 05 43 61 6D 65 6C 78)
        at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:165)
        at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
        at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
        at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
        at org.apache.mina.common.support.AbstractIoFilterChain$HeadFilter.messageReceived(AbstractIoFilterChain.java:499)
        at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
        at org.apache.mina.common.support.AbstractIoFilterChain.fireMessageReceived(AbstractIoFilterChain.java:293)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor.read(SocketIoProcessor.java:228)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor.process(SocketIoProcessor.java:198)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor.access$400(SocketIoProcessor.java:45)
        at org.apache.mina.transport.socket.nio.SocketIoProcessor$Worker.run(SocketIoProcessor.java:485)
        at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
        ... 3 more
        Caused by: java.lang.NullPointerException
        at org.apache.mina.common.ByteBuffer$3.resolveClass(ByteBuffer.java:1529)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
        at java.io.ObjectInputStream.readClass(ObjectInputStream.java:1461)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1311)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1946)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1870)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
        at org.apache.camel.component.bean.BeanInvocation.readExternal(BeanInvocation.java:99)
        at java.io.ObjectInputStream.readExternalData(ObjectInputStream.java:1791)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
        at org.apache.mina.common.ByteBuffer.getObject(ByteBuffer.java:1537)
        at org.apache.mina.filter.codec.serialization.ObjectSerializationDecoder.doDecode(ObjectSerializationDecoder.java:92)
        at org.apache.mina.filter.codec.CumulativeProtocolDecoder.decode(CumulativeProtocolDecoder.java:133)
        at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:158)
        ... 14 more

          People

          • Assignee:
            Unassigned
            Reporter:
            Caspar MacRae
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development