Jersey ContainerRequestFilter causes MarshallingException - jersey

I created a new ContainerRequestFilter to print out any new request payloads that coming in, but only if the HTTP server was started with the DEBUG_MODE argument. When I send a request to my REST resource while not in DEBUG_MODE, everything works fine.
When this filter executes:
#Provider
#Priority(Priorities.USER)
public class InboundDebugFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (AuthorizationMain.DEBUG_MODE) {
System.out.println("New request at: " + requestContext.getUriInfo().getRequestUri().toString());
BufferedReader br = new BufferedReader(new InputStreamReader(requestContext.getEntityStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
br.close();
System.out.println(sb.toString());
}
}
}
I get the following long stacktrace AFTER the 2 print lines execute just fine in this filter (but before the code gets to my resource class):
javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.readFrom(MOXyJsonProvider.java:708)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:256)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:235)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:74)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
at org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:271)
at org.glassfish.jersey.server.internal.inject.EntityParamValueFactoryProvider$EntityValueFactory.provide(EntityParamValueFactoryProvider.java:96)
at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.provide(ParamValueFactoryWithSource.java:71)
at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:94)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:127)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:384)
at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: javax.json.JsonException: I/O error while parsing JSON]
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1072)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:341)
at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.readFrom(MOXyJsonProvider.java:660)
... 31 more
Caused by: Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: javax.json.JsonException: I/O error while parsing JSON
at org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalException(XMLMarshalException.java:120)
at org.eclipse.persistence.internal.oxm.record.json.JsonStructureReader.parse(JsonStructureReader.java:147)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:978)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:425)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:375)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:708)
at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:643)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:339)
... 32 more
Caused by: javax.json.JsonException: I/O error while parsing JSON
at org.glassfish.json.JsonTokenizer.read(JsonTokenizer.java:444)
at org.glassfish.json.JsonTokenizer.nextToken(JsonTokenizer.java:354)
at org.glassfish.json.JsonParserImpl$NoneContext.getNextEvent(JsonParserImpl.java:222)
at org.glassfish.json.JsonParserImpl$StateIterator.next(JsonParserImpl.java:172)
at org.glassfish.json.JsonParserImpl.next(JsonParserImpl.java:149)
at org.glassfish.json.JsonReaderImpl.read(JsonReaderImpl.java:84)
at org.eclipse.persistence.internal.oxm.record.json.JsonStructureReader.parse(JsonStructureReader.java:139)
... 38 more
Caused by: java.io.IOException
at org.glassfish.grizzly.http.io.InputBuffer.read(InputBuffer.java:341)
at org.glassfish.grizzly.http.server.NIOInputStreamImpl.read(NIOInputStreamImpl.java:83)
at org.glassfish.jersey.message.internal.EntityInputStream.read(EntityInputStream.java:102)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream.read(ReaderInterceptorExecutor.java:296)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at org.glassfish.json.JsonTokenizer.fillBuf(JsonTokenizer.java:473)
at org.glassfish.json.JsonTokenizer.read(JsonTokenizer.java:434)
... 44 more
I'm not sure what causes the problem here, any tips?

A stream can only be read once. If you read it in the filter, then the MessageBodyReader has nothing to read. This is probably causing the exception. If you are going to read the stream in the filter, then you should reset it with requestContext.setEntityStream.

Related

SpringBoot Camel (3.14.0) and ElasticSearch Integration

I'm trying to integrate Spring Boot (2.6.3) with Camel (3.14.0) to send a simple query to ElasticSearch.
The project is located at https://github.com/saavedrah/springboot-camel-elastic
I have a timer that sends a ElasticSearch query every 60 sec.
However, the following exception is generated:
2022-01-26 11:08:48.036 WARN 23668 --- [1 - timer://foo] o.a.camel.component.timer.TimerConsumer : Error processing exchange. Exchange[2578AAA06ED30CB-0000000000000000]. Caused by: [org.apache.camel.CamelExecutionException - Exception occurred during execution on the exchange: Exchange[]]
org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[]
at org.apache.camel.CamelExecutionException.wrapCamelExecutionException(CamelExecutionException.java:45) ~[camel-api-3.14.0.jar:3.14.0]
at org.apache.camel.support.AbstractExchange.setException(AbstractExchange.java:589) ~[camel-support-3.14.0.jar:3.14.0]
at org.apache.camel.support.DefaultExchange.setException(DefaultExchange.java:27) ~[camel-support-3.14.0.jar:3.14.0]
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:69) ~[camel-support-3.14.0.jar:3.14.0]
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172) ~[camel-core-processor-3.14.0.jar:3.14.0]
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:469) ~[camel-core-processor-3.14.0.jar:3.14.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:187) ~[camel-base-engine-3.14.0.jar:3.14.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64) ~[camel-base-engine-3.14.0.jar:3.14.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:184) ~[camel-core-processor-3.14.0.jar:3.14.0]
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398) ~[camel-base-engine-3.14.0.jar:3.14.0]
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210) ~[camel-timer-3.14.0.jar:3.14.0]
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76) ~[camel-timer-3.14.0.jar:3.14.0]
at java.base/java.util.TimerThread.mainLoop(Timer.java:556) ~[na:na]
at java.base/java.util.TimerThread.run(Timer.java:506) ~[na:na]
Caused by: java.lang.NoClassDefFoundError: org/elasticsearch/common/CheckedConsumer
at org.apache.camel.component.elasticsearch.ElasticsearchProducer$HighLevelClient.<init>(ElasticsearchProducer.java:347) ~[camel-elasticsearch-rest-3.14.0.jar:3.14.0]
at org.apache.camel.component.elasticsearch.ElasticsearchProducer$HighLevelClient.<init>(ElasticsearchProducer.java:345) ~[camel-elasticsearch-rest-3.14.0.jar:3.14.0]
at org.apache.camel.component.elasticsearch.ElasticsearchProducer.process(ElasticsearchProducer.java:124) ~[camel-elasticsearch-rest-3.14.0.jar:3.14.0]
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66) ~[camel-support-3.14.0.jar:3.14.0]
... 10 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.elasticsearch.common.CheckedConsumer
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581) ~[na:na]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
... 14 common frames omitted
UPDATE 1
Accordingly with this site CAMEL-17183 the downloaded version of ElasticSearch (7.15.2) does not have the [org.elasticsearch.common.CheckedConsumer] class.
So, how should I update the gradle.properties to get the supported version of ElasticSearch(7.8.0) ?
UPDATE 2
Gradle properties was updated to force the version of ElasticSearch.
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('org.elasticsearch.client:elasticsearch-rest-high-level-client') with module('org.elasticsearch.client:elasticsearch-rest-high-level-client:7.8.0')
substitute module('org.elasticsearch.client:elasticsearch-rest-client') with module('org.elasticsearch.client:elasticsearch-rest-client:7.8.0')
substitute module('org.elasticsearch:elasticsearch') with module('org.elasticsearch:elasticsearch:7.8.0')
}
}
}
And now I'm getting the following exception, I guess it is related with the lack of parameters passed to the query...
java.lang.IllegalArgumentException: Wrong body type. Only Map, String or SearchRequest is allowed as a type
at org.apache.camel.component.elasticsearch.ElasticsearchProducer.process(ElasticsearchProducer.java:232)
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:469)
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:187)
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:184)
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398)
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210)
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)
at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
at java.base/java.util.TimerThread.run(Timer.java:506)
13:13:25.219 [Camel (camel-1) thread #1 - timer://foo] WARN o.a.c.component.timer.TimerConsumer - Error processing exchange. Exchange[DB28E010007B18C-0000000000000006]. Caused by: [java.lang.IllegalArgumentException - Wrong body type. Only Map, String or SearchRequest is allowed as a type]
java.lang.IllegalArgumentException: Wrong body type. Only Map, String or SearchRequest is allowed as a type
at org.apache.camel.component.elasticsearch.ElasticsearchProducer.process(ElasticsearchProducer.java:232)
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:469)
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:187)
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:184)
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398)
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210)
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)
at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
at java.base/java.util.TimerThread.run(Timer.java:506)
Any help is appreciated.
What Huang was telling me was that I should put some query in my timer component body to pass it to the Search operation, something like:
from("timer://foo?fixedRate=true&period=60000")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody("{\"query\":{\"match_all\":{}}}");
}
})
.to("direct:search");
from("direct:search")
.to("elasticsearch-rest://elasticsearch?operation=Search&indexName=twitter");
Thank you.

SpelEvaluationException when initiating GET on a SftpOutboundGateway

I have a Spring Integration Flow starting with a SFTPOutboundGateway. It should get a file from a SFTP server. The file contains Event objects in JSON format. My configuration is:
#Bean
public DirectChannelSpec sftpGetInputChannel() {
return MessageChannels.direct();
}
#Bean
public QueueChannelSpec remoteFileOutputChannel() {
return MessageChannels.queue();
}
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(5000));
return pollerMetadata;
}
#Bean
public IntegrationFlow sftpGetFlow(TransferContext context) {
return IntegrationFlows.from("sftpGetInputChannel")
.handle(Sftp.outboundGateway(sftpSessionFactory(context.getChannel()),
AbstractRemoteFileOutboundGateway.Command.GET, "payload")
.remoteDirectoryExpression(context.getRemoteDir())
.localDirectory(new File(context.getLocalDir()))
.localFilenameExpression(context.getLocalFilename())
)
.channel("remoteFileOutputChannel")
.transform(Transformers.fromJson(Event[].class))
.get();
}
To get a file from the SFTP server I send a message to the gateway's input channel "sftpGetInputChannel":
boolean sent = sftpGetInputChannel.send(new GenericMessage<>(env.getRemoteDir() + "/" + env.getRemoteFilename()));
An SpelEvaluationException is thrown when trying to interprete the given filename. Both fields, remoteDir and remoteFilename are of type String:
org.springframework.messaging.MessageHandlingException: error occurred in message handler [bean 'sftpGetFlow.sftp:outbound-gateway#0' for component 'sftpGetFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0'; defined in: 'class path resource [com/harry/potter/job/config/SftpConfiguration.class]'; from source: 'bean method sftpGetFlow']; nested exception is org.springframework.messaging.MessagingException: Failed to execute on session; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:192)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:79)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:115)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:133)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:106)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:72)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:570)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:520)
at com.harry.potter.job.MyTask.getFile(MyEventsTask.java:170)
at com.harry.potter.job.myTask.runAsTask(MyEventsTask.java:112)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:836)
Caused by: org.springframework.messaging.MessagingException: Failed to execute on session; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:448)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.doGet(AbstractRemoteFileOutboundGateway.java:680)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.handleRequestMessage(AbstractRemoteFileOutboundGateway.java:584)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:134)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:62)
... 21 common frames omitted
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:75)
at org.springframework.expression.common.ExpressionUtils.convertTypedValue(ExpressionUtils.java:57)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:377)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.generateLocalFileName(AbstractRemoteFileOutboundGateway.java:1316)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.get(AbstractRemoteFileOutboundGateway.java:1081)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.lambda$doGet$6(AbstractRemoteFileOutboundGateway.java:681)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway$$Lambda$30183/0x0000000000000000.doInSession(Unknown Source)
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:439)
... 25 common frames omitted
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.messaging.support.GenericMessage<?>] to type [java.lang.String]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:70)
... 32 common frames omitted
What do I wrong?
Okay, the problem is not within the message to get the file but in the configuration of the gateway:
.localFilenameExpression(context.getLocalFilename())
Just to set the local filename as expression is not allowed because dots - often part of the filename - is a SpEL delimiter to separate bean from method name. Hence the expression becomes invalid.
Possible expression would be:
.localFilenameExpression("#remoteFileName")
See its JavaDocs:
/**
* Specify a SpEL expression for local files renaming after downloading.
* #param localFilenameExpression the SpEL expression to use.
* #return the Spec.
*/
public S localFilenameExpression(String localFilenameExpression) {
And here is some code snippet how it works:
private String generateLocalFileName(Message<?> message, String remoteFileName) {
if (this.localFilenameGeneratorExpression != null) {
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
evaluationContext.setVariable("remoteFileName", remoteFileName);
return this.localFilenameGeneratorExpression.getValue(evaluationContext, message, String.class);
}
return remoteFileName;
}
The expression you can provide should somehow be in the context of the currently downloaded remote file. Not sure what is yours static context.getLocalFilename(). You can build a local file name based on the request message and that remoteFileName variable contexts.
See more in docs: https://docs.spring.io/spring-integration/docs/current/reference/html/sftp.html#configuring-with-the-java-dsl-3
The sample over there is like this:
.localDirectoryExpression("'myDir/' + #remoteDirectory")
.localFilenameExpression("#remoteFileName.replaceFirst('sftpSource', 'localTarget')"))

Consumers from Rabbit were stopped and never recover

My spring boot application has been running with no erros during months using RabbitMq. In the last weeks, my consumer stopped working and I have to restart my application. Everyday I have to restart the application.
I noticed that it happens after this error in my log:
24-07-2021 07:20:08.138 [SimpleAsyncTaskExecutor-1] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 17002, SQLState: 08006
24-07-2021 07:20:08.295 [SimpleAsyncTaskExecutor-1] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - IO Error: Socket read interrupted, Authentication lapse 682 ms.
24-07-2021 07:20:10.608 [SimpleAsyncTaskExecutor-1] WARN o.s.a.r.l.ConditionalRejectingErrorHandler - Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener method 'protected void br.jus.tjmg.certidaoEmissao.application.queues.EmissaoCriminalHistoricaConsumer.processaMensagem(br.jus.tjmg.certidao.webservice.ConsultaCertidoesRequest)' threw exception
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:198)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:127)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1477)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1400)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1387)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1366)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:848)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:832)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:78)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1073)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:450)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:378)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:474)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:289)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at br.jus.tjmg.certidaoEmissao.application.services.EmissaoCertidaoService$$EnhancerBySpringCGLIB$$46f4e1c7.atualizarExecucaoCertidao(<generated>)
at br.jus.tjmg.certidaoEmissao.application.queues.EmissaoCriminalHistoricaConsumer.processaMensagem(EmissaoCriminalHistoricaConsumer.java:35)
at sun.reflect.GeneratedMethodAccessor49.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:181)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:114)
at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:51)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:190)
... 10 common frames omitted
Caused by: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:115)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:109)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:136)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:254)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:262)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:214)
at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:56)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:162)
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:400)
... 25 common frames omitted
Caused by: java.sql.SQLRecoverableException: IO Error: Socket read interrupted, Authentication lapse 682 ms.
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:794)
at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:688)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:39)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:691)
at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSource.java:384)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:273)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:198)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:176)
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:35)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:106)
... 32 common frames omitted
Caused by: java.io.IOException: Socket read interrupted, Authentication lapse 682 ms.
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:790)
... 42 common frames omitted
Caused by: java.net.SocketTimeoutException: Socket read interrupted
at oracle.net.nt.TimeoutSocketChannel.read(TimeoutSocketChannel.java:152)
at oracle.net.ns.NIOHeader.readHeaderBuffer(NIOHeader.java:82)
at oracle.net.ns.NIOPacket.readFromSocketChannel(NIOPacket.java:139)
at oracle.net.ns.NIOPacket.readFromSocketChannel(NIOPacket.java:101)
at oracle.net.ns.NIONSDataChannel.readDataFromSocketChannel(NIONSDataChannel.java:80)
at oracle.jdbc.driver.T4CMAREngineNIO.prepareForReading(T4CMAREngineNIO.java:98)
at oracle.jdbc.driver.T4CMAREngineNIO.unmarshalUB1(T4CMAREngineNIO.java:534)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:485)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:252)
at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:499)
at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:1279)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:663)
... 42 common frames omitted
24-07-2021 07:20:20.230 [SimpleAsyncTaskExecutor-1] ERROR o.s.a.r.l.SimpleMessageListenerContainer - Stopping container from aborted consumer
24-07-2021 07:20:20.525 [SimpleAsyncTaskExecutor-1] INFO o.s.a.r.l.SimpleMessageListenerContainer - Waiting for workers to finish.
24-07-2021 07:20:20.584 [SimpleAsyncTaskExecutor-1] INFO o.s.a.r.l.SimpleMessageListenerContainer - Successfully waited for workers to finish.
I would like to avoid my consumer gets down. I have tried many different solutions, for example to restart my application after some events, but they didn't work.
public static void main(String[] args) {
context = SpringApplication.run(CertidaoApplication.class, args);
}
public static void restart() {
ApplicationArguments args = context.getBean(ApplicationArguments.class);
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(CertidaoApplication.class, args.getSourceArgs());
});
thread.setDaemon(false);
thread.start();
}
#EventListener
public void handleEvent(ListenerContainerConsumerTerminatedEvent e) {
logger.info("Restart spring boot. ListenerContainerConsumerTerminatedEvent");
CertidaoApplication.restart();
}
#EventListener
public void handleEvent(ListenerContainerConsumerFailedEvent e) {
logger.info("Restart spring boot. ListenerContainerConsumerFailedEvent");
CertidaoApplication.restart();
}
#EventListener
public void handleEvent(ContextStoppedEvent e) {
logger.info("Restart spring boot. ContextStoppedEvent");
CertidaoApplication.restart();
}
#EventListener
public void handleEvent(ContextClosedEvent e) {
logger.info("Restart spring boot. ContextClosedEvent");
CertidaoApplication.restart();
}
Here my configuration:
#Bean
public RabbitListenerContainerFactory<SimpleMessageListenerContainer> prefetchRabbitListenerContainerFactory(ConnectionFactory rabbitConnectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(rabbitConnectionFactory);
factory.setPrefetchCount(2);
factory.setDefaultRequeueRejected(Boolean.FALSE);
factory.setMessageConverter(jsonMessageConverter());
factory.setMissingQueuesFatal(Boolean.FALSE);
return factory;
}
My consumer:
#RabbitListener(queues = "${queue}", concurrency = "1", containerFactory = "prefetchRabbitListenerContainerFactory")
protected void processMessage(ConsultaRequest message) {
logger.info("Test" + message.getNumber());
Thanks a lot.

#Controller Kafka Listener exception not catched by Exception handler #ControllerAdvice

I have a Kafka Listener marked with #Controller:
#KafkaListener(topics = "${binlookup.kafka.topic.insert}")
public BinInfoJsonDTO listenAndInsert(String binInfoJson, Acknowledgment ack) {
log.debug("Kafka server: {}", bootstrapServers);
log.info("Kafka inserting: {}", binInfoJson);
ObjectMapper mapper = new ObjectMapper();
BinInfoJsonDTO dto;
BinLookupError error;
String responseError;
try {
dto = mapper.readValue(binInfoJson, BinInfoJsonDTO.class); // <--- exception happens here
log.debug("The converted DTO: {}", dto);
ResponseEntity<BinInfoJsonDTO> response = controller.insertBIN(Utilities.jsonDtoToEntity(dto));
log.debug("BIN inserted by Kafka. {}", response);
if (response.getStatusCodeValue() == HttpStatus.OK.value() ||
response.getStatusCodeValue() == HttpStatus.CREATED.value()) {
ack.acknowledge(); // manual acknowledge.
log.debug("Acknowledged.");
} else {
responseError = "Unexpected response status code: " + response.getStatusCodeValue();
log.error(responseError);
error = new BinLookupError(responseError);
error.setErrorType(ErrorTypeEnum.UNEXPECTED_STATUS_CODE);
throw new BinLookupException(error);
}
} catch (JsonProcessingException e) {
log.error("Cannot parse Kafka incoming JSON. ", e);
error = new BinLookupError(e.getMessage());
error.setErrorType(ErrorTypeEnum.KAFKA_JSON_FAILURE);
throw new BinLookupException(error);
} catch (IOException e1) {
log.error("I/O exception in Kafka. ", e1);
error = new BinLookupError(e1.getMessage());
error.setErrorType(ErrorTypeEnum.IO_EXCEPTION);
throw new BinLookupException(error);
}
return dto;
}
And, I have an exception handler marked with #ControllerAdvice:
#Slf4j
#ControllerAdvice
public class BinLookupExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {BinLookupException.class})
protected ResponseEntity<BinLookupError> handleBinLookupException(BinLookupException ex) {
BinLookupError error = ex.getError();
log.error("Exception handler: {}", error.getOriginalMsg());
...
}
Now, when I run the application and enter wrongly formatted JSON into the producer, the exception will occur but not catched by the exception handler. The exception is com.fasterxml.jackson.core.JsonParseException.
[NODE=Shenmue3] [ENV=dev] [SRC=UNDEFINED] [TRACE=] [SPAN=] [2018-09-13T09:38:21.035Z] [INFO] [MSG=[org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] c.p.binlookup.kafka.BinInfoConsumer - Kafka inserting: {{{{{ ]
[NODE=Shenmue3] [ENV=dev] [SRC=UNDEFINED] [TRACE=] [SPAN=] [2018-09-13T09:38:21.119Z] [ERROR] [MSG=[org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] c.p.binlookup.kafka.BinInfoConsumer - Cannot parse Kafka incoming JSON. com.fasterxml.jackson.core.JsonParseException: Unexpected character ('{' (code 123)): was expecting double-quote to start field name
at [Source: (String)"{{{{{"; line: 1, column: 3]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1804)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:663)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:561)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddName(ReaderBasedJsonParser.java:1757)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:682)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
at com.xxx.binlookup.kafka.BinInfoConsumer.listenAndInsert(BinInfoConsumer.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:181)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:114)
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:248)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:80)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:51)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1071)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1051)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:998)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:866)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:724)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:748)
]
[NODE=Shenmue3] [ENV=dev] [SRC=UNDEFINED] [TRACE=] [SPAN=] [2018-09-13T09:38:21.122Z] [ERROR] [MSG=[org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] o.s.k.listener.LoggingErrorHandler - Error while processing: ConsumerRecord(topic = insert, partition = 0, offset = 0, CreateTime = 1536831499778, serialized key size = -1, serialized value size = 5, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {{{{{) org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public com.xxx.binlookup.dto.BinInfoJsonDTO com.xxx.binlookup.kafka.BinInfoConsumer.listenAndInsert(java.lang.String,org.springframework.kafka.support.Acknowledgment)' threw exception; nested exception is BinLookupException [error=BinLookupError(originalMsg=Unexpected character ('{' (code 123)): was expecting double-quote to start field name
at [Source: (String)"{{{{{"; line: 1, column: 3], fields=[], errorType=Cannot parse Kafka incoming JSON)]
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:267)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:80)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:51)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1071)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1051)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:998)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:866)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:724)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.xxx.binlookup.exception.BinLookupException: Original message is: Unexpected character ('{' (code 123)): was expecting double-quote to start field name
at [Source: (String)"{{{{{"; line: 1, column: 3]
at com.xxx.binlookup.kafka.BinInfoConsumer.listenAndInsert(BinInfoConsumer.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:181)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:114)
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:248)
... 10 common frames omitted
]
"Exception handler: {}", as part of the log in the handler, is not there.
What more should I do to make it aware of my exception thrown? Thanks.

How to handle Error/Exception on multiple database connections with spring and hibernate?

I am using spring and hibernate to work on multiple database server save,update simultaneously using 2 datasource configuration.
I am using
org.springframework.jdbc.datasource.DriverManagerDataSource
class for creating datasource.
If both the database server up/running then it's work fine.
If I close one of my database server and trying to catch the exception then it's not coming in catch block
and the stack trace error displaying on my web browser.
Stack Trace:
** BEGIN NESTED EXCEPTION **
java.net.ConnectException
MESSAGE: Connection refused: connect
STACKTRACE:
java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:525)
at java.net.Socket.connect(Socket.java:475)
at java.net.Socket.(Socket.java:372)
at java.net.Socket.(Socket.java:215)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:256)
at com.mysql.jdbc.MysqlIO.(MysqlIO.java:271)
at com.mysql.jdbc.Connection.createNewIO(Connection.java:2771)
at com.mysql.jdbc.Connection.(Connection.java:1555)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:285)
at java.sql.DriverManager.getConnection(DriverManager.java:582)
at java.sql.DriverManager.getConnection(DriverManager.java:154)
at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:173)
at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriver(DriverManagerDataSource.java:164)
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnectionFromDriver(AbstractDriverBasedDataSource.java:149)
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnection(AbstractDriverBasedDataSource.java:119)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:116)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:54)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2186)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2666)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:562)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:550)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:546)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:686)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:1)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:683)
at com.service.RegistrationServiceImpl.add(RegistrationServiceImpl.java:56)
at com.controller.RegistrationController.onSubmit(RegistrationController.java:48)
at org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:272)
at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:268)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:763)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:709)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:613)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:536)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:879)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:619)
** END NESTED EXCEPTION *
How can I handle this exception.
I want to display in my GUI that one of my db server is down If any of my db server is down.
Please help on this.
I think there are two options:
List item You should catch the exception in your service layer (like for example in RegistrationServiceImpl), but you will have to do this in all your service classes.
Create a Servlet filter that catches this specific exception and redirect the user to a page showing something like "Sorry, the database is down".
There is #ExceptionHandler annotation in spring. You can create a handler method in some common class of yours. Whenever an exception is thrown you can conveniently show the message you want depending on the exception thrown something like this
#Component
public class BaseController {
#ExceptionHandler(Throwable.class)
public ModelAndView handleException(Throwable throwable, HttpServletRequest request){
ModelAndView view = null;
if (throwable instanceof ConnectException){
view = //set message and return view;
}else if (throwable instanceof someOtherException) {
//do something else;
//handle as many exceptions as you want
}else {
//do something by default for other unhandled/generic exceptions
}
return view;
}
}
The documentation explains more on the return types supported.
You can also make the handler to handle only the kind of exception you want, something like this:
#ExceptionHandler(ConnectException.class)
public ModelAndView handleException(ConnectException ex, HttpServletRequest request){
// handle it
}
You can check this example which is on similar lines.
I hope this helps. Cheers :)

Resources