membersound
membersound

Reputation: 86747

How to catch errors in spring-integration socket server?

I have the following working socket server configuration, and would like to add a handler if any exception occurs, eg inside the Deserializer during read of the message.

Therefore I added a @ServiceActivator(inputChannel = "errorChannel"). But the method is never invoked. Why?

@MessageEndpoint
public class SocketEndpoint {
    @ServiceActivator(inputChannel = "mainChannel")
    public String handleMessage(String message) {
        return "normal response";

    }

    @ServiceActivator(inputChannel = "errorChannel")
    public String handleError(MessagingException message) {
        //TODO this is never invoked!
        return "some error";
    }
}

@Bean
public TcpInboundGateway mainGateway(
        @Qualifier("tcpFactory") TcpConnectionFactoryFactoryBean factory,
        @Qualifier("mainChannel") MessageChannel mainChannel,
        @Qualifier("errorChannel") MessageChannel errorChannel) throws Exception {
    TcpInboundGateway g = new TcpInboundGateway();
    g.setConnectionFactory(factory.getObject());
    g.setRequestChannel(mainChannel);
    g.setErrorChannel(errorChannel);
    return g;
}

@Bean
public TcpConnectionFactoryFactoryBean fact() {
   TcpConnectionFactoryFactoryBean f = new TcpConnectionFactoryFactoryBean();
   f.setType("server");
   //....
   f.setDeserializer(new MyDeserializer());
   return f;
}

class MyDeserializer implements Deserializer<String> {
    @Override
    public String deserialize(InputStream inputStream)
            throw new RuntimeException("catch me in error-channel");
    }
}

Upvotes: 1

Views: 226

Answers (1)

Gary Russell
Gary Russell

Reputation: 174554

throw new RuntimeException("catch me in error-channel");

It can't go to the error channel since there's no message yet (messages sent to error channels are messages that fail downstream processing).

The standard deserializers (that extend AbstractByteArraySerializer) publish a TcpDeserializationExceptionEvent when deserialization fails. See the ByteArrayCrLfSerializer for an example:

https://github.com/spring-projects/spring-integration/blob/master/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayCrLfSerializer.java#L78

public int fillToCrLf(InputStream inputStream, byte[] buffer) throws IOException {
    int n = 0;
    int bite;
    if (logger.isDebugEnabled()) {
        logger.debug("Available to read: " + inputStream.available());
    }
    try {
         ...
    }
    catch (SoftEndOfStreamException e) {
        throw e;
    }
    catch (IOException e) {
        publishEvent(e, buffer, n);
        throw e;
    }
    catch (RuntimeException e) {
        publishEvent(e, buffer, n);
        throw e;
    }
}

See the documentation. The Deserializer needs to be a bean so that it gets an event publisher.

You can then listen for the event(s) with an ApplicationListener< TcpDeserializationExceptionEvent> or an @EventListener method.

Upvotes: 1

Related Questions