Spring WebSocket integration test works at random - java

I have absolutely simple SpringBoot project with simple configuration and simple integration test to test WebSockets.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sandbox.websocket</groupId>
<artifactId>websocket</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SpringBootApplication:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Message broker configuration
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/greeting")
.withSockJS();
}
}
Integration Test to simply connect to server, subscribe to message broker and send message.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class WebSocketIntegrationTest {
#LocalServerPort
private int localServerPort;
private BlockingQueue<String> blockingQueue;
#Before
public void setup() {
blockingQueue = new LinkedBlockingDeque<>();
}
#Test
public void shouldReceiveAMessageFromTheServer() throws Exception {
String uri = "ws://localhost:" + localServerPort + "/greeting";
WebSocketStompClient stompClient = new WebSocketStompClient(
new SockJsClient(Collections.singletonList(
new WebSocketTransport(
new StandardWebSocketClient()))));
String message = "MESSAGE TEST";
ListenableFuture<StompSession> connect = stompClient.connect(uri, new StompSessionHandlerAdapter() {});
StompSession session = connect.get(1, SECONDS);
session.subscribe("/topic", new DefaultStompFrameHandler());
session.send("/topic", message.getBytes());
Assert.assertEquals(message, blockingQueue.poll(10, SECONDS));
}
class DefaultStompFrameHandler implements StompFrameHandler {
#Override
public Type getPayloadType(StompHeaders stompHeaders) {
return byte[].class;
}
#Override
public void handleFrame(StompHeaders stompHeaders, Object o) {
System.out.println("=============================================================");
System.out.println(new String((byte[]) o));
System.out.println("=============================================================");
blockingQueue.offer(new String((byte[]) o));
}
}
}
If I run it and test it from javascript client it works like a charm.
If I run the integration test it works only sometimes. The problem is that sometimes DefaultStompFrameHandler.handleFrame() method is not called, therefore nothing is saved to the queue and assert fails.
I wrote an InboundChannel interceptor to intercept frames and print commands to the console and all four commands are allways printed (CONNECT, SUBSCRIBE, SEND, DISCONNECT).
So, all commands go to the server including SEND, but sometimes (60-70%) StompFrameHandler is not being used no matter how long the queue.poll timeout is set.
Any help, please?

Related

Can't initialize mongo db using ape-nosql-mongo #UsingDataSet

I want to run some integration test using Arquillian, Arquillian cube and Mongo. The desired scenario is:
Start the application in a managed container. Here I want to use Shrinkwrap to add just the service I want to test (for example dao service)
Start the database inside a docker container. Populate the db with some initial data
Run the test against the database
My test looks like this:
#Inject
MongoProducer producer;
#Test
#UsingDataSet(locations = "initialData.json")
public void shouldGetAllFromMongo() {
FindIterable<Document> documents = producer.getMongoClient().getDatabase("bearsdb").getCollection("bears").find();
documents.forEach((Block<? super Document>) e-> System.out.println(e));
}
The initialData.json is under src/test/resources and format of the seeding data is as bellow:
{
"bears": [
{
"firstName": "grizz",
"lastName": "the bear",
"age": 3
},
{
"firstName": "panpan",
"lastName": "the bear",
"age": 3
},
{
"firstName": "icebear",
"lastName": "the bear",
"age": 4
}
]}
My docker-compose file looks like this:
version: '3'
services:
mongo-test-db:
image: mongo:latest
environment:
- MONGO-INITDB-DATABASE=bearsdb
- MONGO-INITDB_ROOT_USERNAME=panda
- MONGO-INITDB_ROOT_PASSWORD=pass
ports:
- 27117:27017
I don't really know if the environments help but I saw this in an example.
My pom.xml contains:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-bom</artifactId>
<version>${version.shrinkwrap.resolvers}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.1.15.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.arquillian</groupId>
<artifactId>arquillian-universe</artifactId>
<version>${version.arquillian_universe}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
and as dependencies
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.arquillian.cube</groupId>
<artifactId>arquillian-cube-docker</artifactId>
<version>${org.arquillian.cube.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.arquillian.universe</groupId>
<artifactId>arquillian-ape-sql-container-dbunit</artifactId>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.arquillian.universe</groupId>
<artifactId>arquillian-ape-nosql-mongodb</artifactId>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.4.3</version>
</dependency>
Please note that I don't use the arquillian-junit-standalone dependency.
Additional note is that I'm using ShwripWrack to package and I deploy the war into an managed Wildfly 8.2.0.Final server. Additionl in the same test class I've tested also against an Postgres running inside docker and for this the #UsingDataSet works ok. Bellow is the working sql test and the createDeploy method:
#Deployment
public static WebArchive createDeployment() {
JavaArchive[] javaArchives = Maven.resolver().resolve(
"org.assertj:assertj-core:3.15.0",
"org.arquillian.cube:arquillian-cube-docker:1.18.2",
"org.mongodb:mongo-java-driver:3.4.3")
.withTransitivity().as(JavaArchive.class);
WebArchive war = ShrinkWrap.create(WebArchive.class, "app.war")
.addClasses(PersonDao.class, Person.class)
.addClasses(MongoProducer.class, PropertyProducer.class, Property.class)
.addAsLibraries(javaArchives)
.addAsResource("test-persistence.xml", ArchivePaths.create("META-INF/persistence.xml"))
.addAsResource("META-INF/application.properties", ArchivePaths.create("META-INF/application.properties"))
.addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml"));
System.out.println(war.toString(true));
return war;
}
#Test
#org.arquillian.ape.rdbms.UsingDataSet("datasets/persons.xml")
public void shouldFindAll() {
List<Person> messages = personDao.findAll();
assertThat(messages.size()).isEqualTo(1);
}
The issue with the above test is that the database doesn't get initialize and nothing is printed out.
I managed to resolve my problem. The issue is that I forgot to add an Junit rule where the configuration to the Mongo database was set.
#Rule
public MongoDbRule mongoDbRule = new MongoDbRule(MongoDbConfigurationBuilder.mongoDb()
.host("localhost")
.port(27117)
.databaseName("pandadb")
.build());
The full test class looks like:
#RunWith(Arquillian.class)
public class PersonDaoDockerIT {
#Rule
public MongoDbRule mongoDbRule = new MongoDbRule(MongoDbConfigurationBuilder.mongoDb()
.host("localhost")
.port(27117)
.databaseName("pandadb")
.build());
#Deployment
public static WebArchive createDeployment() {
JavaArchive[] javaArchives = Maven.resolver().resolve(
"org.assertj:assertj-core:3.15.0",
"org.arquillian.cube:arquillian-cube-docker:1.18.2",
"org.mongodb:mongo-java-driver:3.4.3")
.withTransitivity().as(JavaArchive.class);
WebArchive war = ShrinkWrap.create(WebArchive.class, "app.war")
.addClasses(PersonDao.class, Person.class)
.addClasses(MongoProducer.class, PropertyProducer.class, Property.class)
.addPackages(true, "com.lordofthejars.nosqlunit")
.addAsLibraries(javaArchives)
.addAsResource("test-persistence.xml", ArchivePaths.create("META-INF/persistence.xml"))
.addAsResource("META-INF/application.properties", ArchivePaths.create("META-INF/application.properties"))
.addAsResource("datasets/", ArchivePaths.create("datasets/"))
.addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml"));
System.out.println(war.toString(true));
return war;
}
#Inject
PersonDao personDao;
#Inject
MongoProducer producer;
#Test
public void injectionPointShouldBeNotNull() {
assertThat(personDao).isNotNull();
}
#Test
public void mongoProducerShouldBeNotNull() {
assertThat(producer).isNotNull();
}
#Test
#org.arquillian.ape.rdbms.UsingDataSet("datasets/persons.xml")
public void shouldFindAll() {
List<Person> messages = personDao.findAll();
assertThat(messages.size()).isEqualTo(1);
}
#Test
#UsingDataSet(locations = "/datasets/initialData.json")
public void shouldGetAllFromMongo() {
FindIterable<Document> documents = producer.getMongoClient().getDatabase("pandadb").getCollection("bears").find();
documents.forEach((Block<? super Document>) System.out::println);
}
}

Why is my IE browser getting launched twice with Selenium and Cucumber?

I am writing very basic automation test with Selenium-Cucumber that is launching an IE browser and closing it at the end.
The problem is that the browser gets launched twice.
The test does not have much it other than few System.out statements. I am kind of new to both selenium-based automation testing and Cucumber and not able to understand why is it getting launched twice.
Please guide.
BrowserConfig.java
public class BrowserConfig {
private static final String IE_DRIVER_EXE = "drivers/IEDriverServer.exe";
private static final String WEBDRIVER_IE_DRIVER = "webdriver.ie.driver";
private static final String BASE_URL = "https://www.google.com";
public static WebDriver getIEWebDriver() {
String filePath = ClassLoader.getSystemClassLoader().getResource(IE_DRIVER_EXE).getFile();
System.setProperty(WEBDRIVER_IE_DRIVER, filePath);
InternetExplorerOptions options = new InternetExplorerOptions().requireWindowFocus();
options.setCapability(INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
options.setCapability(ENABLE_ELEMENT_CACHE_CLEANUP, true);
options.setCapability(IE_ENSURE_CLEAN_SESSION, true);
options.setCapability(ACCEPT_SSL_CERTS, true);
options.setCapability("nativeEvents", false);
options.setCapability(INITIAL_BROWSER_URL, BASE_URL);
WebDriver driver = new InternetExplorerDriver(options);
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
return driver;
}
public static void releaseResources(WebDriver driver) {
if (null != driver) {
driver.close();
driver.quit();
}
}
}
TestRunner.java
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty", "json:target/cucumber-reports/cucumber.json"},
features = {"src/test/resources/features"})
public class TestRunner extends ApplicationTests {
}
LoginStep.java
#Ignore
public class LoginStep {
WebDriver driver;
#Before
public void setup() {
if (this.driver == null) {
this.driver = BrowserConfig.getIEWebDriver();
}
}
#After
public void cleanUp() {
BrowserConfig.releaseResources(driver);
}
#Given("^The user is on the Login page$")
public void doLogin() {
System.out.println("The user is on the Login page");
}
#When("^The user enters the correct credentials on the Login page$")
public void setWelcomePage() {
System.out.println("The user enter the correct credentials on the Login page");
}
#Then("^The user is displayed Welcome page$")
public void validate() {
System.out.println("The user is displayed Welcome page");
}
}
HelpStep.java
#Ignore
public class HelpStep {
WebDriver driver;
#Before
public void setup() {
if (this.driver == null) {
this.driver = BrowserConfig.getIEWebDriver();
}
}
#After
public void cleanUp() {
BrowserConfig.releaseResources(driver);
}
#When("^The user clicks on the Help menu link from the Welcome page$")
public void setWelcomePage() {
System.out.println("The user clicks on the Help menu link from the Welcome page");
}
#Then("^The user is displayed Help page$")
public void validate() {
System.out.println("The user is displayed Help page");
}
}
help.feature
Feature: Check that the user is able to navigate to Help page
Background:
Given The user is on the Login page
When The user enters the correct credentials on the Login page
Then The user is displayed Welcome page
Scenario:
When The user clicks on the Help menu link from the Welcome page
Then The user is displayed Help page
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>cucumber-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cucumber-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<cucumber.version>4.2.3</cucumber.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<plugin>
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>3.14.0</version>
<executions>
<execution>
<id>execution</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<projectName>${project.artifactId}</projectName>
<outputDirectory>${project.build.directory}/cucumber-reports</outputDirectory>
<cucumberOutput>${project.build.directory}/cucumber-reports/cucumber.json</cucumberOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Because you are initializing and call your driver twice in feature files.
Background part of your feature file are initializing browser firstly in LoginStep.java then your Scenario is also initialize browser in HelpStep.java.
I prefer using global Hooks.java class for #Before and #After hooks and inject driver between different .java classes.
Found the solution. The below sample code is not the same as original post but this fixes the issue. Added new class "Hooks.java" that contains common steps and removed "Background" from feature files. That helped fix the issue.
Hooks.java
public class Hooks {
public static WebDriver driver;
#Before
public void setUp() {
System.out.println("Into the setup method of AccountStep...");
driver = BrowserConfig.getDriver();
}
#After
public void cleanUp() {
System.out.println("Into the cleanUp method of AccountStep...");
if (null != driver) {
driver.close();
driver.quit();
}
}
}
help.feature
Feature: Check that the user is able to navigate to Help page
Scenario:
Given The user is on the Help page
When The user clicks on the links within the Help page
Then The user is navigated to that Help section
HelpStep.java
#Ignore
public class HelpStep {
private WebDriver driver;
public HelpStep() {
this.driver = Hooks.driver;
}
#Given("^The user is on the Help page$")
public void onPage() {
System.out.println("The user is on the Help page");
}
#When("^The user clicks on the links within the Help page$")
public void clickLinks() {
System.out.println("The user clicks on the links within the Help page");
}
#Then("^The user is navigated to that Help section$")
public void validate() {
System.out.println("The user is navigated to that Help section");
}
}
Make sure you specific the before and after hooks with tag for every Feature, Why ? ok for example you have two features called UsersFeature and ProductsFeature and you make some hooks like initBrowser as before and closeBrowser as after for UsersFeature and ProductsFeature what happens when you run that test without any tags ? let me tell you that hooks it will running for tow times or (N times for parallel) for every Feature for that test and N = "number of the features in that test" so all the before hooks in that test will runing first even if there is million Features and also the all the after hooks so make sure use tags like #Before('#users_feature') #After('#users_feature') in that time that hooks will runing only when the test executing the feature scenarios with #users_feature tag

How shoud I fix this Java error, caused by it`s working on Heroku?

I have already successfully deployed my app on Heroku, but my app is crashing while running.
I`m getting am error:
Error R10 (Boot timeout) -> Web process failed to bind to $PORT within
90 seconds of launch
I found in internet this code, which pasted in main class - no result:
public static String PORT = System.getenv("PORT");
public static String SERVER_URL = System.getenv("SERVER_URL");
Procfile:
web: java $JAVA_OPTS -Dserver.port=$PORT -cp
target/classes:target/dependency/* Bot
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>tgBot</artifactId>
<dependencies>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>4.1.2</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals><goal>copy-dependencies</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Main class:
import org.telegram.telegrambots.ApiContextInitializer;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import java.io.IOException;
public class Bot extends TelegramLongPollingBot {
public static String PORT = System.getenv("PORT");
public static String SERVER_URL = System.getenv("SERVER_URL");
public static void main(String[] args) {
ApiContextInitializer.init();
TelegramBotsApi bot = new TelegramBotsApi();
try {
bot.registerBot(new Bot());
} catch (TelegramApiRequestException e) {
e.printStackTrace();
}
}
public void onUpdateReceived(Update update) {
Message message = update.getMessage();
Methods method = new Methods();
Answers answer = new Answers();
Model model = new Model();
if (message != null && message.hasText()) {
if (message.getText() == answer.row1Button) {
method.sendMsg(message, answer.faq);
}
String s = message.getText();
if ("/start".equals(s) || "Справка/помощь по боту".equals(s) || "/help".equals(s)) {
method.sendMsg(message, answer.faq);
} else if ("/api".equals(s)) {
method.sendMsg(message, answer.api);
} else {
try {
method.sendMsg(message, Weather.getWeather(message.getText(), model));
} catch (IOException e) {
method.sendMsg(message, answer.fail);
}
}
}
}
public String getBotUsername() {
return "Weather";
}
public String getBotToken() {
return "my bot token :D";
}
}
This could help you https://github.com/pengrad/telegram-bot-heroku, but it uses other library to work with Telegram Bot API – java-telegram-bot-api
There is a Procfile (need to update main class there) and build.gradle files for deploy.
By default it sets Webhook:
public class Main {
public static void main(String[] args) {
final String portNumber = System.getenv("PORT");
if (portNumber != null) {
port(Integer.parseInt(portNumber));
}
// current app url to set webhook
// should be set via heroku config vars
// https://devcenter.heroku.com/articles/config-vars
// heroku config:set APP_URL=https://app-for-my-bot.herokuapp.com
final String appUrl = System.getenv("APP_URL");
// define list of bots
BotHandler[] bots = new BotHandler[]{
new TestTelegramBot()
};
// set bot to listen https://my-app.heroku.com/BOTTOKEN
// register this URL as Telegram Webhook
for (BotHandler bot : bots) {
String token = bot.getToken();
post("/" + token, bot);
if (appUrl != null) {
bot.getBot().execute(new SetWebhook().url(appUrl + "/" + token));
}
}
}
}
Can easily change to long polling:
bot.setUpdatesListener(updates -> {
for (Update update : updates) {
onUpdateReceived(update);
}
return UpdatesListener.CONFIRMED_UPDATES_ALL;
});

Springcloud bus custom messages cannot be sent through rabbitmq

When using the springcloud bus, a custom message is created and sent through rabbitmq, but after the message is sent, it does not go to rabbitmq. When you try to call /actuator/bus-refresh, you can see the bus messages emitted from the console page of rabbitmq.
I tried to start a micro service to register a custom event listener but failed to receive it. However, if the sender registers a listener himself, he can receive it but does not send it from rabbitmq.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
About #RemoteApplicationEventScan annotations, I code all under the same package, so I should be able to scan to TestEvent. I also tried to specify basepackage.
#SpringBootApplication
#RemoteApplicationEventScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#RestController
#RequestMapping("test")
public class TestController {
#Autowired
private ApplicationContext context;
#RequestMapping("test")
public String test() {
final TestEvent testEvent = new TestEvent(this, context.getId(), null,"test");
context.publishEvent(testEvent);
return "success";
}
}
#Data
public class TestEvent extends RemoteApplicationEvent {
private String action;
public TestEvent(Object source, String originService, String destinationService, String action) {
super(source, originService, destinationService);
this.action = action;
}
}
When I called http://localhost:8080/actuator/bus-refresh I can see the information in the rabbitmq.
{" type ":" AckRemoteApplicationEvent ", "timestamp" : 1554350325406, "originService" : "application: 0: b3461fbec3536203a7020ff9d24bb11b", "destinationService" : "* *", "id" : "e6b875bd - 2402-494 - f - a870 - 4917324 d2c5c ackId ", "" :" af93075e - 55 d2-41 f8 - ba27 - e3c80cf19eea ", "ackDestinationService" : "* *", "the event" is: "org. Springframework. Cloud. Bus. Event. RefreshRemoteApplicationEvent"}.
But when I call to http://localhost:8080/test/test, I don't.
I came into the same issue a few days ago and it turned out that it was because the originService was incorrect. passing in context.getId() as originService doesn't work.
Short answer: use org.springframework.cloud.bus.BusProperties#id. You can inject BusProperties to your component. Or you can configure your own spring cloud bus id as stated in the document.
I am not 100% sure this is the proper way. Maybe I missed something in the document. It is just based on what I read from the source code of org.springframework.cloud.bus.BusAutoConfiguration, method acceptLocal.
Hope it works for you.

Unable to connect to mongo database using Java, OSGI, Karaf

I've installed the mongo driver in my running Karaf server:
bundle:install -s wrap:mvn:org.mongodb/mongo-java-driver/3.6.3
I'm simply trying to connect to the DB and log the databases I have. Currently running out of the box local instance. Below is the code I wrote to demo this in OSGI/Karaf. I'm using the mvn bundle plugin.
I created a database under the alias osgiDatabase
I'm running my debugger and the failure happens during the instantiation of the MongoClient() but not understanding what I could be doing wrong.
This works when I don't use Karaf. The only error I get is Activator start error in bundle
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qa</groupId>
<artifactId>board</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>6.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>com.mongodb, org.osgi.framework</Import-Package>
<Bundle-Activator>Connection.Activator</Bundle-Activator>
<Export-Package>*</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
DBUtil
package Connection;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import java.util.List;
public class DBUtil {
MongoClient client;
MongoDatabase database;
public DBUtil() {
}
public DBUtil(String databaseName) {
if (client == null) {
client = new MongoClient();
database = client.getDatabase(databaseName);
}
}
/**
* Allows you to reveal all databases under the current connection
*/
public void showDatabases() {
if (client == null) {
throw new NullPointerException();
}
List<String> databases = client.getDatabaseNames();
for (String db : databases) {
System.out.println("The name of the database is: " + db);
}
}
}
Activator
package Connection;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
public void start(BundleContext bundleContext) throws Exception {
DBUtil util = new DBUtil("osgiDatabase");
// util.showDatabases();
System.out.println("Working");
}
public void stop(BundleContext bundleContext) throws Exception {
System.out.println("Bundle disabled");
}
}
Your Import-Package configuration looks wrong. If you configure it explicitly like this you switch off the auto detection of needed packages. So it is very likely you are missing some packages your code needs.
Instead try to only configure the activator and leave the rest on defaults.
To get better logs you should use a try catch in your Activator an log the exception using slf4j. So you get some more information what is wrong.

Categories

Resources