Standalone Consumer (SpringJMS) created another Queue on ActiveMQ - java

I created a simple standalone consumer, trying to consume 4 messages sitting on the ActiveMQ. But when I started the application, it created another Queue with the same name as shown in the image below:
My Project Structure looks like this:
And code inside classes looks like the following:
class FebMessageConsumer
package com.consumer.messages.febMessageConsumer;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
#Component
public class FebMessageConsumer {
#JmsListener(destination = "CDD Feb 21 Queue")
///#JmsListener
public void processFebMessage(String message) {
System.out.println("Message Retrieved is:" +message);
}
}
class FebMessageConsumerApplication
package com.consumer.messages.febMessageConsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jms.annotation.EnableJms;
#SpringBootApplication
#EnableJms
public class FebMessageConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FebMessageConsumerApplication.class, args);
}
}
1) What's wrong in the above code?
2) Once I get above thing working,I plan on deploying it as a WAR to Apache Tomcat 8.5. Is it like when I deploy the application or start the application as Java Application, it's going to consume all the messages one by one? OR when I start the application, only one message will be consumed at a time and then I'll have to stop the application and then start again to consume next message?
Here's a Google Drive Link to the zipped project in case needed for reference.

The existing queue name includes quotes.
Use #JmsListener(destination = "\"CDD Feb 21 Queue\"").
It will continually receive messages one by one.

Related

Test Spring boot Application startup using Junit

I have some business logic that runs when Spring boot application starts (i.e in main method)
#SpringBootApplication
#EnableGatewayService
#EnableAsync
#Slf4j
public class AuthOpsApplication {
public static void main(String[] args) throws IOException {
application.addListeners(new WEPFallbackListener());
application.addListeners(new SaeListener());
application.run(args);
// some business logic
log.info("logs some info of the business logic");
}
}
I want to write a test case to check if the log.info is getting printed and its value is as expected. I do not want to test the business logic as a standalone code, I would like to run the main function and somehow read the log that it puts out, Is this possible?
What I tried:
import org.springframework.test.context.junit4.SpringRunner;
import uk.org.lidalia.slf4jtest.TestLogger;
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
import org.springframework.boot.test.autoconfigure.actuate.metrics.AutoConfigureMetrics;
import org.springframework.test.context.ActiveProfiles;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = AuthOpsApplication.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY)
#ActiveProfiles("test")
#AutoConfigureMetrics
public class LogTest {
TestLogger logger = TestLoggerFactory.getTestLogger(AuthOpsApplication.class);
#Test
public void testAnyLog() throws IOException {
System.out.println(logger.getLoggingEvents());
}
#After
public void clearLoggers() {
TestLoggerFactory.clear();
}
}
This runs successfully and creates all the Beans but does not actually call the main() method of my AuthOpsApplication class.
( I can say this because the System.out.println() that I did gives all the other logs except the ones in main() method).
Thanks in advance for the help.
Your test code can do this:
Apply https://stackoverflow.com/a/1119559/6944068 to capture stdout.
Run what's inside AuthOpsApplication.main().
Collect captured stdout until you see the expected message.
Call application.close() to shut down.
Some general advice:
It's pretty common to do startup logging right after calling application.run, but strictly speaking that's a race condition and you don't known at what point the business info you're logging will be available. You'll be more robust if you put the logging into the beans that have that information.
The code as given in the question does not initialize application.
You don't want to copy the code for step 2 from main(), you'll want to put that into a function you can call from your test code. That function should also return application so the test code can close() it in step 4.
If you have more tests that require the full application, you'll want to organize them that you have application startup and shutdown only once. (I don't have recipes for that, how to do that would be food for another SO question.)

How do I Connect Spring Cloud Stream Functional Beans to a Kafka Binder?

I'm using the Spring Cloud Streams Documentation to try and work out how to connect my micro service to Kafka via the binder already downloaded in Gradle. I've tried creating a simple #Bean Function<String, String>() method within my Spring Boot Application class and have verified that it is able to talk to Kafka by using the command line to interact with the uppercase-in-0 and uppercase-out-0 topics, as is described in the beginning of the documentation confirming that the application is able to communicate with Kafka. At this point I attempted to create the following class with the expectation that it would load via auto discovery:
package com.yuknis.loggingconsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class LoggingConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(LoggingConsumerApplication.class, args);
}
}
package com.yuknis.loggingconsumer.functions;
import java.util.function.Function;
public class CharCounter implements Function<String, Integer> {
/**
* Applies this function to the given argument.
*
* #param s the function argument
* #return the function result
*/
#Override
public Integer apply(String s) {
return s.length();
}
}
With the application.properties files as such:
spring.cloud.function.scan.packages:com.yuknis.loggingconsumer.functions
I'm not 100% sure what should happen now, but I'm assuming that it should see the class and automatically create a charcounter-out-0 and charcounter-in-0 topic which I could consume and publish to, with the data in those topics going through that function. That's isn't what's happening. What might I be missing? Is this class supposed to create the topic the same way that the #Bean would?
Even though each of the functions are loaded with spring.cloud.function.scan.packages set to a package and spring.cloud.function.scan.enabled set to true, it still doesn't create the topics. You'll still need to set spring.cloud.function.scan.definition to the Function, Consumer, or Supplier you'd like to have communicate with Kafka like so:
spring.cloud.function:
scan:
enabled: true
packages: com.yuknis.loggingconsumer.functions
definition: charCounter;lowercase;uppercase
After that, it will create the charCounter-in-0 and charCounter-out-0 topics, which can be mapped if necessary with the spring.cloud.function.charCounter-in-0 or spring.cloud.function.charCounter-out-0 expression property.

Schedule task dynamically, in Springboot application

In a spring-boot application, I need to create a scheduled task that executes an exposed method (in the application domain).
Through the graphical interface, the user can configure the execution time and periodicity.
I already have this part.
The problem is to know if using quartz or similar library is possible to program the task and to be reprogrammed if the user modifies the configuration.
Please can you give me documentation about it so I can configure it this way.
you can use #Scheduled annotation of spring. You can annotate any method on the spring component by specifying the delaystring ,i.e. the interval it should be running after. This can be configured in the properties file. To specify interval you can use "fixedRate" or "fixedDelay".
fixedRate- Executes the new run even if previous run of the job is still in progress.
fixedDelay-controls the next execution time when the last execution finishes.
This had helped me in the past.
https://spring.io/guides/gs/scheduling-tasks
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html
1.You can create the JOB class containing the task to be done:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class MyScheduledTask {
private static final SimpleDateFormat currentTime =
new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
#Scheduled(fixedRate = 2000) //interval in millisconds
public void doSomeTask() {
System.out.println("doSome task exceuted at "
+ currentTime.format(new Date()));
}
}
2.Main Spring boot class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
#SpringBootApplication
#EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(new Object[] { Application.class }, args);
}
}
Hope this helps you a bit.

Camel read properties file

How do I configure the use of a properties file using Java DSL and the Main object?
According to this page I should be able to call something like:
main.setPropertyPlaceholderLocations("example.properties");
However that simply doesn't work. It seems that option wasn't added until Camel 2.18 and I'm running 2.17.1.
What was the original way to set a properties file to use when letting the application run in a standalone form?
Some backstory:
I'm trying to convert from Spring to Java DSL. During that conversion I was attempting to have my Camel application run on its own. I know that is achieved using main.run();.
I had things "functioning" when using the CamelContext, but that cannot run on its own. So I know using the following will work in that case:
PropertiesComponent pc = new PropertiesComponent();
pc.setLocation("classpath:/myProperties.properties");
context.addComponent("properties", pc);
Is there some way I can tell the main to use that setup? Or is there something else needed?
You can use the following snippet:
PropertiesComponent pc = new PropertiesComponent();
pc.setLocation("classpath:/myProperties.properties");
main.getCamelContexts().get(0).addComponent("properties", pc);
Also, if you are using camel-spring, you could use org.apache.camel.spring.Main class, it should use the property placeholder from your application context.
Since you are mentioning you are in the process to move from Spring XML to Java Config here's a minimum application that is using properties and injecting it into a Camel route (it's really properties management in Spring injected into our Camel route bean):
my.properties:
something=hey!
Main class:
package camelspringjavaconfig;
import org.apache.camel.spring.javaconfig.CamelConfiguration;
import org.apache.camel.spring.javaconfig.Main;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#ComponentScan("camelspringjavaconfig")
#PropertySource("classpath:my.properties")
public class MyApplication extends CamelConfiguration {
public static void main(String... args) throws Exception {
Main main = new Main();
main.setConfigClass(MyApplication.class); // <-- passing to the Camel Main the class serving as our #Configuration context
main.run(); // <-- never teminates
}
}
MyRoute class:
package camelspringjavaconfig;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public class MyRoute extends RouteBuilder {
#Autowired
Environment env; //<-- we are wiring the Spring Env
#Override
public void configure() throws Exception {
System.out.println(env.getProperty("something")); //<-- so that we can extract our property
from("file://target/inbox")
.to("file://target/outbox");
}
}

Do annotations on a class still get called when only accessing static members?

I have the following class:
package hello;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
#Component
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
If I reference it in my main camel route, like so:
package com.example.integration;
import hello.*;
import org.apache.camel.ProducerTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestCamelSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("camelspring.xml");
ProducerTemplate camelTemplate = context.getBean("camelTemplate", ProducerTemplate.class);
Application.main(args);
System.out.println("Message Sending started");
camelTemplate.sendBody("jms:queue:testQSource","Sample Message");
System.out.println("Message sent");
}
}
Do my annotations in Application.class still get accessed even though I only reference Application.main?
I ask because the #EnableAutoConfiguration is supposed to configure the application for Tomcat, but now that I am not running Application.class directly, the application is defaulting to jetty and then I get an error that WebSockets are only supported in Tomcat.
Has anyone had this issue before or know how to solve it?
Here is the stack trace. I can see from the console log that it never starts the Tomcat instance that it does when the whole class is accessed in the example. It seems to be continuing as if it is a jetty app rather than Tomcat. Please correct me if any of these assumptions are wrong:
Caused by: java.lang.IllegalStateException: Websockets are currently only supported in Tomcat (found class org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory).
at org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration$1.customize(WebSocketAutoConfiguration.java:74)
at org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor.postProcessBeforeInitialization(EmbeddedServletContainerCustomizerBeanPostProcessor.java:67)
at org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor.postProcessBeforeInitialization(EmbeddedServletContainerCustomizerBeanPostProcessor.java:54)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:407)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 16 more
First of all, annotations cannot be "called".
Annotations are data, not code. In your case Spring Boot reads your annotations when you call SpringApplication.run(Application.class, args); and performs necessary configurations, therefore it doesn't matter how you call Application.main().
I guess your problem is caused by the fact that you have Jetty in the classpath, and it forces Spring Boot to use Jetty rather than Tomcat as embedded servlet container.
So, try to do the following:
Find out how Jetty appeared in your classpath
Use mvn dependency:tree -Dverbose if you use Maven
If you don't need Jetty in the classpath, exclude it from dependencies
Otherwise, you need to force Spring Boot to ignore presence of Jetty
Something like exclude = EmbeddedServletContainerAutoConfiguration.EmbeddedJetty.class in #EnableAutoConfiguration may help

Categories