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

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")
...

Related

Accessing Azure Service Bus with Apache Camel using Java Application?

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();
}
}

MockEndpoint fails to run route

Using mock to launch a salesforce streaming route as shown here fails for the following route:
from("salesforce:AccountUpdateTopic?notifyForFields=ALL&notifyForOperations=ALL")
.tracing().convertBodyTo(String.class).to("file:D:/tmp/")
.to("mock:output")
.log("SObject ID: ${body}");
in
package org.apache.camel.component.salesforce;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.component.salesforce.internal.OperationName;
import org.junit.Test;
public class StreamingApiIntegrationTest extends AbstractSalesforceTestBase {
#Test
public void testSubscribeAndReceive() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:AccountUpdateTopic");
mock.start();
Thread.sleep(10000);
mock.stop();
}
#Override
protected RouteBuilder doCreateRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
// test topic subscription
from("salesforce:AccountUpdateTopic?notifyForFields=ALL&notifyForOperations=ALL").tracing().convertBodyTo(String.class).to("file:D:/tmp/").to("mock:output").log("SObject ID: ${body}");
}
};
}
}
Running this test does not start the route (updates are not fetched from Salesforce and stored in /tmp/).
Can mock run a route and wait for updates from Salesforce? Is there a shorter example that allows for testing salesforce routes without making use of spring?
You misunderstood the Camel Mock component. Mocks are not starting anything. They are just endpoints who record and assert the messages they receive.
To trigger a Camel route you have to send a message to it. You can do this easily using a ProducerTemplate.
It is this line from the example you mention that does exactly that.
CreateSObjectResult result = template().requestBody(
"direct:upsertSObject", merchandise, CreateSObjectResult.class);
template is the ProducerTemplate and requestBody the method to send a message to the endpoint direct:upsertSObject and wait for a response. See the Javadocs of ProducerTemplate for the various existing signatures.

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);
}
}

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.

Categories

Resources