Can I know which endpoint is finally targeted when using load balancer? - apache-camel

I have a route using a customized load balancer as,
from("timer://myTimer?period=2000")
.loadBalance(new MyCustomLoadBalancer())
.to("mock:em1").to("mock:em2").to("mock:em3")
.end();
In the customized balancer class, it seems only processors can be gotten.
public class MyCustomLoadBalancer extends SimpleLoadBalancerSupport {
public void process(Exchange exchange) throws Exception {
List<Processor> pList = getProcessors();
.......
//It is wanted to log which endpoint is finally targeted.
foo.process(exchange);
}
}
But here, I want to log actually which endpoint is targeted when using this load balancer.
In product environment, Jetty or HTTP endpoints will be used instead of these mock endpoints.
Is there a way to realized this?
===================================================================
Based on the suggestion from Ibsen, I used the Jetty endpoint to do test.
from("jetty:http://0.0.0.0:8043?matchOnUriPrefix=true")
.loadBalance(new MyCustomLoadBalancer())
.to("jetty:http://localhost:80?bridgeEndpoint=true&throwExceptionOnFailure=false")
.to("jetty:http://www.google.com?bridgeEndpoint=true&throwExceptionOnFailure=false")
.end();
But the Processors are not class of SendProcessor("foo instanceof SendProcessor" returns false), so I can't get the endpoint by getDestination.
I believe there should be some relationship between the endpoint and processor.
Could you give me more help?
Thanks.

The Processor is a SendProcessor where you can get the endpoint it will send the exchange to.
if (foo instanceof SendProcessor) {
SendProcessor send = (SendProcessor) foo;
Endpoint dest = send.getDestination();
...
}

Related

Camel-Azure BlobServiceProducer IllegalArgumentException: Unsupported blob type:org.apache.camel.component.file.GenericFile

I have written a camel route which polls a folder and sends it to Azure Blob Container
I followed the example mentioned in the Azure document page
https://github.com/apache/camel/blob/master/components/camel-azure/src/main/docs/azure-blob-component.adoc
I am reversing the route. Instead of a consumer, I am using the Azure Blob Producer.
This is my route. I have used Java DSL.
from("file://C:/camel/source1").to("azure-blob://datastorage/container1/BLOB1?credentials=#credentials&operation=updateBlockBlob")
When I placed a file, I got the following error.
**java.lang.IllegalArgumentException: Unsupported blob type:org.apache.camel.component.file.GenericFile
at org.apache.camel.component.azure.blob.BlobServiceProducer.getInputStreamFromExchange(BlobServiceProducer.java:474) ~[camel-azure-2.19.2.jar:2.19.2]
at org.apache.camel.component.azure.blob.BlobServiceProducer.updateBlockBlob(BlobServiceProducer.java:143) ~[camel-azure-2.19.2.jar:2.19.2]
at org.apache.camel.component.azure.blob.BlobServiceProducer.process(BlobServiceProducer.java:79) ~[camel-azure-2.19.2.jar:2.19.2]**
I was able to fix this. I rewrote my route as.
from("file://C:/camel/source1")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
Object file = exchange.getIn().getMandatoryBody();
exchange.getOut().setBody(
GenericFileConverter.genericFileToInputStream(
(GenericFile<?>) file, exchange));
}
})
.to("azure-blob://datastorage/container1/BLOB1?credentials=#credentials&operation=updateBlockBlob")
.to("mock:Result");
My Question is, do I need to really write the processor? Shouldn't the camel component be receiving a stream or a File Object?
Yeah this is a little bug. I have logged a ticket: https://issues.apache.org/jira/browse/CAMEL-11844
You can do the workaround you did, or you can add a .convertBodyTo and convert to a FileInputStream, String etc.
from("file://C:/camel/source1")
.convertBodyTo(String.class)
...

Mocking XMPP endpoints

I'm trying to verify my Camel routes I need to prevent the endpoints from starting, the XMPP in particular as it contains concrete host information in their URI. Unfortunately I don't seem to figure out how.
My test class is as follows:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = {
ApplicationConfig.class
},
loader = CamelSpringDelegatingTestContextLoader.class)
#UseAdviceWith
#MockEndpointsAndSkip
public class XMPPRouteBuilderTest {
#Autowired
ApplicationContext applicationContext;
#Autowired
CamelContext camelContext;
#Test
public void testConfigure() throws Exception {
camelContext.start();
Collection<Endpoint> endpoints = camelContext.getEndpoints();
}
}
Whenever I call start() the actual endpoints are started which causes the XMPP routes to fail with host not found exceptions; I was expecting the mocks to replace the real ones.
Can anyone suggest what am I doing wrong?
Best,
Edoardo
#MockEndpointsAndSkip is only for producers (eg not consumers) so all the route from endpoints is not mocked.
You can use the replaceFromWith with the advice-with builder. See the section Replace from with another endpoint in the official Camel documentation for an example:
http://camel.apache.org/advicewith.html

NoClassDefFoundError: javax.naming.directory.InitialDirContext is a restricted class. Using CCS (GCM) in Google App Engine

Im trying to implement google's Cloud Connection Server with Google App Engine following this tutorial -
Implementing an XMPP-based App Server. I copied latest smack jars from http://www.igniterealtime.org/projects/smack/ (smack.jar and smackx.jar), put them in WEB-INF/lib and added them to the classpath (im using eclipse).
In the code sample in the first link i posted, the XMPPConnection is initiated in a 'main' method. Since this is not really suitable to GAE i created a ServletContextListener and added it to web.xml.
public class GCMContextListener implements ServletContextListener {
private static final String GCM_SENDER_ID = "*GCM_SENDER_ID*";
private static final String API_KEY = "*API_KEY*";
private SmackCcsClient ccsClient;
public GCMContextListener() {
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
final String userName = GCM_SENDER_ID + "#gcm.googleapis.com";
final String password = API_KEY;
ccsClient = new SmackCcsClient();
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
try {
ccsClient.disconnect();
} catch (XMPPException e) {
e.printStackTrace();
}
}
}
web.xml
<web-app>
<listener>
<listener-class>com.myserver.bootstrap.GCMContextListener</listener-class>
</listener>
</web-app>
Now, when i start the GAE server i get the following exception :
java.lang.NoClassDefFoundError: javax.naming.directory.InitialDirContext is a restricted class. Please see the Google App Engine developer's guide for more details.
i searched the "Google App Engine developer's guide for more details" but couldnt find anything about this. can you please help me ?
Google App Engine restricts access to certain JRE classes. In fact they published a whitelist that shows you which classes are useable. It seems to me that the Smack library might require some reference to a directory context (maybe to create the XMPP messages?) and that is why your servlet causes this exception. The javax.naming.directory is not in the whitelist.
I'm currently working on setting up a GCM Server as well. It seems to me that you need to read through the example and see what that main method is doing. What I see is a connection to the GCM server:
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
Then a downstream message being sent to a device:
// Send a sample hello downstream message to a device.
String toRegId = "RegistrationIdOfTheTargetDevice";
String messageId = ccsClient.getRandomMessageId();
Map<String, String> payload = new HashMap<String, String>();
payload.put("Hello", "World");
payload.put("CCS", "Dummy Message");
payload.put("EmbeddedMessageId", messageId);
String collapseKey = "sample";
Long timeToLive = 10000L;
Boolean delayWhileIdle = true;
ccsClient.send(createJsonMessage(toRegId, messageId, payload, collapseKey,
timeToLive, delayWhileIdle));
}
These operations would be completed at some point during your application's lifecycle, so your servlet should support them by providing the methods the example is implementing, such as the connect method that appears in the first piece of code that I pasted here. It's implementation is in the example at line 235 if I'm not mistaken.
As the documentation says, the 3rd party application server, which is what you're trying to implement using GAE, should be:
Able to communicate with your client.
Able to fire off properly formatted requests to the GCM server.
Able to handle requests and resend them as needed, using exponential back-off.
Able to store the API key and client registration IDs. The API key is included in the header of POST requests that send messages.
Able to store the API key and client registration IDs.
Able to generate message IDs to uniquely identify each message it sends.

Camel CXF asynchronous request and reply

I would like to set up a Camel CXF endpont, and have the SOAP response asynchronous to much of my Camel Route. The route will have a lot of processing steps, and I do not want to have the response generated at the very end.
An example endpoint:
<cxf:cxfEndpoint id="someEndpoint"
address="/Service"
serviceClass="com.SomeImpl" />
An example route:
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("cxf:bean:someEndpoint")
to("bean:processingStep1")
to("bean:replyToSOAP") // I would like to respond to cxf:cxfEndpoint here!
to("bean:processingStep2")
to("bean:processingStep3")
to("bean:processingStep4");
// The response to cxf:cxfEndpoint actually happens here.
}
}
I have tried many options in MyRouteBuilder to "fork" the process (i.e. bean:replyToSOAP):
.multicast().parallelProcessing()
In-memory Asynchronous messaging ("seda" and "vm")
I have NOT tried JMS. It could be overkill for what I want to do.
I can get the route steps to process in parallel, but all steps must be completed before the response is generated.
In addition to the answer Claus gives below, I'd like to add that the placement of wireTap is important. Using:
.wireTap("bean:replyToSOAP")
will not get the desired behavior. What will is:
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("cxf:bean:someEndpoint")
to("bean:processingStep1")
.wireTap("direct:furtherProcessing")
to("bean:replyToSOAP") // respond to cxf:cxfEndpoint here
from("direct:furtherProcessing") // steps happen independantly of beann:replyToSOAP
to("bean:processingStep2")
to("bean:processingStep3")
to("bean:processingStep4");
}
}
There is the WireTap EIP which can spin of a copy of the message to be processed independently from the current route: http://camel.apache.org/wire-tap

GWT RPC method name at App Engine server log

our project runs on GWT and Java App Engine and we use the standard GWT RPC mechanism.
App engine adds log trace for each RPC call, but it just logs the servlet URL and not the called method.
We would like to add the method name to the log URL.
We have tried extending RpcRequestBuilder class, overriding doCreate and adding the method name to the URL, but the problem is that at this point the method name is unknown - it's known later at doSetRequestData (as part of the data string).
Thanks
Itzik
In each rpc implementation you can override one of readContent and processCall and add logging.
#Override
public String processCall(String payload) throws SerializationException {
// TODO Auto-generated method stub
String processCall = super.processCall(payload);
Logger.getLogger("").info(processCall);
return processCall;
}
#Override
protected String readContent(HttpServletRequest request)
throws ServletException, IOException {
// TODO Auto-generated method stub
String readContent = super.readContent(request);
Logger.getLogger("").info(readContent);
return readContent;
}
Log Line
6|0|4|http://127.0.0.1:8888/_4021625/|35C4974968FC8F8A9A7EA4881FD49F57|com.bitdual.client.LogMeService|logmemethod|1|2|3|4|0|

Resources