Accessing Azure Service Bus with Apache Camel? - java

How can you access the Azure Service Bus using Apache Camel using Camel as a standalone Java application?

If you are trying to access Azure Service Bus using Apache Camel you can do so by using the Camel AMQ libraries.
You can use the following Maven dependencies in case of you are using Maven:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-parent</artifactId>
<version>2.17.6</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-amqp</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.qpid/qpid-amqp-1-0-client-jms -->
<dependency>
<groupId>org.apache.qpid</groupId>
<artifactId>qpid-amqp-1-0-client-jms</artifactId>
<version>0.32</version>
</dependency>
</dependencies>
Note: I am using a relatively old version of Apache Camel here, but this setup should work with newer versions too.
If you want to create an endpoint for consuming messages from the Azure Service Bus you can create an AMQComponent which acts as a connection factory bind it to the registry and then use it to listen to messages.
Here is an example:
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.amqp.AMQPComponent;
import org.apache.camel.main.Main;
import org.apache.qpid.amqp_1_0.jms.impl.ConnectionFactoryImpl;
public class AzureMQToFileAMQ {
public static void main(String[] args) throws Exception {
Main main = new Main();
AMQPComponent connectionFactory = new AMQPComponent(
ConnectionFactoryImpl
.createFromURL("amqps://"
+ "dev.emea-uk-test.q:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#xxxxxxxxxxxxxxxxxxxxxxxxxxx.servicebus.windows.net"
+ ":" + "5671"));
main.bind("amqp", connectionFactory);
main.addRouteBuilder(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("amqp:queue:dev.emea.uk.test.q?consumerType=Simple")
.process(exchange -> {
final String body = new String((byte[])exchange.getIn().getBody());
System.out.println(body);
});
}
});
main.run();
}
}

This project is a very good option.

Related

Filtering a string URI before parsing in reactor-netty HttpServer

Assume we have dependencies as described here.
pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-bom</artifactId>
<version>2022.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-core</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
</dependency>
</dependencies>
and simple HttpServer application
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;
public class Application {
public static void main(String[] args) {
DisposableServer server =
HttpServer.create()
.host("localhost")
.port(8080)
.bindNow();
server.onDispose()
.block();
}
}
URI parsing is a very dangerous operation in our time.
How can I access the URI string before it will be parsed with HttpOperations.resolvePath method?
It is very important to apply some filters and rules in this place to protect against malicious requests.
Lifecycle callbacks don't help me. Filtering with nginx or HttpLoadBalancer add a very high latency so they are not suitable. I expect low latency.
Thank you!

Cannot persist via Hibernate ORM with Panache using rubenlagus/TelegramBots

I'm using Quarkus 2.15.1 and rubenlagus/TelegramBots 6.3.0
My pom.xml dependencies are:
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
I've configured jdbc URL, username & password as well.
The problem is when I'm trying to persist an object (via Active Record or Repository pattern) there is an exception.
The code snippet is:
#ApplicationScoped
public class VoteBot extends TelegramLongPollingBot {
#Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
long chatId = update.getMessage().getChatId();
String messageText = update.getMessage().getText();
if (messageText.matches("^[A-Za-z\\s]+$")) {
Participant participant = new Participant();
participant.setChatId(chatId);
participant.setName(messageText);
// Some code
Participant.persist(participant); // Here is the exceptional line goes
// Some code
}
}
Startup class looks like:
#ApplicationScoped
public class Application {
void onStart(#Observes StartupEvent ev) {
try {
TelegramBotsApi telegramBotsApi = new TelegramBotsApi(DefaultBotSession.class);
telegramBotsApi.registerBot(new VoteBot());
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
The exception message is:
2022-12-25 02:22:19,727 ERROR [org.tel.tel.upd.DefaultBotSession] (ckorovoda_vote_bot Telegram Executor) Cannot use the EntityManager/Session because neither a transaction nor a CDI request context is active. Consider adding #Transactional to your method to automatically activate a transaction, or #ActivateRequestContext if you have valid reasons not to use transactions.: javax.enterprise.context.ContextNotActiveException: Cannot use the EntityManager/Session because neither a transaction nor a CDI request context is active. Consider adding #Transactional to your method to automatically activate a transaction, or #ActivateRequestContext if you have valid reasons not to use transactions.
at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.acquireSession(TransactionScopedSession.java:106)
at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.contains(TransactionScopedSession.java:325)
at org.hibernate.engine.spi.SessionLazyDelegator.contains(SessionLazyDelegator.java:710)
at org.hibernate.Session_5b93bee577ae2f8d76647de04cfab36afbf52958_Synthetic_ClientProxy.contains(Unknown Source)
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.persist(AbstractJpaOperations.java:100)
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.persist(AbstractJpaOperations.java:96)
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.persist(AbstractJpaOperations.java:112)
at io.quarkus.hibernate.orm.panache.PanacheEntityBase.persist(PanacheEntityBase.java:756)
at store.ckorovoda.Participant.persist(Participant.java)
at store.ckorovoda.VoteBot.onUpdateReceived(VoteBot.java:74)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.telegram.telegrambots.meta.generics.LongPollingBot.onUpdatesReceived(LongPollingBot.java:27)
at org.telegram.telegrambots.updatesreceivers.DefaultBotSession$HandlerThread.run(DefaultBotSession.java:317)
I've tried adding #Transactional, #ActivateRequestContext and changing bean scopes. I've also tried to use EntityManager and quarkus-narayana-jta. However, I'm pretty sure it's all connected with this 3rd-party lib for Telegram.
I'm stuck with it and will appreciate any recommendation or hints for resolving that stuff.
Thank you!

Issue in creating Keycloak object in quarkus application

While working with keycloak Java Distribution 8.0.0 API and quarkus I have an issue in creating Keycloak objects.
dependencies list
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus-plugin.version>1.0.0.CR2</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.0.0.CR2</quarkus.platform.version>
<surefire-plugin.version>2.22.1</surefire-plugin.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>8.0.0</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
</dependencies>
main method
public static void main(String[] args) {
String serverUrl = "http://localhost:8181/auth";
String realmId = "master";
String clientId = "admin-cli";
KeycloakClient client = new KeycloakClient(serverUrl, realmId, clientId);
Keycloak kc = client.getKeycloak("adminuser", "adminpassword");
RealmResource realmResource = kc.realm("keycloak-client");
UsersResource userRessource = realmResource.users();
if (userRessource != null) {
System.out.println("Count: " + userRessource.count());
} else {
System.out.println("null");
}
}
keycloak client class
public Keycloak getKeycloak(final String username, final String password) {
// Type mismatch: cannot convert from Client to ResteasyClient
ResteasyClient resteasyClient = new ResteasyClientBuilder().connectionPoolSize(10)
.register(new CustomJacksonProvider()).build();
return KeycloakBuilder.builder().serverUrl(this.serverUrl).realm(this.realmId).username(username)
.password(password).clientId(this.clientId).resteasyClient(resteasyClient).build();
}
I came to know that the issue was caused due to keycloak-admin-client which still use ResteasyClient as a Class here so i changed my dependency list to the following.
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>8.0.0</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.6.3.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>3.6.3.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.6.3.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
Now the Main method working fine but I got another error.
Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.resteasy.server.common.deployment.ResteasyServerCommonProcessor#build threw an exception: java.lang.IncompatibleClassChangeError: Implementing class
I want to know that is that possible to work quarkus and keycloak-admin alongside with current version. else there any workaround possible.
Thanks

Netty HttpServer api changed/differs from available examples

Netty server instantiation in Arjen Poutsma's blog post and Josh Long's video example is done by creating an reactor.ipc.netty.http.HttpServer instance and then calling it's start or startAndAwait method with an ReactorHttpHandlerAdapter instance as an argument.
However the API seems to have changed as now start and startAndAwait methods now expect a lambda with the following signature:
java.util.function.Function<? super reactor.ipc.netty.http.HttpChannel,? extends org.reactivestreams.Publisher<java.lang.Void>>
Project dependencies and their versions are the same as in Arjen Poutsma's example project
<dependency>
<groupId>org.reactivestreams</groupId>
<artifactId>reactive-streams</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>io.projectreactor.ipc</groupId>
<artifactId>reactor-netty</artifactId>
<version>0.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web-reactive</artifactId>
<version>5.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.2</version>
</dependency>
What is the new/proper way of instantiating a netty server with spring reactor support?
The recommended way to set up project for now is to use http://start.spring.io/ as Josh Long suggests in his video. This is because spring reactive is only release candidate now and we need compatible versions to run samples.This is achieved via adding this piece to code:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-dependencies-web-reactive</artifactId>
<version>0.1.0.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
According your question about HttpServer interface change, the minimal working example is the following:
import org.reactivestreams.Publisher;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.RouterFunction;
import org.springframework.web.reactive.function.ServerRequest;
import org.springframework.web.reactive.function.ServerResponse;
import reactor.core.publisher.Mono;
import reactor.ipc.netty.http.server.HttpServer;
import java.io.IOException;
import static org.springframework.web.reactive.function.RequestPredicates.GET;
import static org.springframework.web.reactive.function.RouterFunctions.route;
import static org.springframework.web.reactive.function.RouterFunctions.toHttpHandler;
public class FunctionalReactiveServer {
public static final String HOST = "localhost";
public static final int PORT = 8080;
public static void main(String[] args) throws InterruptedException, IOException {
RouterFunction<?> route = route(GET("/sayHello"), FunctionalReactiveServer::sayHelloHandler);
HttpHandler httpHandler = toHttpHandler(route);
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
HttpServer server = HttpServer.create(HOST, PORT);
server.newHandler(adapter).block();
System.out.println("Press ENTER to exit.");
System.in.read();
}
public static ServerResponse<Publisher<String>> sayHelloHandler(ServerRequest request) {
return ServerResponse.ok().body(Mono.just("Hello!"), String.class);
}
}

Spring Cloud Zuul CircuitBreaker All Routes via TurbineStream Not Turbine-AMQP

I'm using spring boot 1.3.1 and spring cloudl Brixtom.M4, While using springboot 1.3.1 i found that Turbine-AMQP project is no longer available instead we have now Spring Turbine Stream project.
I what to user SpringTurbine with rabbitmq or kafka and want to monitor hystrix stream of all routes registered in Zuul, I'm able to see the hystrix.stream for the zuul and also able to see that in hystrix dashboard, but not sure how to use the spring turbine stream.
On the net i found the code and documentation for using Turbine AMQP.
I have zuul server running ad http://localhost:9003/ with depedencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
and main.java as
#SpringBootApplication
#EnableZuulProxy
#EnableCircuitBreaker
public class EdgeServerApplication {
public static void main(String[] args) {
SpringApplication.run(EdgeServerApplication.class, args);
}
}
I also have springTurbinestream project as
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-turbine-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
org.springframework.boot
spring-boot-starter-actuator
and main class for TurbineStream as
#SpringBootApplication
#EnableTurbineStream
#EnableDiscoveryClient
public class WiziqTurbineApplication {
public static void main(String[] args) {
SpringApplication.run(WiziqTurbineApplication.class, args);
}
}
When I run the application and go to http://localhost:9003/hystrix.stream i see the stream but if i go to http://localhost:9003/turbine.stream it going on error.
What I'm doing wrong?
Your client app (on port 9003) is not supposed to have a /turbine.stream. It is supposed to send messages with hystrix metrics to rabbit (for instance). To make it do that you need to add spring-cloud-netflix-hystrix-stream and spring-cloud-starter-stream-rabbit (just like you did on the server for the *-turbine-* dependencies).

Categories