I am trying to use Spring Integration to read files via SFTP and to use multiple servers to only read each file once. I have configured the SFTP reader within Spring Boot and it works with the in-memory metadata store. When I configure the JdbcMetadataStore using Postgres, Spring boot will no longer start and there is no error message other than Tomcat is shutting down. I am using Spring Boot with JPA and Spring WS
2018-10-22 11:16:06.098 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure
2018-10-22 11:16:06.106 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'metadataStore' has been autodetected for JMX exposure
2018-10-22 11:16:06.114 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'metadataStore': registering with JMX server as MBean [org.springframework.integration.jdbc.metadata:name=metadataStore,type=JdbcMetadataStore]
2018-10-22 11:16:06.125 INFO 6775 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
I am using annotation based configuration
#Bean
public ConcurrentMetadataStore metadataStore(final DataSource dataSource) {
return new JdbcMetadataStore(dataSource);
}
#Bean
public SessionFactory<ChannelSftp.LsEntry> sftpSessionFactory() {
final DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost(this.host);
factory.setPort(this.port);
factory.setUser(this.username);
factory.setPassword(this.password);
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<>(factory);
}
#Bean
#InboundChannelAdapter(channel = "stream", poller = #Poller(fixedDelay = "5000"))
public MessageSource<InputStream> sftpMessageSource(ConcurrentMetadataStore metadataStore) {
final SftpStreamingMessageSource messageSource = new SftpStreamingMessageSource(template(), null);
messageSource.setRemoteDirectory("/");
messageSource.setFilter(new SftpPersistentAcceptOnceFileListFilter(metadataStore,
"INT_"));
//messageSource.setFilter(new SftpPersistentAcceptOnceFileListFilter(new SimpleMetadataStore(),
// "streaming"));
return messageSource;
}
#Bean
#Transformer(inputChannel = "stream", outputChannel = "data")
public org.springframework.integration.transformer.Transformer transformer() {
return new StreamTransformer();
}
#Bean
public SftpRemoteFileTemplate template() {
return new SftpRemoteFileTemplate(sftpSessionFactory());
}
I noticed it failed when trying to load the metadatastore to JMX. I then disabled JMX in Spring Boot and it fixed the issue. Not sure why it was failing to add the bean to JMX but disabling JMX in the spring boot property(yml) file fixed the issue.
spring:
jmx:
enabled: false
Related
I'm trying to configure my spring security application.
I want to create my own UserDetailsService.
For that i do something like this:
public class ApplicationUserService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return this.someUser();
}
}
I got 2 ways to add this UserService to Spring Security
Add it to configuration class. Something like this:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
protected UserDetailsService userDetailsService() {
return applicationUserService;
}
}
Or add annotaion #Component, or #Service on my class.
Everything is working fine when i chose only 1 way, but i got an question: why when i trying to use both variants (add #Service and add #Bean to config) nothing is working?
I got no exceptions, error or something like this in console:
2021-09-11 17:26:16.755 INFO 15819 --- [ main] com.example.test.TestApplication : Starting TestApplication using Java 16.0.2 on aleksander-MS-7A71 with PID 15819 (/home/aleksander/programming/java/4fun/test/target/classes started by aleksander in /home/aleksander/programming/java/4fun/test)
2021-09-11 17:26:16.756 INFO 15819 --- [ main] com.example.test.TestApplication : No active profile set, falling back to default profiles: default
2021-09-11 17:26:17.402 INFO 15819 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-09-11 17:26:17.409 INFO 15819 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-09-11 17:26:17.409 INFO 15819 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.52]
2021-09-11 17:26:17.442 INFO 15819 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-09-11 17:26:17.442 INFO 15819 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 630 ms
2021-09-11 17:26:17.555 INFO 15819 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#6981f8f3, org.springframework.security.web.context.SecurityContextPersistenceFilter#38bb9d7a, org.springframework.security.web.header.HeaderWriterFilter#62db3891, org.springframework.security.web.authentication.logout.LogoutFilter#48528634, org.springframework.security.web.authentication.www.BasicAuthenticationFilter#80bfdc6, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#78d6447a, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#5e65afb6, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#623dcf2a, org.springframework.security.web.session.SessionManagementFilter#2819c460, org.springframework.security.web.access.ExceptionTranslationFilter#6f49d153, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#60bbacfc]
2021-09-11 17:26:17.676 INFO 15819 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-09-11 17:26:17.682 INFO 15819 --- [ main] com.example.test.TestApplication : Started TestApplication in 1.215 seconds (JVM running for 1.794)
The way you've described the question, the application will definitely throw an exception unless you've defined the bean preference.
First case:
Basically, UserDetailsService is an interface and you've provided the implementation of it by declaring the bean as
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
protected UserDetailsService userDetailsService() {
return new ApplicationUserService();
}
}
Second case: You want to check the behaviour by declaring another bean using #Service or #Component annotation as following
#Service
public class ApplicationUserService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new UserDetails();
}
}
If you try to use the above cases together, it won't work. The case is very simple you are providing two beans of type UserDetailsService to the spring container and hence it won't be able to identify which one it should use.
If you want to check the behaviour with both the cases you've to set the priority for beans, so in that case you can mark one of the bean with #Primary annotation.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Primary
#Bean
#Override
protected UserDetailsService userDetailsService() {
return new ApplicationUserService();
}
}
I am trying to create a simple Resttemplate which will fetch the schema from Schema Registary and if response is 200 it will fetch the Schema ID and send it along with message in Avro format to kafka. Here is my code:
.
#SpringBootApplication
public class DemoApplication implements CommandLineRunner{
String kafkarwsrproxyURL = String.format("%s/topics/%s", "https://kafka-rest-proxy-**********", "test-topic");
String schemaurl = String.format("%s/subjects/%s/versions/latest", "https://schema-registry-*********", "test-topic");
#Autowired
private RestTemplate restTemplate;
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
ObjectMapper obj = new ObjectMapper();
JSONObject event = new JSONObject();
JSONObject record = new JSONObject();
JSONObject eventenvolpe = new JSONObject();
JSONObject jsondata = new JSONObject();
JSONArray jsonarray =new JSONArray();
JSONObject recordvalue =new JSONObject();
// connecting to schema registary and getting back schema
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/vnd.schemaregistry.v1+json"));
headers.setBasicAuth("username", "password");
HttpEntity<String> SchemaEntity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> result = restTemplate.exchange(schemaurl, HttpMethod.GET, SchemaEntity, String.class);
if(result.getStatusCodeValue()==200) {
JsonNode rootNode = obj.readTree(result.getBody());
JsonNode schema_id = rootNode.path("id");//fetchinf schema id form schema
event = new JSONObject();
record = new JSONObject();
eventenvolpe = new JSONObject();
jsondata = new JSONObject();
jsondata.put("data", obj.writeValueAsString(new Data("test1",1)));
eventenvolpe.put("event_envelope", jsondata);
recordvalue.put("value", eventenvolpe);
jsonarray.put(recordvalue);
event.put("value_schema_id", schema_id);
event.put("records", recordvalue);//setting up event object to send to kafka
System.out.println(event);
//Sending message to kafka
HttpHeaders messageheaders = new HttpHeaders();
messageheaders.setContentType(MediaType.valueOf("application/vnd.kafka.avro.v2+json"));
messageheaders.setBasicAuth("username", "password");
HttpEntity<JSONObject> message = new HttpEntity<JSONObject>(event,messageheaders );
ResponseEntity<String> result1 = restTemplate.exchange(kafkarwsrproxyURL, HttpMethod.POST, message, String.class);
if(result1.getStatusCodeValue()==200) {
System.out.println("Message is pushed to Kafka");
}
}
}
}
I am successfully able to fetch schema form registry but while sending back to kafka getting error.
2020-06-30 20:02:56.078 INFO 7972 --- [ main] com.example.demo.DemoApplication :
No active profile set, falling back to default profiles: default
2020-06-30 20:02:59.235 INFO 7972 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer :
Tomcat initialized with port(s): 8089 (http)
2020-06-30 20:02:59.263 INFO 7972 --- [ main] o.apache.catalina.core.StandardService :
Starting service [Tomcat]
2020-06-30 20:02:59.264 INFO 7972 --- [ main] org.apache.catalina.core.StandardEngine :
Starting Servlet engine: [Apache Tomcat/9.0.36]
2020-06-30 20:02:59.434 INFO 7972 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] :
Initializing Spring embedded WebApplicationContext
2020-06-30 20:02:59.434 INFO 7972 --- [ main] w.s.c.ServletWebServerApplicationContext :
Root WebApplicationContext: initialization completed in 3269 ms
2020-06-30 20:02:59.847 INFO 7972 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor :
Initializing ExecutorService 'applicationTaskExecutor'
2020-06-30 20:03:00.238 INFO 7972 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer :
Tomcat started on port(s): 8089 (http) with context path ''
2020-06-30 20:03:00.251 INFO 7972 --- [ main] com.example.demo.DemoApplication :
Started DemoApplication in 4.945 seconds (JVM running for 5.758)
{"records":{"value":{"event_envelope":{"data":"
{\"test\":\"test1\",\"testEventId\":1}"}}},"value_schema_id":"5"}
2020-06-30 20:03:02.276 INFO 7972 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with
'debug' enabled.
2020-06-30 20:03:02.282 ERROR 7972 --- [ main] o.s.boot.SpringApplication :
Application run failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) [spring-boot-
2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:779) [spring-boot-
2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) [spring-boot-
2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) [spring-boot-
2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-
2.3.1.RELEASE.jar:2.3.1.RELEASE]
at com.example.demo.DemoApplication.main(DemoApplication.java:44) [classes/:na]
Caused by: org.springframework.web.client.RestClientException: No HttpMessageConverter for
org.json.JSONObject and content type "application/vnd.kafka.avro.v2+json"
at `org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:961) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:737) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:674) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:583) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at com.example.demo.DemoApplication.run(DemoApplication.java:91) [classes/:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) [spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE] ... 5 common frames omitted
2020-06-30 20:03:02.878 INFO 7972 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down
ExecutorService 'applicationTaskExecutor'`
It seems that the trouble is cause by the fact that your client doesn't know how to read this "exotic" data type: "application/vnd.kafka.avro.v2+json"
Here's a possible solution in this post:
no suitable HttpMessageConverter found for response type
To sum up - you either have to register the corresponding HttpMessageConverter for the MIME type "application/vnd.kafka.avro.v2+json" or change (if you have access) the returning MIME type from server. You can also "hack" a quick proxy script, so that it goes to server and fetches data and then sends it to you client with changed MIME type.
Dependencies:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
And the code snippet:
#Bean
public RestTemplate restTemplate() {
final RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
List<MediaType> types = Arrays.asList(
new MediaType("application", "*+json", DEFAULT_CHARSET)
);
converter.setSupportedMediaTypes(types);
messageConverters.add(converter);
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
The CamelContextStartedEvent is called twice for the same camel context (camel-1). The issue might be the way I register the EventNotifier. You can reproduce the issue with Spring Initializr with Spring Boot 1.5.14, Spring Boot Camel Starter 2.21.1 and Spring Boot Web Starter.
See the logs:
2018-07-06 11:04:41.104 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) is starting
2018-07-06 11:04:41.106 INFO 19092 --- [ main] o.a.c.m.ManagedManagementStrategy : JMX is enabled
2018-07-06 11:04:41.191 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.boot.RoutesCollector : Starting CamelMainRunController to ensure the main thread keeps running
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Total 0 routes, of which 0 are started
2018-07-06 11:04:41.194 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) started in 0.090 seconds
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.216 INFO 19092 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 11223 (http)
2018-07-06 11:04:41.221 INFO 19092 --- [ main] com.example.bug.BugApplication : Started BugApplication in 4.684 seconds (JVM running for 6.773)
The service that initializes the EventNotifier:
#Service
public class SchedulerService {
private final CamelContext camelContext;
private final StartupEventNotifier startupEventNotifier;
public SchedulerService(CamelContext camelContext, StartupEventNotifier startupEventNotifier) {
this.camelContext = camelContext;
this.startupEventNotifier = startupEventNotifier;
}
#PostConstruct
public void init() {
camelContext.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
}
The EventNotifier:
#Component
public class StartupEventNotifier extends EventNotifierSupport {
private static final Logger logger = LoggerFactory.getLogger(StartupEventNotifier.class);
#Override
public void notify(EventObject event) throws Exception {
if (event instanceof CamelContextStartedEvent) {
logger.info("CamelContextStartedEvent for {}", event.getSource());
}
}
#Override
public boolean isEnabled(EventObject event) {
if (event instanceof CamelContextStartedEvent) {
return true;
}
return false;
}
}
application.yml:
camel:
springboot:
main-run-controller: true
server:
port: 11223
It is called twice, because it is registered twice. Once by you and once by Apache Camel. EventNotifier is registered automatically, if is found in Registry. Since your StartupEventNotifier is annotated as Component, it is part of Registry and Apache Camel registered it during CamelContext startup (You can see it in CamelAutoConfiguration line 424).
You have four options:
Remove your custom registration from SchedulerService.
Remove #Component annotation from StartupEventNotifier and register it with with camelContext.getManagementStrategy().addEventNotifier(new StartupEventNotifier())
Add duplicity check to your SchedulerService. Something like:
if (!context.getManagementStrategy().getEventNotifiers().contains(startupEventNotifier)){
context.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
Register EventNotifier in #PostConstruct of RouteBuilder. It will be registered before automatic discovery is started and then it will be skipped in CamelAutoConfiguration (See line 422)
I have to convert a project using Spring integration in xmls to Java config, and tried below, but I am getting exceptions.
What I am trying to achieve is, create a message listener which listens messages on a queue destination, puts it on to a channel, which is read and processed by a xsl transformer that puts in the next channel, which is again read and processed by JaxbUnmarshaller to create to Java object and put it the third channel, which will be consumed by a Java Consumer. In case of error, the message is put on a error channel which is again the same Java Consumer that handles it.
Below is the Spring config
<int:channel id="channel_1"/>
<int:channel id="channel_2"/>
<int:channel id="channel_3"/>
<int:channel id="channel_error"/>
<int-jms:message-driven-channel-adapter connection-factory="factory" destination-name="destName"
pub-sub-domain="false" channel="channel_1" error-channel="channel_error"/>
<int-xml:xslt-transformer input-channel="channel_1" output-channel="channel_2" xsl-resource="classpath:sample.xsl"/>
<int-xml:unmarshalling-transformer input-channel="channel_2" output-channel="channel_3" unmarshaller="unmarshaller"/>
<oxm:jaxb2-marshaller id="unmarshaller">
<oxm:class-to-be-bound name="sample.example.MyData"/>
</oxm:jaxb2-marshaller>
<int:outbound-channel-adapter channel="channel_3" ref="consumer" method="handleMessage"/>
<bean id="consumer" class="sample.example.MyConsumer"></bean>
<int:outbound-channel-adapter channel="channel_error" ref="consumer" method="handleError"/>
Below is the Java Config I have for this
#Bean
public MessageChannel channel_1() {
return new DirectChannel();
}
#Bean
public MessageChannel channel_2() {
return new DirectChannel();
}
#Bean
public MessageChannel channel_3() {
return new DirectChannel();
}
#Bean
public MessageChannel channel_error() {
return new DirectChannel();
}
#Bean
#Autowired
public DefaultMessageListenerContainer container(String destinationQueueName) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(factory());
container.setDestinationName(destinationQueueName);
container.setPubSubDomain(false);
container.setMessageListener(messageListener());
return container;
}
#Bean
public ChannelPublishingJmsMessageListener messageListener(){
ChannelPublishingJmsMessageListener adapter = new ChannelPublishingJmsMessageListener();
adapter.setRequestChannel(channel_1());
adapter.setErrorChannel(channel_error());
return adapter;
}
#Bean
#Transformer(inputChannel = "channel_1", outputChannel = "channel_2")
public XsltPayloadTransformer transformer() {
return new XsltPayloadTransformer(new ClassPathResource("sample.xsl"));
}
#Bean
#Transformer(inputChannel = "channel_2", outputChannel = "channel_3")
public UnmarshallingTransformer unmarshallingTransformer() {
return new UnmarshallingTransformer(unmarshaller());
}
#Bean
public Jaxb2Marshaller unmarshaller() {
Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
unmarshaller.setClassesToBeBound(MyData.class);
return unmarshaller;
}
#Bean
#ServiceActivator(inputChannel = "channel_3")
public MessageHandler messageHandler() {
return new MethodInvokingMessageHandler(consumer(), "handleMessage");
}
#Bean
#ServiceActivator(inputChannel = "channel_error")
public MessageHandler errorHandler() {
return new MethodInvokingMessageHandler(consumer(), "handleError");
}
I get the below exception, when I refer for this exception, it says that service activator is not configured properly. I am not sure what I am missing, can someone please help.
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'org.springframework.web.context.WebApplicationContext:/v1.channel_error'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:81)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:287)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:95)
at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:281)
at org.springframework.integration.jms.ChannelPublishingJmsMessageListener$GatewayDelegate.send(ChannelPublishingJmsMessageListener.java:479)
at org.springframework.integration.jms.ChannelPublishingJmsMessageListener.onMessage(ChannelPublishingJmsMessageListener.java:322)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:674)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:634)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:605)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:308)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:246)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1144)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1136)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1033)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:107)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
... 16 more
Logs on start up :
2016-03-30 13:06:46,423 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletConfigInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,403 DEBUG com.amazonaws.jmx.MBeans.registerMBean[58] - Failed to register mbean com.amazonaws.management:type=AwsSdkMetrics
javax.management.InstanceAlreadyExistsException: com.amazonaws.management:type=AwsSdkMetrics
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
at com.amazonaws.jmx.MBeans.registerMBean(MBeans.java:52)
at com.amazonaws.jmx.SdkMBeanRegistrySupport.registerMetricAdminMBean(SdkMBeanRegistrySupport.java:27)
at com.amazonaws.metrics.AwsSdkMetrics.registerMetricAdminMBean(AwsSdkMetrics.java:355)
at com.amazonaws.metrics.AwsSdkMetrics.<clinit>(AwsSdkMetrics.java:316)
at com.amazonaws.AmazonWebServiceClient.requestMetricCollector(AmazonWebServiceClient.java:629)
at com.amazonaws.AmazonWebServiceClient.isRMCEnabledAtClientOrSdkLevel(AmazonWebServiceClient.java:570)
at com.amazonaws.AmazonWebServiceClient.isRequestMetricsEnabled(AmazonWebServiceClient.java:562)
at com.amazonaws.AmazonWebServiceClient.createExecutionContext(AmazonWebServiceClient.java:523)
at com.amazonaws.services.sqs.AmazonSQSClient.getQueueUrl(AmazonSQSClient.java:525)
at com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper.getQueueUrl(AmazonSQSMessagingClientWrapper.java:260)
at com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper.getQueueUrl(AmazonSQSMessagingClientWrapper.java:230)
at com.amazon.sqs.javamessaging.SQSSession.createQueue(SQSSession.java:576)
at org.springframework.jms.support.destination.DynamicDestinationResolver.resolveQueue(DynamicDestinationResolver.java:84)
at org.springframework.jms.support.destination.DynamicDestinationResolver.resolveDestinationName(DynamicDestinationResolver.java:58)
at org.springframework.jms.support.destination.JmsDestinationAccessor.resolveDestinationName(JmsDestinationAccessor.java:98)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.createListenerConsumer(AbstractPollingMessageListenerContainer.java:204)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.initResourcesIfNecessary(DefaultMessageListenerContainer.java:1167)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1143)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1136)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1033)
at java.lang.Thread.run(Thread.java:745)
2016-03-30 13:06:46,423 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletConfigInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,427 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletContextInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,427 DEBUG com.amazonaws.metrics.AwsSdkMetrics.registerMetricAdminMBean[369] - Admin mbean registered under com.amazonaws.management:type=AwsSdkMetrics/4
2016-03-30 13:06:46,427 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletContextInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [jndiProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [jndiProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemEnvironment] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemEnvironment] PropertySource with lowest search precedence
2016-03-30 13:06:46,429 DEBUG org.springframework.web.context.support.StandardServletEnvironment.<init>[126] - Initialized StandardServletEnvironment with PropertySources [servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment]
2016-03-30 13:06:46,429 DEBUG org.springframework.web.context.support.StandardServletEnvironment.<init>[126] - Initialized StandardServletEnvironment with PropertySources [servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment]
2016-03-30 13:06:46,432 DEBUG com.choiceedge.library.common.service.v1.endpoint.AbstractEndpoint$RequestContextAwareFilter.init[177] - Initializing filter 'RequestContextAwareFilter'
2016-03-30 13:06:46,436 DEBUG com.choiceedge.library.common.service.v1.endpoint.AbstractEndpoint$RequestContextAwareFilter.init[202] - Filter 'RequestContextAwareFilter' configured successfully
2016-03-30 13:06:46,437 DEBUG com.amazonaws.auth.AWSCredentialsProviderChain.getCredentials[105] - Loading credentials from EnvironmentVariableCredentialsProvider
2016-03-30 13:06:46,438 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBean[248] - Returning cached instance of singleton bean 'cxf'
2016-03-30 13:06:46,438 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBean[248] - Returning cached instance of singleton bean 'cxf'
This is how I register my AppConfig in my WebApplicationInitializer
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
rootContext = new AnnotationConfigWebApplicationContext();
rootContext.getEnvironment().setActiveProfiles(System.getenv(ENVIRONMENT));
LOGGER.info(System.getenv(ENVIRONMENT));
System.out.println("Starting application in " + System.getenv(ENVIRONMENT));
rootContext.register(AppConfig.class);
rootContext.setDisplayName(DISPLAY_NAME);
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(rootContext));
.....
And in my AppConfig I have
#Configuration
#ImportResource("...") - this is for another custom library
#ComponentScan(...)
#EnableIntegration
public class AppConfig {
Haven't you missed #EnableIntegration on your #Configuration?
Starting with version 4.0, the #EnableIntegration annotation has been introduced, to allow the registration of Spring Integration infrastructure beans (see JavaDocs). This annotation is required when only Java & Annotation configuration is used, e.g. with Spring Boot and/or Spring Integration Messaging Annotation support and Spring Integration Java DSL with no XML integration configuration.
http://docs.spring.io/spring-integration/docs/4.3.0.BUILD-SNAPSHOT/reference/html/overview.html#configuration-enable-integration
SOLVED : The changes that resolved the issue, was to autowire the channels to the listener. And Make the PropertyPlaceHolderConfigurer bean as static
#Bean
#Autowired
public ChannelPublishingJmsMessageListener messageListener(MessageChannel channel_1, MessageChannel channel_error){
ChannelPublishingJmsMessageListener adapter = new ChannelPublishingJmsMessageListener();
adapter.setRequestChannel(channel_1);
adapter.setErrorChannel(channel_error);
return adapter;
}
I have a basic API setup with Spring MVC Rest as following.
public abstract class AbstractApi implements InitializingBean {
#Autowired
protected ValidatorFactory validatorFactory;
/* ... */
#Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(validatorFactory);
}
}
#Controller
#RequestMapping("books")
public class BookApi extends AbstractApi {
private final BookRepository bookRepository;
#Autowired
public BookApi(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Book> getBooks() {
return new ResponseEntity<>(bookRepository.findAll(), HttpStatus.OK);
}
}
The server returns 404 - Not Found if I send GET /books request with above configuration.
But, if I make AbstractApi un-implement InitializingBean, it works fine. Also, annotating #PostConstruct to afterPropertiesSet() instead of implementing InitializingBean works.
Why is Spring #Controller API not working when implementing InitializingBean?
Your code looks correct. I tested in on my own and everything works as expected. What I'm suggesting is to remove #Autowired ValidatorFactory in AbstractApi class just for testing purpose. Implementing InitializingBean is not related to the request mapping handler mapping. My working code is:
public abstract class AbstractApi implements InitializingBean {
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("after properties set");
}
}
and my controller
#Controller
#RequestMapping("books")
public class BooksController extends AbstractApi {
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> getBooks() {
return new ResponseEntity<>("", HttpStatus.OK);
}
}
and starting log from tomcat:
2016-01-28 16:48:03.141 INFO 2238 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2016-01-28 16:48:03.317 INFO 2238 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2016-01-28 16:48:03.329 INFO 2238 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.0.23
2016-01-28 16:48:03.405 INFO 2238 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2016-01-28 16:48:03.405 INFO 2238 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1815 ms
2016-01-28 16:48:03.512 INFO 2238 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2016-01-28 16:48:03.515 INFO 2238 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
after properties set
Your current #RequestMapping("books") path is incorrectly specified. When running locally on port 8080 looks like http://localhost:8080books
and should be #RequestMapping("/books") - http://localhost:8080/books
give that a try.