I'm trying to set up a project with the stack on title, the JMS that we're using is ActiveMQ. So, here is the configuration that I'm doing:
#SpringBootApplication
public class Application {
private static Logger logger = Logger.getLogger(Application.class);
#Value("${broker.component.name}")
private String brokerComponetName;
#Value("${broker.dead.letter.queue}")
private String brokerDeadLetterQueue;
#Value("${broker.in.queue}")
private String brokerInQueue;
#Value("${broker.out.queue}")
private String brokerOutQueue;
#Value("${broker.url}")
private String brokerUrl;
#Value("${broker.user}")
private String brokerUser;
#Value("${broker.password}")
private String brokerPassword;
public static void main(String[] args) throws Exception {
logger.info("starting loader");
SpringApplication.run(Application.class, args);
}
#Bean
public SpringCamelContext camelContext(ApplicationContext applicationContext) throws Exception {
SpringCamelContext camelContext = new SpringCamelContext(applicationContext);
camelContext.addComponent(brokerComponetName, JmsComponent.jmsComponent(connectionFactory()));
camelContext.addRoutes(new RouteBuilder() {
public void configure() throws ConfigurationException {
errorHandler(deadLetterChannel(brokerDeadLetterQueue)
.onRedelivery(new FailureProcessor())
.useOriginalMessage()
.maximumRedeliveries(5)
.redeliveryDelay(5000)
.retryAttemptedLogLevel(LoggingLevel.INFO));
from(brokerInQueue)
.process(new MessageProcessor())
.to(brokerOutQueue);
}
});
return camelContext;
}
#Bean
public ConnectionFactory connectionFactory() throws ConfigurationException {
System.out.println("BROKER URL: " + brokerUrl);
return new ActiveMQConnectionFactory(brokerUser,
brokerPassword, brokerUrl);
}
I already tried to add #EnableJms to Application with no success. The stack error is the follow:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'jmsListenerContainerFactory' defined in class
path resource
[org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.class]:
Bean instantiation via factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate
[org.springframework.jms.config.DefaultJmsListenerContainerFactory]:
Factory method 'jmsListenerContainerFactory' threw exception; nested
exception is java.lang.NoSuchMethodError:
org.springframework.jms.config.DefaultJmsListenerContainerFactory.setAutoStartup(Z)V
Thank's in advanced and sorry about any mistake in question.
Apparently it's a bug of spring boot 1.3.3:
DefaultJmsListenerContainerFactory does not contains the required method.
Try to upgrade to spring boot 1.4.0 (in spite it is not in RELEASE version at the moment).
That should solve the bug.
I encountered the same Exception and read the answers here. Because I'm using Spring boot 1.5.1-RELEASE, I found the answers not to be applicable and continued my search.
What I found to be the cause on my end was not properly reading the manual:
http://camel.apache.org/activemq.html. The introduction states:
To use this component make sure you have the activemq.jar or activemq-core.jar on your classpath along with any Camel dependencies such as camel-core.jar, camel-spring.jar and camel-jms.jar.
So what solved the problem was 2 extra Maven entries.
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${apache.camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>${apache.camel.version}</version>
</dependency>
I hope it helps someone.
If somebody meet with this issue I found solution.
We need to downgrade version of spring-boot to 1.2.3.RELEASE, because camel-jms:2.16.2 uses spring components in version 4.1.9.
Related
I am migrating an application to Spring boot 3.0, but I have a problem with the injection of a ProducerTemplate in one of my services (annotation #Service se Spring Boot).
I was using the Spring Boot starter from Camel
Current Spring Boot version is : 2.7.5
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-rabbitmq-starter</artifactId>
<version>3.15.0</version>
</dependency>
My ProducerTemplate is injected into the constructor of my service that extends RouteBuilder
#Service
public class MyServiceImpl extends RouteBuilder implements MyService {
private final ProducerTemplate producerTemplate;
#Autowired
public MyServiceImpl(ProducerTemplate producerTemplate) {
this.producerTemplate = producerTemplate;
}
At startup, the application crashes with this message :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.mycompany.ServiceImpl required a bean of type 'org.apache.camel.ProducerTemplate' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.apache.camel.ProducerTemplate' in your configuration.
It's not very clear to me how I should take it.
I guess I have to use the dependency
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>3.15.0</version>
</dependency>
instead of
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.15.0</version>
</dependency>
But I don't really know how I should instantiate the ProducerTemplate and the CamelContext ?
I tried without really believing something like this :
#Configuration
public class CamelConfig {
#Bean
public CamelContext getCamelContext() throws Exception {
CamelContext context = new DefaultCamelContext();
if (context.isStopped()) context.start();
return context;
}
#Bean
public ProducerTemplate getProducerTemplate() throws Exception
{
final ProducerTemplate template = getCamelContext().createProducerTemplate();
return template;
}
}
#Service
public class MyServiceImpl implements MyService {
private final ProducerTemplate producerTemplate;
private CamelContext context;
#Autowired
public MyServiceImpl(ProducerTemplate producerTemplate, CamelContext context) {
this.producerTemplate = producerTemplate;
this.context = context;
try {
this.context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:update-legacy")
.to("bean:updateJdbc");
The app failed with the following error message :
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: bean://updateJdbc due to: No bean could be found in the registry for: updateJdbc
Tries to create an web application based on spring boot with web-socket support
Define public static main class annotated with #SpringBootApplication
#SpringBootApplication
public class Facade {
public static void main(String[] argv) throws IOException {
Map<String,Object> contextProperties = new HashMap<>();
contextProperties.put("server.port",p.getProperty("server.port","8091"));
SpringApplication app = new SpringApplication(Facade.class);
app.setDefaultProperties(contextProperties);
app.run(argv);
}
}
Add configuration class
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketTextHandler(), "/ws").setAllowedOrigins("*");
}
}
Add handler
#Component
public class SocketTextHandler extends TextWebSocketHandler {
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
String payload = message.getPayload();
session.sendMessage(new TextMessage("Hi " + payload + " how may we help you?"));
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
session.sendMessage(new TextMessage("Connected!"));
}
}
There are maven dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-coyote</artifactId>
<version>9.0.31</version>
</dependency>
spring boot version is 2.5.5
When I connect to socket using JavaScript
webSocket = new WebSocket(wsUrl);
I see in app logs
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.socket.server.HandshakeFailureException: Servlet request failed to upgrade to WebSocket: http://127.0.0.1:8091/ws; nested exception is javax.servlet.ServletException: java.lang.reflect.InvocationTargetException] with root cause
java.lang.ClassNotFoundException: org.apache.coyote.http11.upgrade.UpgradeInfo
The tomcat-coyote dependency is in pom.xlm
I used web-sockets in jersey implementation under tomcat9. Now I tries to migrate application to spring-boot, but confused with NoClassDef exception.
Could you please explain or suggest solution for this cause.
I'm very newbie to this messaging queue and just started learning some basic stuffs in this.
So for our spring boot application we followed an architecture like contoller talks to service & service talks to repository so here i have to create one controller that will accept a class DTO as a json and post these information to the message queue specified in the apache camel.
I'm following this link ! for my reference that works well but when i tried to implement it in my project , it saying me an error listed below.
Error
Exception encountered during context initialization - cancelling
refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'trackerQueueController': Unsatisfied
dependency expressed through field 'camelContext'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'org.apache.camel.CamelContext' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I have created an controller,routes & processor as below:
Controller
#RestController
#RequestMapping("/deviceinfo")
public class TrackerQueueController {
#Autowired
CamelContext camelContext;
#Autowired
private
ProducerTemplate producerTemplate;
#PostMapping()
public void startCamel(#RequestBody FieldUpdate fieldUpdate) {
producerTemplate.sendBody("activemq:topic:in", fieldUpdate);
}
}
Routes
#Component
public class TrackerQueueRoutes extends RouteBuilder {
#Override
public void configure() throws Exception {
from("activemq:topic:in")
.process(new TrackerProcessor() {
#Override
public void process(Exchange exchange) throws
Exception {
log.info("I'm in");
FieldUpdate body =
exchange.getIn().getBody(FieldUpdate.class);
log.info("Hello from camel processed message!
Received payload: {}" , body.getSerialNumber());
exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE,
HttpStatus.ACCEPTED);
}
});
}
}
Processor
public class TrackerProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
}
}
Can any one provide me some tutorial link that fulfil my need or any ideas.
As Claus Ibsen suggested in the comments, you have to add these dependencies to your POM file
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>[camel-version]</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
camel-spring-boot-starter automatically starts a CamelContext for you, discovers routes etc
spring-boot-starter-web keeps your application running by listening for web requests. Otherwise it would immediately shut down after startup because there is nothing to execute.
Since your Camel route class is correctly annotated (#Component) and subclassed (extends RouteBuilder), it should be auto-discovered by the Camel SpringBoot starter.
See the Camel-SpringBoot docs for all these topics and more.
I have an spring boot app that is exchanging messages over binary websocket. I.e. NO STOMP, AMQP etc. or any other messaging protocol!!! Now I need to mark one of my classes with the Scope of "websocket". Like that befow:
#Service("session")
#Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Session {
...
}
I have read the documentation here that quote:
" WebSocket-scoped beans can be injected into controllers and any
channel interceptors registered on the "clientInboundChannel". "
I would like to emphasis the word "and" in that sentence.
Well i do have a controller, but i do not have any channelInterceptor. I am injecting this as:
#Controller("entryPoint")
public class EntryPoint {
#Autowired
private ApplicationContext applicationContext;
private ApplicationEventPublisher applicationEventPublisher;
#Autowired
private Session session;
...
#PostConstruct
public void init() {
// Invoked after dependencies injected
logger.info("EntryPoint init method i.e. #PostConstruct invoked");
}
...
}
Now the first thig i found to be interesting is that i need the annotation #EnableWebSocketMessageBroker i.e. it seems that #EnableWebSocket is not enough , but then comes the question why. I should be able to define that scope independinglly whether i am using messaging protocol or not. At least that is what i belive.
anyway without it i am getting the error
java.lang.IllegalStateException: No Scope registered for scope name 'websocket'
I said ok, lets create a dummy config file for the message broker which is bringing additional dependencies such as :
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-net</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.13.Final</version>
</dependency>
as a config like
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/testEndPoint");
}
#Override
public void configureClientInboundChannel(ChannelRegistration inboundChannelRegistration) {
}
#Override
public void configureClientOutboundChannel(ChannelRegistration outboundChannelRegistration) {
}
#Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
return true;
}
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration webSocketTransportRegistration) {
webSocketTransportRegistration.setMessageSizeLimit(45678910);
webSocketTransportRegistration.setSendBufferSizeLimit(9101112);
webSocketTransportRegistration.setSendTimeLimit(123456789);
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
System.out.println("WEB SOCKET ARGUMENT RESOLVER");
}
#Override
public void addReturnValueHandlers(
List<HandlerMethodReturnValueHandler> arg0) {
System.out.println("WEB SOCKET RETURN VALUE HANDLER");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
StompBrokerRelayRegistration stompBrokerRelayRegistration = config.enableStompBrokerRelay(
"/topic/",
"/queue/errors",
"/exchange/amp.direct/testaError/",
"/exchange/amp.direct/testCreateAccount/"
);
stompBrokerRelayRegistration.setRelayHost("127.0.0.6");
stompBrokerRelayRegistration.setRelayPort(61613);
stompBrokerRelayRegistration.setSystemLogin("guest");
stompBrokerRelayRegistration.setSystemPasscode("guest");
stompBrokerRelayRegistration.setAutoStartup(true);
stompBrokerRelayRegistration.setSystemHeartbeatSendInterval(5000);
stompBrokerRelayRegistration.setSystemHeartbeatReceiveInterval(4000);
config.setApplicationDestinationPrefixes("/app");
}
}
which brings the error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.serverSyncSession': Scope 'websocket' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound SimpAttributes found. Your code is probably not processing a client message and executing in message-handling methods invoked by the SimpAnnotationMethodMessageHandler?
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
...
Caused by: java.lang.IllegalStateException: No thread-bound SimpAttributes found. Your code is probably not processing a client message and executing in message-handling methods invoked by the SimpAnnotationMethodMessageHandler?
at org.springframework.messaging.simp.SimpAttributesContextHolder.currentAttributes(SimpAttributesContextHolder.java:82) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.simp.SimpSessionScope.get(SimpSessionScope.java:36) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
... 45 common frames omitted
While the message is clear i.e. my code is indeed not thread bound and is executed in a messageHandelr just not in the SimpAnnotationMethodMessageHandler, but in a BinaryMessageHandler class that extends BinaryWebSocketHandler. Why should i not be able to place a scope on a bean it is clearlly used by the websockets. Why do we need all annotation #EnableWebSocketMessageBroker at all and all following dependencies?
It is not really clear to me what else do i need to do in order to get my bean with the right scope. Somehow i have the feeling that this will get me again to some messaging dependency that i am really trying to avoid.
My question is does anyone have some hint for me what do I need to do in BinaryMessageHandler in order to tell spring to thread that session bean with the scope "wesocket". Is there a way to achive that without the annotation #EnableWebSocketMessageBroker?
any feedback is appreciated.
Following the Spring Boot reference guides, I've set up a Hello World example. My workplace uses Ant, so I implemented build.xml based on https://www.mkyong.com/ant/ant-spring-mvc-and-war-file-example/ The resultant WAR file works correctly when deployed onto the WebLogic 12c server. Note: As per this guide, .properties files are copied to ${web.classes.dir}.
Now, I want to query the server's Oracle SQL database via JNDI. Following various parts of the Spring Boot references & guides, this is my modified code at present:
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements WebApplicationInitializer {
#Autowired
private static JdbcTemplate jdbcTemplate;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
public static void update(String query) {
jdbcTemplate.update(query);
}
}
#RestController
#RequestMapping("/query")
public class CrudController {
#RequestMapping(value="/update", method=RequestMethod.GET)
public String update(#PathVariable String tableName, /* other params */) {
// Generates query from params
Application.update(query);
return query;
}
}
I've also added an application.properties file which contains a single line in accordance with the Spring reference guide:
spring.datasource.jndi-name=jndiName
At this point, the WAR can still deploy onto the server but when I go to http://ipaddr:port/appName/query/update?params I get a NullPointerException. I've separately verified that update() correctly generates a SQL query with valid syntax, so I suspect I've gotten the database configuration wrong.
What's the correct way to connect to the JNDI database and execute a query?
Edit:
After updating my code according to Strelok's answer, I tried to run the updated WAR file on the WebLogic server, which subsequently throws the following exception:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'crudController': Injection of autowired dependencies failed; ...
...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate main.java.controllers.CrudController.jdbcTemplate; ...
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.jdbc.core.JdbcTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I tried modifying the #Autowired annotation to #Autowired(required=true) but that didn't change anything. How can I resolve this?
Your JdbcTemplate is static and is located in your application class, whereas it should belong in your controller. That's where you should use it.
Spring cannot inject static fields directly, so make sure anything injected by Spring is never static. Your code should look something like this:
Application.java
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements WebApplicationInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
CrudController.java
#RestController
#RequestMapping("/query")
public class CrudController {
#Autowired
private JdbcTemplate jdbcTemplate;
#RequestMapping(value="/update", method=RequestMethod.GET)
public String update(#PathVariable String tableName, /* other params */) {
jdbcTemplate.update(query);
return query;
}
}