Accessing Azure Service Bus with Apache Camel using Java Application? - java

How can we achieve the Azure Service Bus using Apache Camel where using camel AMQP we will have a connection with Azure Service Bus and using JMS we can listen to topic messages?
I am trying something like this, but I am getting warnings and I am not able to consume or produce messages, maybe I am not doing something correct inside createFromURL.
2022-05-28 17:37:04.450 WARN 26776 --- [r[testtopic]] c.c.j.DefaultJmsMessageListenerContainer : Setup of JMS message listener invoker failed for destination 'testtopic' - trying to recover. Cause: Timeout waiting for attach.
public class AzureMQToFileAMQ {
public static void main(String[] args) throws Exception {
Main main = new Main();
AMQPComponent connectionFactory = new AMQPComponent(
ConnectionFactoryImpl.createFromURL("amqp://testresoruce.servicebus.windows.net: 5672 "));
main.bind("amqp", connectionFactory);
main.addRouteBuilder(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("amqp:topic:testtopic").process(exchange -> {
final String body = new String((byte[]) exchange.getIn().getBody());
System.out.println(body);
});
}
});
main.run();
}
}

Related

Callback-driven Spring Cloud Dataflow source application

I want to create a Spring Cloud Dataflow source application based on a lib that connects to a messaging service (IRC, actually) and calls my callback when a message arrives. The only goal of the source app is to create an SCDF message from the received IRC message and send it to the stream.
I have come up with the following solution:
The IrcListener class annotated with #Component does some configuration and starts listening for IRC messages when the start() method is called. When a message is received its onGenericMessage callback simply sends the message to the stream via the injected source property:
#Component
public class IrcListener extends ListenerAdapter {
#Override
public void onGenericMessage(GenericMessageEvent event) {
Message msg = new Message();
msg.content = event.getMessage();
source.output().send(MessageBuilder.withPayload(msg).build());
}
private Source source;
private String _name;
private String _server;
private List<String> _channels;
public void start() throws Exception {
Configuration configuration = new Configuration.Builder()
.setName(_name)
.addServer(_server)
.addAutoJoinChannels(_channels)
.addListener(this)
.buildConfiguration();
PircBotX bot = new PircBotX(configuration);
bot.startBot();
}
#Autowired
public IrcListener(Source source) {
this.source = source;
_name = "ircsource";
_server = "irc.rizon.net";
_channels = Arrays.asList("#test".split(","));
}
}
The main class runs Spring Application and calls the aforementioned start() method on the IrcListener component.
#EnableBinding(Source.class)
#SpringBootApplication
public class IrcStreamApplication {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(IrcStreamApplication.class, args);
context.getBean(IrcListener.class).start();
}
}
This works ok and the messages are received and published to the stream successfully, but I'd like to know whether this is the right approach to take in the Spring (Cloud Dataflow) universe and or maybe I am missing something important?
It looks ok; but, generally, message-driven sources extend MessageProducerSupport and call sendMessage(Message<?>).
(and override doStart() in this case).
It would give you access to message history tracking and error handling (if the send fails).

File transfer over HTTP using camel

I'm trying to set up a Camel route for transferring files over HTTP. I'm also trying to understand the concept as I'm new to this.
When I code something like below, does that mean I'm routing a simple message over HTTP? Could I call Jetty the consumer in this case? I'm able to run the below code and call the browser and see the message successfully.
from("jetty://http://localhost:32112/greeting")
.setBody(simple("Hello, world!"));
However, I want to send a simple message(eventually an XML) over HTTP following which I would want to save it on disk and analyse it further. Should the code like below work?
CamelContext context = new DefaultCamelContext();
ProducerTemplate template = context.createProducerTemplate();
template.sendBody("direct:start", "This is a test message");
from("direct:start")
.to("jetty://localhost:32112/greeting");
from("jetty://http://localhost:32112/greeting")
.to("direct:end");
Should I be not using direct:start here for parsing XMLs?
Thanks a lot for the help.
first you have to create your routes and start your context. Then you can send messages via your template.
The route could look like this
from("jetty:http://0.0.0.0:32112/greeting")
.routeId("xml-converter-route").autoStartup(false)
.bean(xmlConverterBean, "convertXmlMethodToBeCalledInBean()")
;
If you just want to transfer data and nothing else use restlet or netty-http4. More lightweight than jetty.
from("restlet:/http://localhost:32112/greeting").convertBodyTo(String.class).log(LoggingLevel.INFO, "filetransfer", "log of body: ${body} and headers ${headers}").to("file://C:/test?fileName=body.txt");
Here's a camel test which may help you understand how these components work.
public class CamelRESTExampleTest extends CamelTestSupport {
Logger LOG = LoggerFactory.getLogger(CamelRESTExampleTest.class);
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
public void configure() {
// Create a service listening on port 8080
from("restlet:http://localhost:8080/xmlFileService?restletMethod=post")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
String rawXML = exchange.getIn().getBody(String.class);
LOG.info("rawXML=" + rawXML);
}
});
// Read files from the local directory and send to the service.
// Create a test.xml file in this directory and it will be read in
from("file:src/test/resources/data?noop=true")
.to("restlet:http://localhost:8080/xmlFileService?restletMethod=post");
}
};
}
#Test
public void test() throws InterruptedException {
// Give the route time to complete
TimeUnit.SECONDS.sleep(5);
}
}

Apache Camel BindException: "Can't Assign Requested Address"

I am in the process of learning how to use Camel. I am having an issue with the following snippet of code:
#SpringBootApplication
public class FeefooExampleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(FeefooExampleApplication.class, args);
CamelContext camelContext = new DefaultCamelContext();
camelContext.addRoutes(new CamelConfig());
camelContext.start();
Blah blah = new Blah();
blah.getFeefoData();
}
}
My CamelConfig Class is the following:
package com.example.camel;
import com.example.feefo.FeedbackProcessor;
import org.apache.camel.builder.RouteBuilder;
public class CamelConfig extends RouteBuilder {
private FeedbackProcessor feedbackProcessor = new FeedbackProcessor();
#Override
public void configure() throws Exception {
from("jetty:http://cdn2.feefo.com/api/xmlfeedback?merchantidentifier=example-retail-merchant")
.convertBodyTo(String.class)
.bean(feedbackProcessor, "processFeedback") ;
}
}
The error that is reported is the following: 'Exception in thread "main" java.net.BindException: Can't assign requested address'
Would anybody be able to help ?
Thank You
When used as a consumer, the jetty component create an HTTP server, listening to a HTTP request, and creating an exchange with this request.
In other words, when you do from("jetty:http://cdn2.feefo.com/.."), you are asking jetty to create an HTTP server with the network interface associated to "cdn2.feefo.com": This fails (well, I have assumed your machine is not this host)
If you want to request this HTTP address, you have to use jetty (or the http4 component) as a producer. For example:
from("direct:check_xmlfeedback")
.to("jetty:http://cdn2.feefo.com/api/xmlfeedback?merchantidentifier=example-retail-merchant")
...
and call your route with :
context.getProducerTemplate().requestBody("direct:check_xmlfeedback", null);
If you want to periodically poll this HTTP address, you can use the timer component:
from("timer:check?period=5m")
.to("jetty:http://cdn2.feefo.com/api/xmlfeedback?merchantidentifier=example-retail-merchant")
...

Netty 4 - Outbound message at head of pipeline discarded

I am using Netty 4 RC1. I initialize my pipeline at the client side:
public class NodeClientInitializer extends ChannelInitializer<SocketChannel> {
#Override
protected void initChannel(SocketChannel sc) throws Exception {
// Frame encoding and decoding
sc.pipeline()
.addLast("logger", new LoggingHandler(LogLevel.DEBUG))
// Business logic
.addLast("handler", new NodeClientHandler());
}
}
NodeClientHandler has the following relevant code:
public class NodeClientHandler extends ChannelInboundByteHandlerAdapter {
private void sendInitialInformation(ChannelHandlerContext c) {
c.write(0x05);
}
#Override
public void channelActive(ChannelHandlerContext c) throws Exception {
sendInitialInformation(c);
}
}
I connect to the server using:
public void connect(final InetSocketAddress addr) {
Bootstrap bootstrap = new Bootstrap();
ChannelFuture cf = null;
try {
// set up the pipeline
bootstrap.group(new NioEventLoopGroup())
.channel(NioSocketChannel.class)
.handler(new NodeClientInitializer());
// connect
bootstrap.remoteAddress(addr);
cf = bootstrap.connect();
cf.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture op) throws Exception {
logger.info("Connect to {}", addr.toString());
}
});
cf.channel().closeFuture().syncUninterruptibly();
} finally {
bootstrap.shutdown();
}
}
So, what I basically want to do is to send some initial information from the client to the server, after the channel is active (i.e. the connect was successful). However, when doing the c.write() I get the following warning and no package is send:
WARNING: Discarded 1 outbound message(s) that reached at the head of the pipeline. Please check your pipeline configuration.
I know there is no outbound handler in my pipeline, but I didn't think I need one (at this point) and I thought Netty would take care to transport the ByteBuffer over to the server. What am I doing wrong here in the pipeline configuration?
Netty only handle messages of type ByteBuf by default if you write to the Channel. So you need to wrap it in a ByteBuf. See also the Unpooled class with its static helpers to create ByteBuf instances.

Netty Camel samples

I'm a newbie to Netty.
I'm looking for some samples. (Preferably but not necessarity using Camel Netty Component and Spring)
Specifically a sample Netty app that consumes TCP messages.
Also how can I write a JUnit test that can test this netty app?
Thanks,
Dar
I assume you still want to integrate with Camel. I would first look at the camel documentation . After that frustrates you, you will need to start experimenting. I have one example where I created a Camel Processor as a Netty Server. The Netty components work such that a From endpoint is a server which consumes and a To endpoint is a client which produces. I needed a To endpoint that was a server and the component did not support that. I simply implemented a Camel Processor as a spring bean that started a Netty Server when it was initialized. The JBoss Netty documentation and samples are very good though. It is worthwhile to step through them.
Here is my slimmed down example. It is a server that sends a message to all the clients that are connected. If you are new to Netty I highly suggest going through the samples I linked to above:
public class NettyServer implements Processor {
private final ChannelGroup channelGroup = new DefaultChannelGroup();
private NioServerSocketChannelFactory serverSocketChannelFactory = null;
private final ExecutorService executor = Executors.newCachedThreadPool();
private String listenAddress = "0.0.0.0"; // overridden by spring-osgi value
private int listenPort = 51501; // overridden by spring-osgi value
#Override
public void process(Exchange exchange) throws Exception {
byte[] bytes = (byte[]) exchange.getIn().getBody();
// send over the wire
sendMessage(bytes);
}
public synchronized void sendMessage(byte[] message) {
ChannelBuffer cb = ChannelBuffers.copiedBuffer(message);
//writes to all clients connected.
this.channelGroup.write(cb);
}
private class NettyServerHandler extends SimpleChannelUpstreamHandler {
#Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelOpen(ctx, e);
//add client to the group.
NettyServer.this.channelGroup.add(e.getChannel());
}
// Perform an automatic recon.
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelConnected(ctx, e);
// do something here when a clien connects.
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
// Do something when a message is received...
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Log the exception/
}
}
private class PublishSocketServerPipelineFactory implements ChannelPipelineFactory {
#Override
public ChannelPipeline getPipeline() throws Exception {
// need to set the handler.
return Channels.pipeline(new NettyServerHandler());
}
}
// called by spring to start the server
public void init() {
try {
this.serverSocketChannelFactory = new NioServerSocketChannelFactory(this.executor, this.executor);
final ServerBootstrap serverBootstrap = new ServerBootstrap(this.serverSocketChannelFactory);
serverBootstrap.setPipelineFactory(new PublishSocketServerPipelineFactory());
serverBootstrap.setOption("reuseAddress", true);
final InetSocketAddress listenSocketAddress = new InetSocketAddress(this.listenAddress, this.listenPort);
this.channelGroup.add(serverBootstrap.bind(listenSocketAddress));
} catch (Exception e) {
}
}
// called by spring to shut down the server.
public void destroy() {
try {
this.channelGroup.close();
this.serverSocketChannelFactory.releaseExternalResources();
this.executor.shutdown();
} catch (Exception e) {
}
}
// injected by spring
public void setListenAddress(String listenAddress) {
this.listenAddress = listenAddress;
}
// injected by spring
public void setListenPort(int listenPort) {
this.listenPort = listenPort;
}
}
The camel release has a lot of examples but without a simple one for netty component.
Netty component can be use to setup a socket server to consume message and produce response back to the client. After some time of search on the web, I create my own tutorial using netty component in camel as a simple Camel-Netty hello world example to show:
Using netty component in camel to receive TCP message
Using POJO class to process the received message and create response
Sending response back to client.

Categories

Resources